This commit is contained in:
Emanuel Rodriguez 2022-10-01 00:25:34 -07:00
parent 47caee3ddd
commit 8e18e3ddc1
24 changed files with 3225 additions and 5 deletions

View File

@ -148,7 +148,8 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<div class="cell">
<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(bayesrules)</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(tidyverse)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(tidyverse)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu">library</span>(patchwork)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<p>The chapter is set up with an example of polling results. We are put into the scenario where we are managig the campaing for a candidate. We know that on average her support based on recent polls is around 45%. In the next few sections well work through our Bayesian framework and incorporate a new tool the <strong>Beta-Binomial</strong> model. This model will take develop a continuous prior, as opposed to the discrete ones weve been working with so far.</p>
<section id="the-beta-prior" class="level2">
@ -229,7 +230,7 @@ The Standard Uniform
<div class="callout-body-container callout-body">
<p>When <span class="math inline">\pi</span> can take equally take on any value between 0 and 1, we can model <span class="math inline">\pi</span> using the standard uniform model.</p>
<p><span class="math display">\pi \sim Unif(0, 1)</span></p>
<p>the pdf of <span class="math inline">Unif(0, 1)</span> is <span class="math inline">\f(\pi) = 1</span></p>
<p>the pdf of <span class="math inline">Unif(0, 1)</span> is <span class="math inline">f(\pi) = 1</span></p>
<p>Note that <span class="math inline">Unif(0, 1)</span> is just a special case of the Beta with hyperparameters <span class="math inline">\alpha = \beta = 1</span>, see <a href="#fig-std-unif-as-beta">Figure&nbsp;2</a></p>
</div>
</div>
@ -282,6 +283,136 @@ The Standard Uniform
<p>it follows that</p>
<p><span class="math display">SD = \sqrt{Var(\pi)}</span></p>
</section>
<section id="tuning-the-beta-prior" class="level3">
<h3 class="anchored" data-anchor-id="tuning-the-beta-prior">Tuning the beta prior</h3>
<p>Now that we know we can use the beta model to represent <span class="math inline">\pi</span> for <span class="math inline">\pi \in [0, 1]</span>, what we need to try and do is tune the model so that it best represents our prior. Our options of course are chaning values of <span class="math inline">\alpha</span> and <span class="math inline">\beta</span>. We can make use of the fact that we know that on average the candidate is polling at around 45%. That is we know that</p>
<p><span class="math display">E(\pi) \approx .45 \approx \frac{\alpha}{\alpha + \beta}</span></p>
<p><em>so I tried to work through the algebra myself, but was unable to do so, the book gets to the following conclusion</em></p>
<p><span class="math display">\alpha = \frac{9}{11}\beta</span></p>
<div class="cell">
<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>p <span class="ot">&lt;-</span> <span class="fu">plot_beta</span>(<span class="dv">9</span>, <span class="dv">11</span>) <span class="sc">+</span> </span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">labs</span>(<span class="at">title=</span><span class="st">"Beta(9,11)"</span>) <span class="sc">+</span> </span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_x_continuous</span>(<span class="at">breaks=</span><span class="fu">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="at">by=</span>.<span class="dv">1</span>))</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>p2 <span class="ot">&lt;-</span> <span class="fu">plot_beta</span>(<span class="dv">27</span>, <span class="dv">33</span>) <span class="sc">+</span> </span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">labs</span>(<span class="at">title=</span><span class="st">"Beta(27,33)"</span>) <span class="sc">+</span> </span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_x_continuous</span>(<span class="at">breaks=</span><span class="fu">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="at">by=</span>.<span class="dv">1</span>))</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>p3 <span class="ot">&lt;-</span> <span class="fu">plot_beta</span>(<span class="dv">45</span>, <span class="dv">55</span>) <span class="sc">+</span> </span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">labs</span>(<span class="at">title=</span><span class="st">"Beta(45,55)"</span>) <span class="sc">+</span> </span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_x_continuous</span>(<span class="at">breaks=</span><span class="fu">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="at">by=</span>.<span class="dv">1</span>))</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>p <span class="sc">/</span> p2 <span class="sc">/</span> p3</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output-display">
<p><img src="ch3-beta-binomial_files/figure-html/unnamed-chunk-6-1.png" class="img-fluid" width="672"></p>
</div>
</div>
<p>when compared to the original polling values, we can see that the closest of these is <span class="math inline">Beta(45, 55)</span></p>
<p>we can get the pdf, and then mean, mode and variance of the pdf.</p>
<p><span class="math display">f(\pi) = \frac{\Gamma(100)}{\Gamma(45)\Gamma(55)}\pi^{44}(1-\pi)^{54}</span></p>
<p><span class="math display">E(\pi) = \frac{45}{45 + 55} = .4500</span> <span class="math display">\text{Mode}(\pi) = \frac{45 - 1}{45 + 55 - 2} = .449</span> <span class="math display"> SD(\pi) = .05</span></p>
<div class="cell" data-fig.caption="the prior distrubtions with Y = 30 hihglighted">
<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>rb1 <span class="ot">&lt;-</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="dv">50</span>, .<span class="dv">2</span>)</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>rb2 <span class="ot">&lt;-</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="dv">50</span>, .<span class="dv">3</span>)</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>rb3 <span class="ot">&lt;-</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="dv">50</span>, .<span class="dv">5</span>)</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>rb4 <span class="ot">&lt;-</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="dv">50</span>, .<span class="dv">6</span>)</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>rb5 <span class="ot">&lt;-</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="dv">50</span>, .<span class="dv">7</span>)</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>rb6 <span class="ot">&lt;-</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="dv">50</span>, .<span class="dv">8</span>)</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>results <span class="ot">&lt;-</span> <span class="fu">tibble</span>(</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .2)</span><span class="st">`</span> <span class="ot">=</span> rb1,</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .3)</span><span class="st">`</span> <span class="ot">=</span> rb2,</span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .5)</span><span class="st">`</span> <span class="ot">=</span> rb3,</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .6)</span><span class="st">`</span> <span class="ot">=</span> rb4,</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .7)</span><span class="st">`</span> <span class="ot">=</span> rb5,</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .8)</span><span class="st">`</span> <span class="ot">=</span> rb6,</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>) <span class="sc">|&gt;</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> <span class="fu">pivot_longer</span>(<span class="at">names_to =</span> <span class="st">"bin_model"</span>, <span class="at">values_to =</span> <span class="st">"value"</span>, </span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">Bin(50, .2)</span><span class="st">`</span><span class="sc">:</span><span class="st">`</span><span class="at">Bin(50, .8)</span><span class="st">`</span>) <span class="sc">|&gt;</span></span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="at">is_30 =</span> value <span class="sc">==</span> <span class="dv">30</span>)</span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>results <span class="sc">|&gt;</span></span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a> <span class="fu">ggplot</span>(<span class="fu">aes</span>(value, <span class="at">fill=</span>is_30)) <span class="sc">+</span> <span class="fu">geom_bar</span>(<span class="at">stat =</span> <span class="st">"count"</span>) <span class="sc">+</span></span>
<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_fill_manual</span>(<span class="at">values =</span> <span class="fu">c</span>(<span class="st">"grey30"</span>, <span class="st">"darkblue"</span>), <span class="at">guide=</span><span class="st">"none"</span>) <span class="sc">+</span> </span>
<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a> <span class="fu">facet_wrap</span>(<span class="fu">vars</span>(bin_model))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output-display">
<div id="fig-betas-for-poll" class="quarto-figure quarto-figure-center anchored">
<figure class="figure">
<p><img src="ch3-beta-binomial_files/figure-html/fig-betas-for-poll-1.png" class="img-fluid figure-img" width="672"></p>
<p></p><figcaption class="figure-caption">Figure&nbsp;4: <strong>?(caption)</strong></figcaption><p></p>
</figure>
</div>
</div>
</div>
<p>After the finish the poll, we see that the actual value of <span class="math inline">Y</span> is 30. The vertical line in <a href="#fig-betas-for-poll">Figure&nbsp;4</a></p>
<div class="cell">
<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>results <span class="ot">&lt;-</span> <span class="fu">tibble</span>(</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="at">ys =</span> <span class="dv">1</span><span class="sc">:</span><span class="dv">50</span>, </span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .1)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">1</span>),</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .2)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">2</span>),</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .3)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">3</span>),</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .4)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">4</span>),</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .5)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">5</span>),</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .6)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">6</span>),</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .7)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">7</span>),</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .8)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">8</span>),</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a> <span class="st">`</span><span class="at">beta(50, .9)</span><span class="st">`</span> <span class="ot">=</span> <span class="fu">dbinom</span>(<span class="at">x =</span> ys, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> .<span class="dv">9</span>),</span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>) <span class="sc">|&gt;</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a> <span class="fu">pivot_longer</span>(<span class="at">names_to =</span> <span class="st">"beta_model"</span>, <span class="at">values_to=</span><span class="st">"value"</span>, <span class="sc">-</span>ys) <span class="sc">|&gt;</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">mutate</span>(</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a> <span class="at">is_30 =</span> ys <span class="sc">==</span> <span class="dv">30</span>, </span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a> <span class="at">pie =</span> <span class="fu">rep</span>(<span class="fu">c</span>(.<span class="dv">1</span>, .<span class="dv">2</span>, .<span class="dv">3</span>, .<span class="dv">4</span>, .<span class="dv">5</span>, .<span class="dv">6</span>, .<span class="dv">7</span>, .<span class="dv">8</span>, .<span class="dv">9</span>), <span class="dv">50</span>))</span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a>results <span class="sc">|&gt;</span> <span class="fu">ggplot</span>(<span class="fu">aes</span>(ys, value, <span class="at">fill =</span> is_30)) <span class="sc">+</span> </span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a> <span class="fu">geom_col</span>() <span class="sc">+</span> </span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_fill_manual</span>(<span class="at">values =</span> <span class="fu">c</span>(<span class="st">"darkgray"</span>, <span class="st">"darkblue"</span>), <span class="at">guide=</span><span class="st">"none"</span>) <span class="sc">+</span> </span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a> <span class="fu">facet_wrap</span>(<span class="fu">vars</span>(beta_model))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output-display">
<p><img src="ch3-beta-binomial_files/figure-html/unnamed-chunk-8-1.png" class="img-fluid" width="672"></p>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>results <span class="sc">|&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">filter</span>(is_30) <span class="sc">|&gt;</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">ggplot</span>(<span class="fu">aes</span>(pie, value)) <span class="sc">+</span> <span class="fu">geom_col</span>() <span class="sc">+</span> </span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_x_continuous</span>(<span class="at">breaks =</span> <span class="fu">seq</span>(.<span class="dv">1</span>, .<span class="dv">9</span>, <span class="at">by =</span> .<span class="dv">1</span>))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output-display">
<p><img src="ch3-beta-binomial_files/figure-html/unnamed-chunk-9-1.png" class="img-fluid" width="672"></p>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="fu">summarize_beta_binomial</span>(<span class="at">alpha=</span><span class="dv">45</span>, <span class="at">beta=</span><span class="dv">55</span>, <span class="at">n=</span><span class="dv">50</span>, <span class="at">y=</span><span class="dv">30</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output cell-output-stdout">
<pre><code> model alpha beta mean mode var sd
1 prior 45 55 0.45 0.4489796 0.002450495 0.04950248
2 posterior 75 75 0.50 0.5000000 0.001655629 0.04068942</code></pre>
</div>
</div>
</section>
</section>
<section id="simulation" class="level2">
<h2 class="anchored" data-anchor-id="simulation">Simulation</h2>
<p>In this simulation we first generate 10,000 random values from a beta distribution with parameter <span class="math inline">\alpha = 45, \beta = 55</span>. Recall, that this is what we believe to be support based on recent polls for the candidate, and therefore our prior. We use each one of these are the <code>prob</code> value (the <span class="math inline">\pi</span> value) into 10,000 more random this time from the binomial distribution with <span class="math inline">n = 50</span>. This binomial distribution is the model for <span class="math inline">Y</span> conditioned on <span class="math inline">\pi</span>.</p>
<div class="cell">
<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>sim <span class="ot">&lt;-</span> <span class="fu">tibble</span>(</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="at">pi =</span> <span class="fu">rbeta</span>(<span class="dv">10000</span>, <span class="dv">45</span>, <span class="dv">55</span>)</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>) <span class="sc">|&gt;</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">mutate</span>(<span class="at">y =</span> <span class="fu">rbinom</span>(<span class="dv">10000</span>, <span class="at">size =</span> <span class="dv">50</span>, <span class="at">prob =</span> pi))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</div>
<div class="cell">
<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>sim <span class="sc">|&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">ggplot</span>(<span class="fu">aes</span>(pi, y)) <span class="sc">+</span> <span class="fu">geom_point</span>(<span class="fu">aes</span>(<span class="at">color =</span> (y <span class="sc">==</span> <span class="dv">30</span>))) <span class="sc">+</span> </span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">scale_color_manual</span>(<span class="at">values =</span> <span class="fu">c</span>(<span class="st">"darkgrey"</span>, <span class="st">"navyblue"</span>))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output-display">
<p><img src="ch3-beta-binomial_files/figure-html/unnamed-chunk-12-1.png" class="img-fluid" width="672"></p>
</div>
</div>
<div class="cell">
<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>sim <span class="sc">|&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">filter</span>(y <span class="sc">==</span> <span class="dv">30</span>) <span class="sc">|&gt;</span> <span class="co"># the posterior</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">ggplot</span>(<span class="fu">aes</span>(pi)) <span class="sc">+</span> <span class="fu">geom_density</span>()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<div class="cell-output-display">
<p><img src="ch3-beta-binomial_files/figure-html/unnamed-chunk-13-1.png" class="img-fluid" width="672"></p>
</div>
</div>
</section>
</main>

View File

@ -18,6 +18,7 @@ format:
```{r}
library(bayesrules)
library(tidyverse)
library(patchwork)
```
The chapter is set up with an example of polling results. We are put into
@ -93,7 +94,7 @@ we can model $\pi$ using the standard uniform model.
$$\pi \sim Unif(0, 1)$$
the pdf of $Unif(0, 1)$ is $\f(\pi) = 1$
the pdf of $Unif(0, 1)$ is $f(\pi) = 1$
Note that $Unif(0, 1)$ is just a special case of the Beta with
hyperparameters $\alpha = \beta = 1$, see @fig-std-unif-as-beta
@ -151,3 +152,151 @@ it follows that
$$SD = \sqrt{Var(\pi)}$$
### Tuning the beta prior
Now that we know we can use the beta model to represent
$\pi$ for $\pi \in [0, 1]$, what we need to try and do is
tune the model so that it best represents our prior. Our
options of course are chaning values of $\alpha$ and $\beta$.
We can make use of the fact that we know that on average
the candidate is polling at around 45%. That is we know
that
$$E(\pi) \approx .45 \approx \frac{\alpha}{\alpha + \beta}$$
*so I tried to work through the algebra myself, but was
unable to do so, the book gets to the following conclusion*
$$\alpha = \frac{9}{11}\beta$$
```{r}
p <- plot_beta(9, 11) +
labs(title="Beta(9,11)") +
scale_x_continuous(breaks=seq(0, 1, by=.1))
p2 <- plot_beta(27, 33) +
labs(title="Beta(27,33)") +
scale_x_continuous(breaks=seq(0, 1, by=.1))
p3 <- plot_beta(45, 55) +
labs(title="Beta(45,55)") +
scale_x_continuous(breaks=seq(0, 1, by=.1))
p / p2 / p3
```
when compared to the original polling values, we can see that the closest
of these is $Beta(45, 55)$
we can get the pdf, and then mean, mode and variance of the pdf.
$$f(\pi) = \frac{\Gamma(100)}{\Gamma(45)\Gamma(55)}\pi^{44}(1-\pi)^{54}$$
$$E(\pi) = \frac{45}{45 + 55} = .4500$$
$$\text{Mode}(\pi) = \frac{45 - 1}{45 + 55 - 2} = .449$$
$$ SD(\pi) = .05$$
```{r}
#| label: fig-betas-for-poll
#| fig-caption: "the prior distrubtions with Y = 30 hihglighted"
rb1 <- rbinom(10000, 50, .2)
rb2 <- rbinom(10000, 50, .3)
rb3 <- rbinom(10000, 50, .5)
rb4 <- rbinom(10000, 50, .6)
rb5 <- rbinom(10000, 50, .7)
rb6 <- rbinom(10000, 50, .8)
results <- tibble(
`Bin(50, .2)` = rb1,
`Bin(50, .3)` = rb2,
`Bin(50, .5)` = rb3,
`Bin(50, .6)` = rb4,
`Bin(50, .7)` = rb5,
`Bin(50, .8)` = rb6,
) |>
pivot_longer(names_to = "bin_model", values_to = "value",
`Bin(50, .2)`:`Bin(50, .8)`) |>
mutate(is_30 = value == 30)
results |>
ggplot(aes(value, fill=is_30)) + geom_bar(stat = "count") +
scale_fill_manual(values = c("grey30", "darkblue"), guide="none") +
facet_wrap(vars(bin_model))
```
After the finish the poll, we see that the actual value of
$Y$ is 30. The vertical line in @fig-betas-for-poll
```{r}
results <- tibble(
ys = 1:50,
`beta(50, .1)` = dbinom(x = ys, size = 50, prob = .1),
`beta(50, .2)` = dbinom(x = ys, size = 50, prob = .2),
`beta(50, .3)` = dbinom(x = ys, size = 50, prob = .3),
`beta(50, .4)` = dbinom(x = ys, size = 50, prob = .4),
`beta(50, .5)` = dbinom(x = ys, size = 50, prob = .5),
`beta(50, .6)` = dbinom(x = ys, size = 50, prob = .6),
`beta(50, .7)` = dbinom(x = ys, size = 50, prob = .7),
`beta(50, .8)` = dbinom(x = ys, size = 50, prob = .8),
`beta(50, .9)` = dbinom(x = ys, size = 50, prob = .9),
) |>
pivot_longer(names_to = "beta_model", values_to="value", -ys) |>
mutate(
is_30 = ys == 30,
pie = rep(c(.1, .2, .3, .4, .5, .6, .7, .8, .9), 50))
results |> ggplot(aes(ys, value, fill = is_30)) +
geom_col() +
scale_fill_manual(values = c("darkgray", "darkblue"), guide="none") +
facet_wrap(vars(beta_model))
```
```{r}
results |>
filter(is_30) |>
ggplot(aes(pie, value)) + geom_col() +
scale_x_continuous(breaks = seq(.1, .9, by = .1))
```
```{r}
summarize_beta_binomial(alpha=45, beta=55, n=50, y=30)
```
## Simulation
In this simulation we first generate 10,000 random values from
a beta distribution with parameter $\alpha = 45, \beta = 55$. Recall,
that this is what we believe to be support based on recent polls for the
candidate, and therefore our prior. We
use each one of these as the `prob` value (the $\pi$ value) into
10,000 more random samples from `rbinom` with
$n = 50$. This binomial distribution is how we model the likelihood. Our
simualtion will
```{r}
sim <- tibble(
pi = rbeta(10000, 45, 55)
) |>
mutate(y = rbinom(10000, size = 50, prob = pi))
```
```{r}
sim |>
ggplot(aes(pi, y)) + geom_point(aes(color = (y == 30))) +
scale_color_manual(values = c("darkgrey", "navyblue"))
```
```{r}
sim |>
filter(y == 30) |> # the posterior
ggplot(aes(pi)) + geom_density()
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,6 +1,5 @@
@import url('https://fonts.googleapis.com/css?family=Lora&display=swap');
@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
body {
font-family: 'Lora';
font-family: 'Lora'
}

203
R/misc/beta-binomial.html Normal file
View File

@ -0,0 +1,203 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.1.251">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta name="author" content="Emanuel Rodriguez">
<title>Beta-Binomial Bayesian Model Example</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
</style>
<script src="beta-binomial_files/libs/clipboard/clipboard.min.js"></script>
<script src="beta-binomial_files/libs/quarto-html/quarto.js"></script>
<script src="beta-binomial_files/libs/quarto-html/popper.min.js"></script>
<script src="beta-binomial_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="beta-binomial_files/libs/quarto-html/anchor.min.js"></script>
<link href="beta-binomial_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="beta-binomial_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="beta-binomial_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="beta-binomial_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="beta-binomial_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
<script>window.backupDefine = window.define; window.define = undefined;</script><script src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js"></script>
<script>document.addEventListener("DOMContentLoaded", function () {
var mathElements = document.getElementsByClassName("math");
var macros = [];
for (var i = 0; i < mathElements.length; i++) {
var texText = mathElements[i].firstChild;
if (mathElements[i].tagName == "SPAN") {
katex.render(texText.data, mathElements[i], {
displayMode: mathElements[i].classList.contains('display'),
throwOnError: false,
macros: macros,
fleqn: false
});
}}});
</script>
<script>window.define = window.backupDefine; window.backupDefine = undefined;</script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css">
<link rel="stylesheet" href="styles.css">
</head>
<body class="fullcontent">
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<main class="content" id="quarto-document-content">
<header id="title-block-header" class="quarto-title-block default">
<div class="quarto-title">
<h1 class="title">Beta-Binomial Bayesian Model Example</h1>
</div>
<div class="quarto-title-meta">
<div>
<div class="quarto-title-meta-heading">Author</div>
<div class="quarto-title-meta-contents">
<p>Emanuel Rodriguez </p>
</div>
</div>
</div>
</header>
<section id="introduction" class="level2">
<h2 class="anchored" data-anchor-id="introduction">Introduction</h2>
<p>In this short article I will try to put together a set of notes to go over the Beta-Binomial Bayesian Model. The example used here is pretty trivial but so is this model so :shrug:</p>
</section>
<section id="when-to-use-the-beta-binomial" class="level2">
<h2 class="anchored" data-anchor-id="when-to-use-the-beta-binomial">When to use the Beta-Binomial?</h2>
<p>The situations it makes sense to use the Beta-Binomial Model (BBM) are cases where we have some conditional dependence between a random variable <span class="math inline">Y</span> and a continuous parameter <span class="math inline">\pi \in [0, 1]</span>. Where <span class="math inline">Y</span> is the number of successes in <span class="math inline">n</span> independent trials, each with a probability of success <span class="math inline">\pi</span>.</p>
<p>For the sake of these notes, let us start by setting up an example that will allow us to illustrate the implementation of this model. Suppose there is a slot machine manufacturer who recently was accused of embedding software into the hardware that would cause more losses than usual to players. To be allowed to continue selling machines to casinos, they must go through a series of inspections. The body governing the sale of these machines has tasked us to determine whether or not the software has been completely removed or if, instead, the company refined the bias to make it less noticeable.</p>
</section>
<section id="what-we-already-know" class="level2">
<h2 class="anchored" data-anchor-id="what-we-already-know">What we already know</h2>
</section>
</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const clipboard = new window.ClipboardJS('.code-copy-button', {
target: function(trigger) {
return trigger.previousElementSibling;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
setTimeout(function() {
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
function tippyHover(el, contentFn) {
const config = {
allowHTML: true,
content: contentFn,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start'
};
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
return note.innerHTML;
});
}
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const cites = ref.parentNode.getAttribute('data-cites').split(' ');
tippyHover(ref, function() {
var popup = window.document.createElement('div');
cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
});
</script>
</div> <!-- /content -->
</body></html>

44
R/misc/beta-binomial.qmd Normal file
View File

@ -0,0 +1,44 @@
---
title: "Beta-Binomial Bayesian Model Example"
author: "Emanuel Rodriguez"
execute:
message: false
warning: false
format:
html:
monofont: "Cascadia Mono"
highlight-style: gruvbox-dark
css: styles.css
callout-icon: false
callout-apperance: simple
toc: false
html-math-method: katex
---
## Introduction
In this short article I will try to put together a set of notes to
go over the Beta-Binomial Bayesian Model. The example used here is pretty
trivial but so is this model so :shrug:
## When to use the Beta-Binomial?
The situations it makes sense to use the Beta-Binomial Model (BBM) are
cases where we have some conditional dependence between a random
variable $Y$ and a continuous parameter $\pi \in [0, 1]$. Where $Y$ is the number of successes in $n$ independent trials, each with a probability of
success $\pi$.
For the sake of these notes, let us start by setting up an example that will
allow us to illustrate the implementation of this model. Suppose there
is a slot machine manufacturer who recently was accused of embedding software
into the hardware that would cause more losses than usual to players.
To be allowed to continue selling machines to casinos, they must go through a
series of inspections. The body governing the sale of these machines has tasked
us to determine whether or not the software has been completely removed or if,
instead, the company refined the bias to make it less noticeable.
## What we already know
The set of facts that we can put together to build a known distribution

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,182 @@
/* quarto syntax highlight colors */
:root {
--quarto-hl-kw-color: #ebdbb2;
--quarto-hl-fu-color: #689d6a;
--quarto-hl-va-color: #458588;
--quarto-hl-cf-color: #cc241d;
--quarto-hl-op-color: #ebdbb2;
--quarto-hl-bu-color: #d65d0e;
--quarto-hl-ex-color: #689d6a;
--quarto-hl-pp-color: #d65d0e;
--quarto-hl-at-color: #d79921;
--quarto-hl-ch-color: #b16286;
--quarto-hl-sc-color: #b16286;
--quarto-hl-st-color: #98971a;
--quarto-hl-vs-color: #98971a;
--quarto-hl-ss-color: #98971a;
--quarto-hl-im-color: #689d6a;
--quarto-hl-dt-color: #d79921;
--quarto-hl-dv-color: #f67400;
--quarto-hl-bn-color: #f67400;
--quarto-hl-fl-color: #f67400;
--quarto-hl-cn-color: #b16286;
--quarto-hl-co-color: #928374;
--quarto-hl-do-color: #98971a;
--quarto-hl-an-color: #98971a;
--quarto-hl-cv-color: #928374;
--quarto-hl-re-color: #928374;
--quarto-hl-in-color: #282828;
--quarto-hl-wa-color: #282828;
--quarto-hl-al-color: #282828;
--quarto-hl-er-color: #cc241d;
}
/* other quarto variables */
:root {
--quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
pre > code.sourceCode > span {
color: #ebdbb2;
}
code span {
color: #ebdbb2;
}
code.sourceCode > span {
color: #ebdbb2;
}
div.sourceCode,
div.sourceCode pre.sourceCode {
color: #ebdbb2;
}
code span.kw {
color: #ebdbb2;
font-weight: bold;
}
code span.fu {
color: #689d6a;
}
code span.va {
color: #458588;
}
code span.cf {
color: #cc241d;
font-weight: bold;
}
code span.op {
color: #ebdbb2;
}
code span.bu {
color: #d65d0e;
}
code span.ex {
color: #689d6a;
font-weight: bold;
}
code span.pp {
color: #d65d0e;
}
code span.at {
color: #d79921;
}
code span.ch {
color: #b16286;
}
code span.sc {
color: #b16286;
}
code span.st {
color: #98971a;
}
code span.vs {
color: #98971a;
}
code span.ss {
color: #98971a;
}
code span.im {
color: #689d6a;
}
code span.dt {
color: #d79921;
}
code span.dv {
color: #f67400;
}
code span.bn {
color: #f67400;
}
code span.fl {
color: #f67400;
}
code span.cn {
color: #b16286;
font-weight: bold;
}
code span.co {
color: #928374;
}
code span.do {
color: #98971a;
}
code span.an {
color: #98971a;
}
code span.cv {
color: #928374;
}
code span.re {
color: #928374;
}
code span.in {
color: #282828;
}
code span.wa {
color: #282828;
}
code span.al {
color: #282828;
font-weight: bold;
}
code span.er {
color: #cc241d;
text-decoration: underline;
}
.prevent-inlining {
content: "</";
}
/*# sourceMappingURL=debc5d5d77c3f9108843748ff7464032.css.map */

View File

@ -0,0 +1,760 @@
const sectionChanged = new CustomEvent("quarto-sectionChanged", {
detail: {},
bubbles: true,
cancelable: false,
composed: false,
});
window.document.addEventListener("DOMContentLoaded", function (_event) {
const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]');
const sidebarEl = window.document.getElementById("quarto-sidebar");
const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left");
const marginSidebarEl = window.document.getElementById(
"quarto-margin-sidebar"
);
// function to determine whether the element has a previous sibling that is active
const prevSiblingIsActiveLink = (el) => {
const sibling = el.previousElementSibling;
if (sibling && sibling.tagName === "A") {
return sibling.classList.contains("active");
} else {
return false;
}
};
// fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior)
function fireSlideEnter(e) {
const event = window.document.createEvent("Event");
event.initEvent("slideenter", true, true);
window.document.dispatchEvent(event);
}
const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]');
tabs.forEach((tab) => {
tab.addEventListener("shown.bs.tab", fireSlideEnter);
});
// Track scrolling and mark TOC links as active
// get table of contents and sidebar (bail if we don't have at least one)
const tocLinks = tocEl
? [...tocEl.querySelectorAll("a[data-scroll-target]")]
: [];
const makeActive = (link) => tocLinks[link].classList.add("active");
const removeActive = (link) => tocLinks[link].classList.remove("active");
const removeAllActive = () =>
[...Array(tocLinks.length).keys()].forEach((link) => removeActive(link));
// activate the anchor for a section associated with this TOC entry
tocLinks.forEach((link) => {
link.addEventListener("click", () => {
if (link.href.indexOf("#") !== -1) {
const anchor = link.href.split("#")[1];
const heading = window.document.querySelector(
`[data-anchor-id=${anchor}]`
);
if (heading) {
// Add the class
heading.classList.add("reveal-anchorjs-link");
// function to show the anchor
const handleMouseout = () => {
heading.classList.remove("reveal-anchorjs-link");
heading.removeEventListener("mouseout", handleMouseout);
};
// add a function to clear the anchor when the user mouses out of it
heading.addEventListener("mouseout", handleMouseout);
}
}
});
});
const sections = tocLinks.map((link) => {
const target = link.getAttribute("data-scroll-target");
if (target.startsWith("#")) {
return window.document.getElementById(decodeURI(`${target.slice(1)}`));
} else {
return window.document.querySelector(decodeURI(`${target}`));
}
});
const sectionMargin = 200;
let currentActive = 0;
// track whether we've initialized state the first time
let init = false;
const updateActiveLink = () => {
// The index from bottom to top (e.g. reversed list)
let sectionIndex = -1;
if (
window.innerHeight + window.pageYOffset >=
window.document.body.offsetHeight
) {
sectionIndex = 0;
} else {
sectionIndex = [...sections].reverse().findIndex((section) => {
if (section) {
return window.pageYOffset >= section.offsetTop - sectionMargin;
} else {
return false;
}
});
}
if (sectionIndex > -1) {
const current = sections.length - sectionIndex - 1;
if (current !== currentActive) {
removeAllActive();
currentActive = current;
makeActive(current);
if (init) {
window.dispatchEvent(sectionChanged);
}
init = true;
}
}
};
const inHiddenRegion = (top, bottom, hiddenRegions) => {
for (const region of hiddenRegions) {
if (top <= region.bottom && bottom >= region.top) {
return true;
}
}
return false;
};
const categorySelector = "header.quarto-title-block .quarto-category";
const activateCategories = (href) => {
// Find any categories
// Surround them with a link pointing back to:
// #category=Authoring
try {
const categoryEls = window.document.querySelectorAll(categorySelector);
for (const categoryEl of categoryEls) {
const categoryText = categoryEl.textContent;
if (categoryText) {
const link = `${href}#category=${encodeURIComponent(categoryText)}`;
const linkEl = window.document.createElement("a");
linkEl.setAttribute("href", link);
for (const child of categoryEl.childNodes) {
linkEl.append(child);
}
categoryEl.appendChild(linkEl);
}
}
} catch {
// Ignore errors
}
};
function hasTitleCategories() {
return window.document.querySelector(categorySelector) !== null;
}
function offsetRelativeUrl(url) {
const offset = getMeta("quarto:offset");
return offset ? offset + url : url;
}
function offsetAbsoluteUrl(url) {
const offset = getMeta("quarto:offset");
const baseUrl = new URL(offset, window.location);
const projRelativeUrl = url.replace(baseUrl, "");
if (projRelativeUrl.startsWith("/")) {
return projRelativeUrl;
} else {
return "/" + projRelativeUrl;
}
}
// read a meta tag value
function getMeta(metaName) {
const metas = window.document.getElementsByTagName("meta");
for (let i = 0; i < metas.length; i++) {
if (metas[i].getAttribute("name") === metaName) {
return metas[i].getAttribute("content");
}
}
return "";
}
async function findAndActivateCategories() {
const currentPagePath = offsetAbsoluteUrl(window.location.href);
const response = await fetch(offsetRelativeUrl("listings.json"));
if (response.status == 200) {
return response.json().then(function (listingPaths) {
const listingHrefs = [];
for (const listingPath of listingPaths) {
const pathWithoutLeadingSlash = listingPath.listing.substring(1);
for (const item of listingPath.items) {
if (
item === currentPagePath ||
item === currentPagePath + "index.html"
) {
// Resolve this path against the offset to be sure
// we already are using the correct path to the listing
// (this adjusts the listing urls to be rooted against
// whatever root the page is actually running against)
const relative = offsetRelativeUrl(pathWithoutLeadingSlash);
const baseUrl = window.location;
const resolvedPath = new URL(relative, baseUrl);
listingHrefs.push(resolvedPath.pathname);
break;
}
}
}
// Look up the tree for a nearby linting and use that if we find one
const nearestListing = findNearestParentListing(
offsetAbsoluteUrl(window.location.pathname),
listingHrefs
);
if (nearestListing) {
activateCategories(nearestListing);
} else {
// See if the referrer is a listing page for this item
const referredRelativePath = offsetAbsoluteUrl(document.referrer);
const referrerListing = listingHrefs.find((listingHref) => {
const isListingReferrer =
listingHref === referredRelativePath ||
listingHref === referredRelativePath + "index.html";
return isListingReferrer;
});
if (referrerListing) {
// Try to use the referrer if possible
activateCategories(referrerListing);
} else if (listingHrefs.length > 0) {
// Otherwise, just fall back to the first listing
activateCategories(listingHrefs[0]);
}
}
});
}
}
if (hasTitleCategories()) {
findAndActivateCategories();
}
const findNearestParentListing = (href, listingHrefs) => {
if (!href || !listingHrefs) {
return undefined;
}
// Look up the tree for a nearby linting and use that if we find one
const relativeParts = href.substring(1).split("/");
while (relativeParts.length > 0) {
const path = relativeParts.join("/");
for (const listingHref of listingHrefs) {
if (listingHref.startsWith(path)) {
return listingHref;
}
}
relativeParts.pop();
}
return undefined;
};
const manageSidebarVisiblity = (el, placeholderDescriptor) => {
let isVisible = true;
return (hiddenRegions) => {
if (el === null) {
return;
}
// Find the last element of the TOC
const lastChildEl = el.lastElementChild;
if (lastChildEl) {
// Find the top and bottom o the element that is being managed
const elTop = el.offsetTop;
const elBottom =
elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight;
// Converts the sidebar to a menu
const convertToMenu = () => {
for (const child of el.children) {
child.style.opacity = 0;
child.style.overflow = "hidden";
}
const toggleContainer = window.document.createElement("div");
toggleContainer.style.width = "100%";
toggleContainer.classList.add("zindex-over-content");
toggleContainer.classList.add("quarto-sidebar-toggle");
toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom
toggleContainer.id = placeholderDescriptor.id;
toggleContainer.style.position = "fixed";
const toggleIcon = window.document.createElement("i");
toggleIcon.classList.add("quarto-sidebar-toggle-icon");
toggleIcon.classList.add("bi");
toggleIcon.classList.add("bi-caret-down-fill");
const toggleTitle = window.document.createElement("div");
const titleEl = window.document.body.querySelector(
placeholderDescriptor.titleSelector
);
if (titleEl) {
toggleTitle.append(titleEl.innerText, toggleIcon);
}
toggleTitle.classList.add("zindex-over-content");
toggleTitle.classList.add("quarto-sidebar-toggle-title");
toggleContainer.append(toggleTitle);
const toggleContents = window.document.createElement("div");
toggleContents.classList = el.classList;
toggleContents.classList.add("zindex-over-content");
toggleContents.classList.add("quarto-sidebar-toggle-contents");
for (const child of el.children) {
if (child.id === "toc-title") {
continue;
}
const clone = child.cloneNode(true);
clone.style.opacity = 1;
clone.style.display = null;
toggleContents.append(clone);
}
toggleContents.style.height = "0px";
toggleContainer.append(toggleContents);
el.parentElement.prepend(toggleContainer);
// Process clicks
let tocShowing = false;
// Allow the caller to control whether this is dismissed
// when it is clicked (e.g. sidebar navigation supports
// opening and closing the nav tree, so don't dismiss on click)
const clickEl = placeholderDescriptor.dismissOnClick
? toggleContainer
: toggleTitle;
const closeToggle = () => {
if (tocShowing) {
toggleContainer.classList.remove("expanded");
toggleContents.style.height = "0px";
tocShowing = false;
}
};
const positionToggle = () => {
// position the element (top left of parent, same width as parent)
const elRect = el.getBoundingClientRect();
toggleContainer.style.left = `${elRect.left}px`;
toggleContainer.style.top = `${elRect.top}px`;
toggleContainer.style.width = `${elRect.width}px`;
};
// Get rid of any expanded toggle if the user scrolls
window.document.addEventListener(
"scroll",
throttle(() => {
closeToggle();
}, 50)
);
// Handle positioning of the toggle
window.addEventListener(
"resize",
throttle(() => {
positionToggle();
}, 50)
);
positionToggle();
// Process the click
clickEl.onclick = () => {
if (!tocShowing) {
toggleContainer.classList.add("expanded");
toggleContents.style.height = null;
tocShowing = true;
} else {
closeToggle();
}
};
};
// Converts a sidebar from a menu back to a sidebar
const convertToSidebar = () => {
for (const child of el.children) {
child.style.opacity = 1;
child.style.overflow = null;
}
const placeholderEl = window.document.getElementById(
placeholderDescriptor.id
);
if (placeholderEl) {
placeholderEl.remove();
}
el.classList.remove("rollup");
};
if (isReaderMode()) {
convertToMenu();
isVisible = false;
} else {
if (!isVisible) {
// If the element is current not visible reveal if there are
// no conflicts with overlay regions
if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) {
convertToSidebar();
isVisible = true;
}
} else {
// If the element is visible, hide it if it conflicts with overlay regions
// and insert a placeholder toggle (or if we're in reader mode)
if (inHiddenRegion(elTop, elBottom, hiddenRegions)) {
convertToMenu();
isVisible = false;
}
}
}
}
};
};
// Find any conflicting margin elements and add margins to the
// top to prevent overlap
const marginChildren = window.document.querySelectorAll(
".column-margin.column-container > * "
);
let lastBottom = 0;
for (const marginChild of marginChildren) {
const top = marginChild.getBoundingClientRect().top;
if (top < lastBottom) {
const margin = lastBottom - top;
marginChild.style.marginTop = `${margin}px`;
}
const styles = window.getComputedStyle(marginChild);
const marginTop = parseFloat(styles["marginTop"]);
lastBottom = top + marginChild.getBoundingClientRect().height + marginTop;
}
// Manage the visibility of the toc and the sidebar
const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, {
id: "quarto-toc-toggle",
titleSelector: "#toc-title",
dismissOnClick: true,
});
const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, {
id: "quarto-sidebarnav-toggle",
titleSelector: ".title",
dismissOnClick: false,
});
let tocLeftScrollVisibility;
if (leftTocEl) {
tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, {
id: "quarto-lefttoc-toggle",
titleSelector: "#toc-title",
dismissOnClick: true,
});
}
// Find the first element that uses formatting in special columns
const conflictingEls = window.document.body.querySelectorAll(
'[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]'
);
// Filter all the possibly conflicting elements into ones
// the do conflict on the left or ride side
const arrConflictingEls = Array.from(conflictingEls);
const leftSideConflictEls = arrConflictingEls.filter((el) => {
if (el.tagName === "ASIDE") {
return false;
}
return Array.from(el.classList).find((className) => {
return (
className !== "column-body" &&
className.startsWith("column-") &&
!className.endsWith("right") &&
!className.endsWith("container") &&
className !== "column-margin"
);
});
});
const rightSideConflictEls = arrConflictingEls.filter((el) => {
if (el.tagName === "ASIDE") {
return true;
}
const hasMarginCaption = Array.from(el.classList).find((className) => {
return className == "margin-caption";
});
if (hasMarginCaption) {
return true;
}
return Array.from(el.classList).find((className) => {
return (
className !== "column-body" &&
!className.endsWith("container") &&
className.startsWith("column-") &&
!className.endsWith("left")
);
});
});
const kOverlapPaddingSize = 10;
function toRegions(els) {
return els.map((el) => {
const top =
el.getBoundingClientRect().top +
document.documentElement.scrollTop -
kOverlapPaddingSize;
return {
top,
bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize,
};
});
}
const hideOverlappedSidebars = () => {
marginScrollVisibility(toRegions(rightSideConflictEls));
sidebarScrollVisiblity(toRegions(leftSideConflictEls));
if (tocLeftScrollVisibility) {
tocLeftScrollVisibility(toRegions(leftSideConflictEls));
}
};
window.quartoToggleReader = () => {
// Applies a slow class (or removes it)
// to update the transition speed
const slowTransition = (slow) => {
const manageTransition = (id, slow) => {
const el = document.getElementById(id);
if (el) {
if (slow) {
el.classList.add("slow");
} else {
el.classList.remove("slow");
}
}
};
manageTransition("TOC", slow);
manageTransition("quarto-sidebar", slow);
};
const readerMode = !isReaderMode();
setReaderModeValue(readerMode);
// If we're entering reader mode, slow the transition
if (readerMode) {
slowTransition(readerMode);
}
highlightReaderToggle(readerMode);
hideOverlappedSidebars();
// If we're exiting reader mode, restore the non-slow transition
if (!readerMode) {
slowTransition(!readerMode);
}
};
const highlightReaderToggle = (readerMode) => {
const els = document.querySelectorAll(".quarto-reader-toggle");
if (els) {
els.forEach((el) => {
if (readerMode) {
el.classList.add("reader");
} else {
el.classList.remove("reader");
}
});
}
};
const setReaderModeValue = (val) => {
if (window.location.protocol !== "file:") {
window.localStorage.setItem("quarto-reader-mode", val);
} else {
localReaderMode = val;
}
};
const isReaderMode = () => {
if (window.location.protocol !== "file:") {
return window.localStorage.getItem("quarto-reader-mode") === "true";
} else {
return localReaderMode;
}
};
let localReaderMode = null;
// Walk the TOC and collapse/expand nodes
// Nodes are expanded if:
// - they are top level
// - they have children that are 'active' links
// - they are directly below an link that is 'active'
const walk = (el, depth) => {
// Tick depth when we enter a UL
if (el.tagName === "UL") {
depth = depth + 1;
}
// It this is active link
let isActiveNode = false;
if (el.tagName === "A" && el.classList.contains("active")) {
isActiveNode = true;
}
// See if there is an active child to this element
let hasActiveChild = false;
for (child of el.children) {
hasActiveChild = walk(child, depth) || hasActiveChild;
}
// Process the collapse state if this is an UL
if (el.tagName === "UL") {
if (depth === 1 || hasActiveChild || prevSiblingIsActiveLink(el)) {
el.classList.remove("collapse");
} else {
el.classList.add("collapse");
}
// untick depth when we leave a UL
depth = depth - 1;
}
return hasActiveChild || isActiveNode;
};
// walk the TOC and expand / collapse any items that should be shown
if (tocEl) {
walk(tocEl, 0);
updateActiveLink();
}
// Throttle the scroll event and walk peridiocally
window.document.addEventListener(
"scroll",
throttle(() => {
if (tocEl) {
updateActiveLink();
walk(tocEl, 0);
}
if (!isReaderMode()) {
hideOverlappedSidebars();
}
}, 5)
);
window.addEventListener(
"resize",
throttle(() => {
if (!isReaderMode()) {
hideOverlappedSidebars();
}
}, 10)
);
hideOverlappedSidebars();
highlightReaderToggle(isReaderMode());
});
// grouped tabsets
window.addEventListener("pageshow", (_event) => {
function getTabSettings() {
const data = localStorage.getItem("quarto-persistent-tabsets-data");
if (!data) {
localStorage.setItem("quarto-persistent-tabsets-data", "{}");
return {};
}
if (data) {
return JSON.parse(data);
}
}
function setTabSettings(data) {
localStorage.setItem(
"quarto-persistent-tabsets-data",
JSON.stringify(data)
);
}
function setTabState(groupName, groupValue) {
const data = getTabSettings();
data[groupName] = groupValue;
setTabSettings(data);
}
function toggleTab(tab, active) {
const tabPanelId = tab.getAttribute("aria-controls");
const tabPanel = document.getElementById(tabPanelId);
if (active) {
tab.classList.add("active");
tabPanel.classList.add("active");
} else {
tab.classList.remove("active");
tabPanel.classList.remove("active");
}
}
function toggleAll(selectedGroup, selectorsToSync) {
for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) {
const active = selectedGroup === thisGroup;
for (const tab of tabs) {
toggleTab(tab, active);
}
}
}
function findSelectorsToSyncByLanguage() {
const result = {};
const tabs = Array.from(
document.querySelectorAll(`div[data-group] a[id^='tabset-']`)
);
for (const item of tabs) {
const div = item.parentElement.parentElement.parentElement;
const group = div.getAttribute("data-group");
if (!result[group]) {
result[group] = {};
}
const selectorsToSync = result[group];
const value = item.innerHTML;
if (!selectorsToSync[value]) {
selectorsToSync[value] = [];
}
selectorsToSync[value].push(item);
}
return result;
}
function setupSelectorSync() {
const selectorsToSync = findSelectorsToSyncByLanguage();
Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => {
Object.entries(tabSetsByValue).forEach(([value, items]) => {
items.forEach((item) => {
item.addEventListener("click", (_event) => {
setTabState(group, value);
toggleAll(value, selectorsToSync[group]);
});
});
});
});
return selectorsToSync;
}
const selectorsToSync = setupSelectorSync();
for (const [group, selectedName] of Object.entries(getTabSettings())) {
const selectors = selectorsToSync[group];
// it's possible that stale state gives us empty selections, so we explicitly check here.
if (selectors) {
toggleAll(selectedName, selectors);
}
}
});
function throttle(func, wait) {
let waiting = false;
return function () {
if (!waiting) {
func.apply(this, arguments);
waiting = true;
setTimeout(function () {
waiting = false;
}, wait);
}
};
}

View File

@ -0,0 +1 @@
.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}

File diff suppressed because one or more lines are too long

6
R/misc/styles.css Normal file
View File

@ -0,0 +1,6 @@
@import url('https://fonts.googleapis.com/css?family=Lora&display=swap');
@import url('https://fonts.googleapis.com/css?family=Source+Code+Pro&display=swap');
body {
font-family: 'Lora';
}