<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Brian Callander</title>
    <link href="http://www.briancallander.com/atom.xml" rel="self" />
    <link href="http://www.briancallander.com" />
    <id>http://www.briancallander.com/atom.xml</id>
    <author>
        <name>Brian Callander</name>
        <email>briancallander+blog@gmail.com</email>
    </author>
    <updated>2020-04-05T00:00:00Z</updated>
    <entry>
    <title>SR2 Chapter 3 Medium</title>
    <link href="http://www.briancallander.com/posts/statistical-rethinking-2/exercise_3M.html" />
    <id>http://www.briancallander.com/posts/statistical-rethinking-2/exercise_3M.html</id>
    <published>2020-04-05T00:00:00Z</published>
    <updated>2020-04-05T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">SR2 Chapter 3 Medium</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on  5 April, 2020  by Brian </br>
     Tags: <a href="/tags/statistical%20rethinking.html">statistical rethinking</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/grid%20approximation.html">grid approximation</a>, <a href="/tags/posterior%0Aprobability.html">posterior
probability</a>, <a href="/tags/posterior%20predictive%20probability.html">posterior predictive probability</a>, <a href="/tags/hpdi.html">hpdi</a>, <a href="/tags/binomial.html">binomial</a> </br>
     Category: <a href="/categories/statistical-rethinking-2.html">statistical-rethinking-2</a> 
    </p>
  </div>
</div>

<p>Here’s my solution to the medium exercises in chapter 3 of McElreath’s Statistical Rethinking, 2nd edition.</p>
<!--more-->
<div>
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbernoulli}{Bernoulli} \DeclareMathOperator{\dpoisson}{Poisson} \DeclareMathOperator{\dnormal}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexponential}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvpamma}{Invpamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<p>Assuming Earth has 70% water cover, and we observe water 8 times out of 15 globe tosses, let’s calculate some posterior quantities with two choices of prior: uniform and step.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">p_true &lt;-<span class="st"> </span><span class="fl">0.7</span>

W &lt;-<span class="st"> </span><span class="dv">8</span>
N &lt;-<span class="st"> </span><span class="dv">15</span>

granularity &lt;-<span class="st"> </span><span class="dv">1000</span> <span class="co"># points on the grid</span></code></pre></div>
<h2 id="uniform-prior">Uniform Prior</h2>
<p>We calculate the grid approximation of the posterior as shown in the book.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m1_grid &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">p =</span> <span class="kw">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="dt">length.out =</span> granularity)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">prior =</span> <span class="dv">1</span>)

m1_posterior &lt;-<span class="st"> </span>m1_grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">likelihood =</span> <span class="kw">dbinom</span>(W, N, p),
    <span class="dt">posterior =</span> prior <span class="op">*</span><span class="st"> </span>likelihood
  )</code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m1_plot-1.svg" alt="Solution to exercise 3M1" /><figcaption>Solution to exercise 3M1</figcaption>
</figure>
<p>We can get draws from our posterior by sampling the water cover values many times with replacement, each value being drawn in proportion to the posterior probability. We can then just summarise these draws to get the desired interval.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m2_samples &lt;-<span class="st"> </span>m1_posterior <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sample_n</span>(<span class="dv">10000</span>, <span class="dt">replace =</span> T, <span class="dt">weight =</span> posterior)

m2_hpdi &lt;-<span class="st"> </span><span class="kw">HPDI</span>(m2_samples<span class="op">$</span>p, <span class="dt">prob =</span> <span class="fl">0.9</span>)
m2_hpdi</code></pre></div>
<pre><code>     |0.9      0.9| 
0.3223223 0.7097097 </code></pre>
<p>The histogram looks as follows. This is much the same as the previous graph, but calculated from the samples.</p>
<figure>
<img src="exercise_3M_files/figure-markdown/m2_plot-1.svg" alt="Solution to exercise 3M2" /><figcaption>Solution to exercise 3M2</figcaption>
</figure>
<p>To get the posterior predictive sample, we take our posterior draws of <span class="math inline">\(p\)</span>, then use them to draw a random number of observed water tosses out of 15. The fraction of posterior predictive samples with a given value is then the posterior predictive probability of that value.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m3_prob &lt;-<span class="st"> </span>m2_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">W =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">15</span>, p)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(W) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">probability =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m3_plot-1.svg" alt="Solution to exercise 3M3" /><figcaption>Solution to exercise 3M3</figcaption>
</figure>
<p>We can also calculate the posterior predictive probabilities with a different number of tosses. Here with 9 tosses.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m4_prob &lt;-<span class="st"> </span>m2_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">W =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">9</span>, p)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(W) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">probability =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m4_plot-1.svg" alt="Solution to exercise 3M4" /><figcaption>Solution to exercise 3M4</figcaption>
</figure>
<h2 id="step-prior">Step Prior</h2>
<p>Now we repeat the same steps but with the step prior instead of the uniform prior. We’ll just repeat it without comment.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m5_grid &lt;-<span class="st"> </span>m1_grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">prior =</span> <span class="kw">if_else</span>(p <span class="op">&lt;</span><span class="st"> </span><span class="fl">0.5</span>, <span class="dv">0</span>, <span class="dv">1</span>))

m5_posterior &lt;-<span class="st"> </span>m5_grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">likelihood =</span> <span class="kw">dbinom</span>(W, N, p),
    <span class="dt">posterior =</span> prior <span class="op">*</span><span class="st"> </span>likelihood
  )</code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m5_1_plot-1.svg" alt="Solution to exercise 3M5 part 1" /><figcaption>Solution to exercise 3M5 part 1</figcaption>
</figure>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m5_samples &lt;-<span class="st"> </span>m5_posterior <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sample_n</span>(<span class="dv">10000</span>, <span class="dt">replace =</span> T, <span class="dt">weight =</span> posterior)

m5_hpdi &lt;-<span class="st"> </span><span class="kw">HPDI</span>(m5_samples<span class="op">$</span>p, <span class="dt">prob =</span> <span class="fl">0.9</span>)
m5_hpdi</code></pre></div>
<pre><code>     |0.9      0.9| 
0.5005005 0.7107107 </code></pre>
<figure>
<img src="exercise_3M_files/figure-markdown/m5_2_plot-1.svg" alt="Solution to exercise 3M5 part 2" /><figcaption>Solution to exercise 3M5 part 2</figcaption>
</figure>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m5_prob &lt;-<span class="st"> </span>m5_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">W =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">15</span>, p)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(W) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">probability =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m5_3_plot-1.svg" alt="Solution to exercise 3M5 part 3" /><figcaption>Solution to exercise 3M5 part 3</figcaption>
</figure>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m5_prob &lt;-<span class="st"> </span>m5_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">W =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">9</span>, p)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(W) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">probability =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m5_4_plot-1.svg" alt="Solution to exercise 3M5 part 4" /><figcaption>Solution to exercise 3M5 part 4</figcaption>
</figure>
<p>Let’s compare the proportion of samples within 0.05 of the true value for each prior.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">p_close_uniform &lt;-<span class="st"> </span>m2_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(<span class="dt">close =</span> p <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">between</span>(p_true <span class="op">-</span><span class="st"> </span><span class="fl">0.05</span>, p_true <span class="op">+</span><span class="st"> </span><span class="fl">0.05</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">probability =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(close) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(probability)

p_close_step &lt;-<span class="st"> </span>m5_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(<span class="dt">close =</span> p <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">between</span>(p_true <span class="op">-</span><span class="st"> </span><span class="fl">0.05</span>, p_true <span class="op">+</span><span class="st"> </span><span class="fl">0.05</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">probability =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(close) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(probability)</code></pre></div>
<p>The probability of being close to the true value under the uniform and step priors is 0.1316 and 0.2157, respectively. The step prior thus has more mass around the true value.</p>
<h2 id="exercise-3m6">Exercise 3M6</h2>
<p>Bayesian models are generative, meaning we can simulate new datasets according to our prior probabilities. We’ll simulate 10 datasets for each value of N of interest. We simulate a dataset by randomly choosing a <code>p_true</code> from our uniform prior, then randomly choosing a <code>W</code> from the corresponding binomial distribution.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m6_prior_predictive &lt;-<span class="st"> </span><span class="kw">crossing</span>(
    <span class="dt">N =</span> <span class="dv">200</span> <span class="op">*</span><span class="st"> </span>(<span class="dv">1</span><span class="op">:</span><span class="dv">16</span>), 
    <span class="dt">iter =</span> <span class="dv">1</span><span class="op">:</span><span class="dv">10</span>
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">p_true =</span> <span class="kw">runif</span>(<span class="kw">n</span>(), <span class="dt">min=</span><span class="dv">0</span>, <span class="dt">max=</span><span class="dv">1</span>), 
    <span class="dt">W =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), N, p_true)
  )</code></pre></div>
<p>For each of these simulated datasets, we grid approximate the posterior, take posterior samples, then calculate the HPDI.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m6_grid &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">p =</span> <span class="kw">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="dt">length.out =</span> granularity)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">prior =</span> <span class="dv">1</span>)

m6_posteriors &lt;-<span class="st"> </span>m6_prior_predictive <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">crossing</span>(m6_grid) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(N, p_true, iter) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">likelihood =</span> <span class="kw">dbinom</span>(W, N, p),
    <span class="dt">posterior =</span> prior <span class="op">*</span><span class="st"> </span>likelihood
  )

m6_samples &lt;-<span class="st"> </span>m6_posteriors <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sample_n</span>(<span class="dv">1000</span>, <span class="dt">replace =</span> <span class="ot">TRUE</span>, <span class="dt">weight =</span> posterior) 

m6_hpdi &lt;-<span class="st"> </span>m6_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="dt">lo =</span> <span class="kw">HPDI</span>(p, <span class="fl">0.99</span>)[<span class="dv">1</span>], <span class="dt">hi =</span> <span class="kw">HPDI</span>(p, <span class="fl">0.99</span>)[<span class="dv">2</span>]) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">width =</span> <span class="kw">abs</span>(hi <span class="op">-</span><span class="st"> </span>lo))</code></pre></div>
<p>Now for each value of N, we check how many of the intervals have the desired width.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m6_n &lt;-<span class="st"> </span>m6_hpdi <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(N) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="dt">fraction =</span> <span class="kw">mean</span>(width <span class="op">&lt;</span><span class="st"> </span><span class="fl">0.05</span>)) </code></pre></div>
<figure>
<img src="exercise_3M_files/figure-markdown/m6_sample_size_plot-1.svg" alt="Solution to exercise 3M6" /><figcaption>Solution to exercise 3M6</figcaption>
</figure>
<p>Thus we expect a sample size around 2600-3000 to give us a sufficiently precise posterior estimation.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>SR2 Chapter 3 Hard</title>
    <link href="http://www.briancallander.com/posts/statistical-rethinking-2/exercise_3H.html" />
    <id>http://www.briancallander.com/posts/statistical-rethinking-2/exercise_3H.html</id>
    <published>2020-04-05T00:00:00Z</published>
    <updated>2020-04-05T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">SR2 Chapter 3 Hard</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on  5 April, 2020  by Brian </br>
     Tags: <a href="/tags/statistical%20rethinking.html">statistical rethinking</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/grid%20approximation.html">grid approximation</a>, <a href="/tags/posterior%0Apredictive%20check.html">posterior
predictive check</a>, <a href="/tags/posterior%20predictive%20distribution.html">posterior predictive distribution</a>, <a href="/tags/map.html">map</a>, <a href="/tags/binomial.html">binomial</a>, <a href="/tags/hpdi.html">hpdi</a> </br>
     Category: <a href="/categories/statistical-rethinking-2.html">statistical-rethinking-2</a> 
    </p>
  </div>
</div>

<p>Here’s my solutions to the hard exercises in chapter 3 of McElreath’s Statistical Rethinking, 2nd edition.</p>
<!--more-->
<div>
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbernoulli}{Bernoulli} \DeclareMathOperator{\dpoisson}{Poisson} \DeclareMathOperator{\dnormal}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexponential}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvpamma}{Invpamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<p>Let’s first put the data into a tibble for easier manipulation later.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">data</span>(homeworkch3)

df &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">birth1 =</span> birth1, <span class="dt">birth2 =</span> birth2) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">birth =</span> <span class="kw">row_number</span>())</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
The first few rows of the data.
</caption>
<thead>
<tr>
<th style="text-align:right;">
birth1
</th>
<th style="text-align:right;">
birth2
</th>
<th style="text-align:right;">
birth
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
2
</td>
</tr>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
3
</td>
</tr>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
4
</td>
</tr>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
5
</td>
</tr>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
6
</td>
</tr>
</tbody>
</table>
<h2 id="h1">3H1</h2>
<p>Let’s check we have the correct total cound and the correct number of boys.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h1_counts &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(order, gender, <span class="op">-</span>birth) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="dt">boys =</span> <span class="kw">sum</span>(gender), <span class="dt">births =</span> <span class="kw">n</span>())</code></pre></div>
<p>Now we can grid approximate the posterior as before.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">granularity &lt;-<span class="st"> </span><span class="dv">1000</span>

h1_grid &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">p =</span> <span class="kw">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="dt">length.out =</span> granularity)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">prior =</span> <span class="dv">1</span>)

h1_posterior &lt;-<span class="st"> </span>h1_grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">likelihood =</span> <span class="kw">dbinom</span>(h1_counts<span class="op">$</span>boys, h1_counts<span class="op">$</span>births, p),
    <span class="dt">posterior =</span> prior <span class="op">*</span><span class="st"> </span>likelihood,
    <span class="dt">posterior =</span> posterior <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(posterior)
  )</code></pre></div>
<p>The maximum a posteriori (MAP) value is the value of p that maximises the posterior.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h1_map &lt;-<span class="st"> </span>h1_posterior <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">slice</span>(<span class="kw">which.max</span>(posterior)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(p)

h1_map</code></pre></div>
<pre><code>[1] 0.5545546</code></pre>
<figure>
<img src="exercise_3H_files/figure-markdown/h1_posterior_plot-1.svg" alt="Solution 3H1: posterior probability of giving birth to a boy." /><figcaption>Solution 3H1: posterior probability of giving birth to a boy.</figcaption>
</figure>
<h2 id="h2">3H2</h2>
<p>We draw samples with weight equalt to the posterior. We then apply the <code>HPDI</code> function to these samples, each time with a different width.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h2_samples &lt;-<span class="st"> </span>h1_posterior <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sample_n</span>(<span class="dv">10000</span>, <span class="dt">replace =</span> <span class="ot">TRUE</span>, <span class="dt">weight =</span> posterior) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(p)

h2_hpdi &lt;-<span class="st"> </span>h2_samples <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">crossing</span>(<span class="dt">prob =</span> <span class="kw">c</span>(<span class="fl">0.5</span>, <span class="fl">0.89</span>, <span class="fl">0.97</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(prob) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_map</span>(HPDI) 

h2_hpdi</code></pre></div>
<pre><code>[[1]]
     |0.5      0.5| 
0.4574575 0.5735736 

[[2]]
    |0.89     0.89| 
0.4534535 0.6606607 

[[3]]
    |0.97     0.97| 
0.4294294 0.6616617 </code></pre>
<h2 id="h3">3H3</h2>
<p>The posterior predictive samples are possible observations according to our posterior.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h3_posterior_predictive &lt;-<span class="st"> </span><span class="kw">rbinom</span>(<span class="dv">10000</span>, <span class="dv">200</span>, h2_samples)</code></pre></div>
<figure>
<img src="exercise_3H_files/figure-markdown/h3_plot-1.svg" alt="Solution 3H3: the posterior predictive distribution for 200 births" /><figcaption>Solution 3H3: the posterior predictive distribution for 200 births</figcaption>
</figure>
<p>The number of observed births is very close to the MAP of the posterior predictive distribution, suggesting we have a decent fit.</p>
<h2 id="h4">3H4</h2>
<p>Our data are from birth pairs and so far we didn’t make any distinction between the first and second births. To test this assumption, we can perform a posterior predictive check as in 3H3, but this time for first births.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h4_posterior_predictive &lt;-<span class="st"> </span><span class="kw">rbinom</span>(<span class="dv">10000</span>, <span class="dv">100</span>, h2_samples)</code></pre></div>
<figure>
<img src="exercise_3H_files/figure-markdown/h4_posterior_predictive_plot-1.svg" alt="Solution 3H4: the posterior predictive distribution for 100 births" /><figcaption>Solution 3H4: the posterior predictive distribution for 100 births</figcaption>
</figure>
<p>The fit doesn’t look quite as good for first births as it did for all births together. It also doesn’t look bad since there is still a fair bit of probability mass around the observed number of first birth boys.</p>
<h2 id="h5">3H5</h2>
<p>As the final posterior predictive check, let’s check the number of boys born after a girl.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h5_counts &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(birth1 <span class="op">==</span><span class="st"> </span><span class="dv">0</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="dt">boys =</span> <span class="kw">sum</span>(birth2), <span class="dt">births =</span> <span class="kw">n</span>())

h5_posterior_predictive &lt;-<span class="st"> </span><span class="kw">rbinom</span>(<span class="dv">10000</span>, h5_counts<span class="op">$</span>births, h2_samples)</code></pre></div>
<figure>
<img src="exercise_3H_files/figure-markdown/h5_posterior_predictive-1.svg" alt="Solution 3H5: the posterior predictive distribution for 100 births" /><figcaption>Solution 3H5: the posterior predictive distribution for 100 births</figcaption>
</figure>
<p>The fit here looks bad, since the observed number of boys is higher than the bulk of the model’s expectations.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>SR2 Chapter 2 Hard</title>
    <link href="http://www.briancallander.com/posts/statistical-rethinking-2/exercise_2H.html" />
    <id>http://www.briancallander.com/posts/statistical-rethinking-2/exercise_2H.html</id>
    <published>2020-03-01T00:00:00Z</published>
    <updated>2020-03-01T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">SR2 Chapter 2 Hard</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on  1 March, 2020  by Brian </br>
     Tags: <a href="/tags/statistical%20rethinking.html">statistical rethinking</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/conditional%20probability.html">conditional probability</a>, <a href="/tags/counting.html">counting</a>, <a href="/tags/bayes%20rule.html">bayes rule</a>, <a href="/tags/pandas.html">pandas</a> </br>
     Category: <a href="/categories/statistical-rethinking-2.html">statistical-rethinking-2</a> 
    </p>
  </div>
</div>

<p>Here’s my solution to the hard exercises in chapter 2 of McElreath’s Statistical Rethinking, 1st edition. When writing this up, I came across a <a href="https://www.theguardian.com/world/2020/feb/28/red-pandas-are-actually-two-separate-species-study-finds">very relevant article</a>. We’ll solve these problems in two ways: using the counting method and using Bayes rule.</p>
<!--more-->
<div>
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbernoulli}{Bernoulli} \DeclareMathOperator{\dpoisson}{Poisson} \DeclareMathOperator{\dnormal}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexponential}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvpamma}{Invpamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<h2 id="counting-method">Counting method</h2>
<p>Let’s generate a dataset with all the features necessary to solve all the questions: twins at first birth, twins at second birth, and testing positive for species A.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">N &lt;-<span class="st"> </span><span class="dv">100000</span>

dfa &lt;-<span class="st"> </span><span class="kw">tibble</span>(
    <span class="dt">species =</span> <span class="st">&#39;A&#39;</span>,
    <span class="dt">t1 =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="fl">0.1</span>),
    <span class="dt">t2 =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="fl">0.1</span>),
    <span class="dt">pa =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="fl">0.8</span>)
  )

dfb &lt;-<span class="st"> </span><span class="kw">tibble</span>(
    <span class="dt">species =</span> <span class="st">&#39;B&#39;</span>,
    <span class="dt">t1 =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="fl">0.2</span>),
    <span class="dt">t2 =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="fl">0.2</span>),
    <span class="dt">pa =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="dv">1</span> <span class="op">-</span><span class="st"> </span><span class="fl">0.65</span>)
  )

df &lt;-<span class="st"> </span>dfa <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">bind_rows</span>(dfb)</code></pre></div>
<p>All of the problems can now be solved by simply filtering out any events not consisent with our observations, then summarising the remaining events.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">h1 &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(t1 <span class="op">==</span><span class="st"> </span><span class="dv">1</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(t2 <span class="op">==</span><span class="st"> </span><span class="dv">1</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>()

h2 &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(t1 <span class="op">==</span><span class="st"> </span><span class="dv">1</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(species <span class="op">==</span><span class="st"> &#39;A&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>()

h3 &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(t1 <span class="op">==</span><span class="st"> </span><span class="dv">1</span>, t2 <span class="op">==</span><span class="st"> </span><span class="dv">0</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(species <span class="op">==</span><span class="st"> &#39;A&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>()

h4a &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(pa <span class="op">==</span><span class="st"> </span><span class="dv">1</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(species <span class="op">==</span><span class="st"> &#39;A&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>()

h4b &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(pa <span class="op">==</span><span class="st"> </span><span class="dv">1</span>, t1 <span class="op">==</span><span class="st"> </span><span class="dv">1</span>, t2 <span class="op">==</span><span class="st"> </span><span class="dv">0</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(species <span class="op">==</span><span class="st"> &#39;A&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>()</code></pre></div>
<table class="table table-hover table-striped table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Solutions
</caption>
<thead>
<tr>
<th style="text-align:left;">
exercise
</th>
<th style="text-align:right;">
bayes
</th>
<th style="text-align:right;">
counting
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
h1
</td>
<td style="text-align:right;">
0.1666667
</td>
<td style="text-align:right;">
0.1669936
</td>
</tr>
<tr>
<td style="text-align:left;">
h2
</td>
<td style="text-align:right;">
0.3333333
</td>
<td style="text-align:right;">
0.3360484
</td>
</tr>
<tr>
<td style="text-align:left;">
h3
</td>
<td style="text-align:right;">
0.3529412
</td>
<td style="text-align:right;">
0.3635856
</td>
</tr>
<tr>
<td style="text-align:left;">
h4a
</td>
<td style="text-align:right;">
0.6956522
</td>
<td style="text-align:right;">
0.6963991
</td>
</tr>
<tr>
<td style="text-align:left;">
h4b
</td>
<td style="text-align:right;">
0.5443787
</td>
<td style="text-align:right;">
0.5656231
</td>
</tr>
</tbody>
</table>
<p>For H1 we expect the probability to be between 0.1 and 0.2, since those are the two possible birth rates. Also, since we observed a twin birth already, it makes sense that it is closer to 0.2 since species B is more likely to birth twins. In other words, in H2 we expect the species to be less likely to be species A. Birthing a singleton infant is fairly common, so we wouldn’t expect this observation to change our inference very much in H3.</p>
<h2 id="bayes-rule">Bayes rule</h2>
<p>Let’s also work out the solutions analytically using Bayes rule. Let’s start with H2 since it’s useful for calculating H1.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P(A \mid T_1)
  &amp;=
  \frac{\mathbb P(T_1 \mid A) \mathbb P(A)}{\mathbb P(T_1)}
  \\
  &amp;=
  \frac{\mathbb P(T_1 \mid A) \mathbb P(A)}{\mathbb P(T_1 \mid A) \mathbb P(A) + \mathbb P(T_1 \mid B) \mathbb P(B)}
  \\
  &amp;=
  \frac{0.1 \cdot 0.5}{0.1 \cdot 0.5 + 0.2 \cdot 0.5}
  \\
  &amp;=
  \frac{0.05}{0.05 + 0.1}
  \\
  &amp;=
  \frac{1}{3}
\end{align}
\]</span></p>
<p>Now we can use our solution to H2 and plug it into the appropriate place in the formula for H1. Note that <span class="math inline">\(\mathbb P(T_2 \mid A)\)</span> is the same as <span class="math inline">\(\mathbb P(T_1 \mid A)\)</span> by the assumptions of the problem. Similarily, once we know the species, whether the first birth was twins is irrelevant to the probability of twins in the second birth, i.e. <span class="math inline">\(\mathbb P(T_2 \mid T_1, A) = \mathbb P(T_2 \mid A)\)</span>.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P(T_2 \mid T_1)
  &amp;=
  \mathbb P(T_2 \mid T_1, A) \mathbb P(A \mid T_1)
  +
  \mathbb P(T_2 \mid T_1, B) \mathbb P(B \mid T_1)
  \\
  &amp;=
  \mathbb P(T_2 \mid A) \mathbb P(A \mid T_1)
  +
  \mathbb P(T_2 \mid B) \mathbb P(B \mid T_1)
  \\
  &amp;=
  \frac{1}{10} \cdot \frac{1}{3} + \frac{2}{10} \cdot \frac{2}{3}
  \\
  &amp;=
  \frac{5}{30}
  \\
  &amp;=
  \frac{1}{6}
\end{align}
\]</span></p>
<p>For H3, let’s use the notation <span class="math inline">\(-T_i\)</span> to mean singleton infants (i.e. not twins).</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P(A \mid T_1, - T_2)
  &amp;=
  \frac{\mathbb P(- T_2 \mid T_1, A) \mathbb P(A \mid T_1)}{\mathbb P(- T_2 \mid T_1)}
  \\
  &amp;=
  \frac{\mathbb P(- T_2 \mid A) \mathbb P(A \mid T_1)}{\mathbb P(- T_2 \mid T_1)}
  \\
  &amp;=
  \frac{(1 - 0.1) \cdot \frac{1}{3}}{1 - 0.15}
  \\
  &amp;=\frac{0.3}{0.85}
  \\
  &amp;=
  \frac{6}{17}
\end{align}
\]</span></p>
<p>This is about 0.353.</p>
<p>Now for H4a.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P(A \mid P_A)
  &amp;=
  \frac{\mathbb P(P_A \mid A) \mathbb P(A)}{\mathbb P(P_A)}
  \\
  &amp;=
  \frac{\mathbb P(P_A \mid A) \mathbb P(A)}{\mathbb P(P_A \mid A) \mathbb P(A) + \mathbb P(P_A \mid B) \mathbb P(B)}
  \\
  &amp;=
  \frac{0.8 \cdot 0.5 }{0.8 \cdot 0.5 + 0.35 \cdot 0.5}
  \\
  &amp;=
  \frac{0.4 }{0.4 + 0.175}
  \\
  &amp;=
  \frac{0.4 }{0.575}
\end{align}
\]</span></p>
<p>This is about 0.696.</p>
<p>Finally H4b.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P(A \mid P_A, T_1, -T_2)
  &amp;=
  \frac{\mathbb P(P_A \mid A, T_1, -T_2) \mathbb P(A \mid T_1, -T_2)}{\mathbb P(P_A \mid T_1, -T_2)}
  \\
  &amp;=
  \frac{\mathbb P(P_A \mid A) \mathbb P(A \mid T_1, -T_2)}{\mathbb P(P_A \mid A) \mathbb P(A \mid T_1, -T_2) + \mathbb P(P_A \mid B) \mathbb P(B \mid T_1, -T_2)}
  \\
  &amp;=
  \frac{\frac{4}{5} \cdot \frac{6}{17} }{\frac{4}{5}\cdot \frac{6}{17} + \frac{7}{20} \cdot \frac{11}{17}}
  \\
  &amp;=
  \frac{\frac{24}{85} }{\frac{24}{85} + \frac{77}{340}}
  \\
  &amp;=
  \frac{\frac{24}{85} }{\frac{92 + 77}{340}}
  \\
  &amp;=
  \frac{24}{85} \cdot \frac{340}{169}
  \\
  &amp;=
  \frac{92}{169} 
\end{align}
\]</span></p>
<p>This is about 0.544.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>SR2 Chapter 2 Medium</title>
    <link href="http://www.briancallander.com/posts/statistical-rethinking-2/exercise_2M.html" />
    <id>http://www.briancallander.com/posts/statistical-rethinking-2/exercise_2M.html</id>
    <published>2020-02-29T00:00:00Z</published>
    <updated>2020-02-29T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">SR2 Chapter 2 Medium</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on 29 February, 2020  by Brian </br>
     Tags: <a href="/tags/statistical%20rethinking.html">statistical rethinking</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/conditional%20probability.html">conditional probability</a>, <a href="/tags/counting.html">counting</a>, <a href="/tags/grid%20approximation.html">grid approximation</a> </br>
     Category: <a href="/categories/statistical-rethinking-2.html">statistical-rethinking-2</a> 
    </p>
  </div>
</div>

<p>Here’s my solutions to the medium exercises in chapter 2 of McElreath’s Statistical Rethinking, 1st edition. My intention is to move over to the 1nd edition when it comes out next month.</p>
<!--more-->
<div>
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbernoulli}{Bernoulli} \DeclareMathOperator{\dpoisson}{Poisson} \DeclareMathOperator{\dnormal}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexponential}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvpamma}{Invpamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<h2 id="globe-tossing">Globe Tossing</h2>
<p>Start by creating a grid and the function <code>posterior</code> which we we use for several calculations. This is analogous to the code provided in the chapter.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">p_true &lt;-<span class="st"> </span><span class="fl">0.7</span> <span class="co"># assumed ground truth</span>

granularity &lt;-<span class="st"> </span><span class="dv">1000</span> <span class="co"># number of points on grid</span>

grid1 &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">p =</span> <span class="kw">seq</span>(<span class="dv">0</span>, <span class="dv">1</span>, <span class="dt">length.out =</span> granularity)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">prior =</span> <span class="dv">1</span>)

posterior &lt;-<span class="st"> </span><span class="cf">function</span>(data, grid) {
  grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">mutate</span>(
      <span class="dt">likelihood =</span> <span class="kw">dbinom</span>(<span class="kw">sum</span>(data <span class="op">==</span><span class="st"> &#39;W&#39;</span>), <span class="kw">length</span>(data), p),
      <span class="dt">unstd_posterior =</span> prior <span class="op">*</span><span class="st"> </span>likelihood,
      <span class="dt">posterior =</span> unstd_posterior <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(unstd_posterior)
    )
}</code></pre></div>
<p>The exercise asks us to approximate the posterior for each of the following three datasets. To do this, we just apply our <code>posterior</code> function above to each of them.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">data &lt;-<span class="st"> </span><span class="kw">list</span>(
    <span class="st">&#39;1&#39;</span> =<span class="st"> </span><span class="kw">c</span>(<span class="st">&#39;W&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;L&#39;</span>),
    <span class="st">&#39;2&#39;</span> =<span class="st"> </span><span class="kw">c</span>(<span class="st">&#39;W&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;L&#39;</span>),
    <span class="st">&#39;3&#39;</span> =<span class="st"> </span><span class="kw">c</span>(<span class="st">&#39;L&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;L&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;W&#39;</span>, <span class="st">&#39;W&#39;</span>)
  ) 

m1 &lt;-<span class="st"> </span>data <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">map_dfr</span>(posterior, grid1, <span class="dt">.id =</span> <span class="st">&#39;dataset&#39;</span>)</code></pre></div>
<figure>
<img src="exercise_2M_files/figure-markdown/unnamed-chunk-3-1.svg" alt="Solution 2M1" /><figcaption>Solution 2M1</figcaption>
</figure>
<p>The posterior becomes gradually more concentrated around the ground truth.</p>
<p>For the second question, we simply do the same but with a different prior. More specifically, for any p below 0.5 we set the prior to zero, then map our posterior over each the the datasets with this new grid.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grid2 &lt;-<span class="st"> </span>grid1 <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">prior =</span> <span class="kw">if_else</span>(p <span class="op">&lt;</span><span class="st"> </span><span class="fl">0.5</span>, <span class="dv">0</span>, prior))

m2 &lt;-<span class="st"> </span>data <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">map_dfr</span>(posterior, grid2, <span class="dt">.id =</span> <span class="st">&#39;dataset&#39;</span>)</code></pre></div>
<figure>
<img src="exercise_2M_files/figure-markdown/unnamed-chunk-5-1.svg" alt="Solution 2M2" /><figcaption>Solution 2M2</figcaption>
</figure>
<p>Again we see the posterior concentrate more around the ground truth. Moreover, the distribution is more peaked (at ~ 0.003) than with the uniform prior, which peaks at around (~0.0025). The first dataset already gets pretty close to this peak, i.e. this more informative prior gets us better inferences sooner.</p>
<p>For the final question on globe tossing, we can just use the counting method rather than grid approximation. We enumerate all possible events in proportion to how likely they are to occur: 10 L for Mars, 3 L and 7 W for Earth. Then we filter our any inconsistent with our observation of land, and summarise the remaining possibilities.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m3 &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">mars =</span> <span class="kw">rep</span>(<span class="st">&#39;L&#39;</span>, <span class="dv">10</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">earth =</span> <span class="kw">if_else</span>(<span class="kw">row_number</span>() <span class="op">&lt;=</span><span class="st"> </span><span class="dv">3</span>, <span class="st">&#39;L&#39;</span>, <span class="st">&#39;W&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(planet, observation) <span class="op">%&gt;%</span><span class="st">  </span><span class="co"># all possible events</span>
<span class="st">  </span><span class="kw">filter</span>(observation <span class="op">==</span><span class="st"> &#39;L&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># only those events consistent with observation</span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(planet <span class="op">==</span><span class="st"> &#39;earth&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># fraction of possible events that are earth</span>
<span class="st">  </span><span class="kw">pull</span>()

m3</code></pre></div>
<pre><code>[1] 0.2307692</code></pre>
<p>We get around 23%.</p>
<h2 id="card-drawing">Card Drawing</h2>
<p>We make a list of all sides, filter out any inconsistent with our observation of a black side, then summarise the remaining card possibilities.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m4_events &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">card =</span> <span class="kw">c</span>(<span class="st">&quot;BB&quot;</span>, <span class="st">&quot;BW&quot;</span>, <span class="st">&quot;WW&quot;</span>)) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># all the cards</span>
<span class="st">  </span><span class="kw">separate</span>(card, <span class="dt">into =</span> <span class="kw">c</span>(<span class="st">&#39;side1&#39;</span>, <span class="st">&#39;side2&#39;</span>), <span class="dt">sep =</span> <span class="dv">1</span>, <span class="dt">remove =</span> F) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(side, colour, <span class="op">-</span>card) <span class="co"># all the sides</span>

m4_possibilities &lt;-<span class="st"> </span>m4_events <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="kw">filter</span>(colour <span class="op">==</span><span class="st"> &#39;B&#39;</span>) <span class="co"># just the possible events where there is a black side</span>

m4 &lt;-<span class="st"> </span>m4_possibilities <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(card <span class="op">==</span><span class="st"> &#39;BB&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>() <span class="co"># which fraction of possible events is a double black?</span>

m4</code></pre></div>
<pre><code>[1] 0.6666667</code></pre>
<p>The next exercise is the same as the previous but with more cards. Note that this equivalent to using the three cards as before but with a larger prior probability on the BB card.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m5_events &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">card =</span> <span class="kw">c</span>(<span class="st">&quot;BB&quot;</span>, <span class="st">&quot;BW&quot;</span>, <span class="st">&quot;WW&quot;</span>, <span class="st">&quot;BB&quot;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">separate</span>(card, <span class="dt">into =</span> <span class="kw">c</span>(<span class="st">&#39;side1&#39;</span>, <span class="st">&#39;side2&#39;</span>), <span class="dt">sep =</span> <span class="dv">1</span>, <span class="dt">remove =</span> F) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(side, colour, <span class="op">-</span>card) 

m5_possibilities &lt;-<span class="st"> </span>m5_events <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(colour <span class="op">==</span><span class="st"> &#39;B&#39;</span>) 

m5 &lt;-<span class="st"> </span>m5_possibilities <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(card <span class="op">==</span><span class="st"> &#39;BB&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>()

m5</code></pre></div>
<pre><code>[1] 0.8</code></pre>
<p>Putting the prior on the cards is equivalent to having the cards in proportion to their prior. The rest of the calculation is the same.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m6_events &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;BB&quot;</span>, <span class="st">&quot;BW&quot;</span>, <span class="st">&quot;WW&quot;</span>) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># cards</span>
<span class="st">  </span><span class="kw">rep</span>(<span class="kw">c</span>(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># prior: repeat each card the given number of times</span>
<span class="st">  </span><span class="kw">tibble</span>(<span class="dt">card =</span> .) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">separate</span>(card, <span class="dt">into =</span> <span class="kw">c</span>(<span class="st">&#39;side1&#39;</span>, <span class="st">&#39;side2&#39;</span>), <span class="dt">sep =</span> <span class="dv">1</span>, <span class="dt">remove =</span> F) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">gather</span>(side, colour, <span class="op">-</span>card) 

m6_possibilities &lt;-<span class="st"> </span>m6_events <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># sides</span>
<span class="st">  </span><span class="kw">filter</span>(colour <span class="op">==</span><span class="st"> &#39;B&#39;</span>) 

m6 &lt;-<span class="st"> </span>m6_possibilities <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># sides consistent with observation</span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(card <span class="op">==</span><span class="st"> &#39;BB&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># proportion of possible events that are BB</span>
<span class="st">  </span><span class="kw">pull</span>()

m6</code></pre></div>
<pre><code>[1] 0.5</code></pre>
<p>This last card drawing exercise is slightly more involved since we can observe any of the two sides of the one card and any of the two sides of the other. Thus, we first generate the list of all possible pairs of cards, expand this into a list of all possible sides that could be observed for each card, filter out any event not consisent with our observations, then summarise whatever is left.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m7_card_pairs &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">card =</span> <span class="kw">c</span>(<span class="st">&quot;BB&quot;</span>, <span class="st">&quot;BW&quot;</span>, <span class="st">&quot;WW&quot;</span>)) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># all the cards</span>
<span class="st">  </span><span class="kw">crossing</span>(., <span class="dt">other_card =</span> .<span class="op">$</span>card) <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="kw">filter</span>(card <span class="op">!=</span><span class="st"> </span>other_card) <span class="co"># all card pairs (can&#39;t draw the same card twice)</span>

m7_events &lt;-<span class="st"> </span>m7_card_pairs <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">separate</span>(card, <span class="dt">into =</span> <span class="kw">c</span>(<span class="st">&#39;side1&#39;</span>, <span class="st">&#39;side2&#39;</span>), <span class="dt">sep =</span> <span class="dv">1</span>, <span class="dt">remove =</span> F) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">separate</span>(other_card, <span class="dt">into =</span> <span class="kw">c</span>(<span class="st">&#39;other_side1&#39;</span>, <span class="st">&#39;other_side2&#39;</span>), <span class="dt">sep =</span> <span class="dv">1</span>, <span class="dt">remove =</span> F) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(side, colour, side1, side2) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># all the sides for card of interest</span>
<span class="st">  </span><span class="kw">gather</span>(other_side, other_colour, other_side1, other_side2) <span class="co"># all sides of other card</span>

m7_possibilities &lt;-<span class="st"> </span>m7_events <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="kw">filter</span>(
    colour <span class="op">==</span><span class="st"> &#39;B&#39;</span>, <span class="co"># we observe that card of interest has a black side</span>
    other_colour <span class="op">==</span><span class="st"> &#39;W&#39;</span> <span class="co"># we observe that the other card has a white side</span>
  ) 

m7 &lt;-<span class="st"> </span>m7_possibilities <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(card <span class="op">==</span><span class="st"> &#39;BB&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span><span class="co"># which fraction of possible events is a double black?</span>
<span class="st">  </span><span class="kw">pull</span>()

m7</code></pre></div>
<pre><code>[1] 0.75</code></pre>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>Speeding up Bayesian sampling with map_rect</title>
    <link href="http://www.briancallander.com/posts/map_rect/speeding_up_bayesian_sampling_with_map_rect.html" />
    <id>http://www.briancallander.com/posts/map_rect/speeding_up_bayesian_sampling_with_map_rect.html</id>
    <published>2019-08-09T00:00:00Z</published>
    <updated>2019-08-09T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">Speeding up Bayesian sampling with map_rect</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on  9 August, 2019  by Brian </br>
     Tags: <a href="/tags/stan.html">stan</a>, <a href="/tags/map_rect.html">map_rect</a>, <a href="/tags/within-chain%20parallelisation.html">within-chain parallelisation</a>, <a href="/tags/threading.html">threading</a>, <a href="/tags/ordinal%0Aregression.html">ordinal
regression</a> </br>
     Category: <a href="/categories/map_rect.html">map_rect</a> 
    </p>
  </div>
</div>

<p>Fitting a full Bayesian model can be slow, especially with a large dataset. For example, it’d be great to analyse the climate crisis questions in the <a href="https://www.europeansocialsurvey.org/data/round-index.html">European Social Survey (ESS)</a>, which typically has around 45,000 respondents from around Europe on a range of socio-political questions. There are two main ways of parallelising your Bayesian model in Stan: between-chain parallelisation and within-chain parallelisation. The first of these is very easy to implement (<code>chains = 4</code>, <code>cores = 4</code>) - it simply runs the algorithm once on each core and pools the posterior samples at the end. The second method is more complicated as it requires a non-trivial modification to the Stan model, but can bring with it large speedups if you have the cores available. In this post we’ll get a &gt;5x speedup of ordinal regression using within-chain parallelisation.</p>
<!--more-->
<p>I’ll assume you are somewhat familiar with <a href="https://github.com/rmcelreath/cmdstan_map_rect_tutorial">McElreath’s introduction with cmdstan</a>, with <a href="https://blog.ignacio.website/post/multithreading-and-map-reduce-in-stan/">Ignacio’s introduction with rstan</a>, and/or with the <a href="https://mc-stan.org/docs/2_19/stan-users-guide/map-reduce-chapter.html">Stan user guide</a>. We’ll implement a mapped version of ordinal regression with one (factor) covariate using similar ideas. The main difference is that we’ll have a shard set up for each distinct level of the factor, and each shard will receive a different number of datapoints. This is my first attempt at making sense of this, so use at your own risk.</p>
<p><strong>Important note</strong>: there is <a href="https://github.com/stan-dev/math/issues/1248#issuecomment-494350329">a bug</a> in the <code>ordered_logistic_lpmf</code> function in stan 2.19.2, the version I currently have installed. Until the fixed version in stan 2.20, I went for the <a href="https://discourse.mc-stan.org/t/ordered-logistic-lpmf/9799/2">easy fix</a>.</p>
<h2 id="setup">Setup</h2>
<p>Suppose you have a large dataset and/or a log-likelihood function that is expensive to evaluate. Then you can break down your dataset into chunks (called <code>shards</code>), calculate the log-likelihood on each shard in parallel, then sum up the log-likelihood of each shard at the end.</p>
<p>There seem to be two types of within-chain parallelisation: <code>threading</code> and <code>Message Passing Interface (MPI)</code>. MPI requires some <a href="https://github.com/stan-dev/math/wiki/MPI-Parallelism">extra setup</a> and is typicaly used if you want to implement within-chain parallelisation across multiple computers. We’ll stick with the simpler threading method.</p>
<p>A <code>thread</code> is (confusingly) sometimes called a <code>core</code>. The number of <code>threads</code> you have will determine how many <code>shards</code> you can calculate at the same time. You can see how many threads you have available with <code>nproc --all</code>.</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">nproc</span> --all</code></pre></div>
<pre><code>4</code></pre>
<p>So I can run 4 threads at the same time. For a more detailed breakdown use <code>lscpu</code>, where the number of threads is given by <code>CPU(s)</code> and is equal to <code>Thread(s) per core</code> * <code>Core(s) per socket</code> * <code>Socket(s)</code>. For me this is 4 = 1 * 4 * 1.</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">lscpu</span></code></pre></div>
<pre><code>Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              4
On-line CPU(s) list: 0-3
Thread(s) per core:  1
Core(s) per socket:  4
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               158
Model name:          Intel(R) Core(TM) i5-7600K CPU @ 3.80GHz
Stepping:            9
CPU MHz:             3993.031
CPU max MHz:         4200,0000
CPU min MHz:         800,0000
BogoMIPS:            7584.00
Virtualisation:      VT-x
L1d cache:           32K
L1i cache:           32K
L2 cache:            256K
L3 cache:            6144K
NUMA node0 CPU(s):   0-3
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d</code></pre>
<p>Before compiling a model with threading, we have to tell Stan to compile with threading. For me, this worked by adding <code>-DSTAN_THREADS -pthread</code> to my Makevars file. Check out the <a href="https://github.com/stan-dev/math/wiki/Threading-Support">recommendations in the docs</a> for more information on this.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">Sys.getenv</span>(<span class="st">&quot;HOME&quot;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">file.path</span>(<span class="st">&quot;.R&quot;</span>, <span class="st">&quot;Makevars&quot;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">print</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">read_file</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">writeLines</span>()</code></pre></div>
<pre><code>[1] &quot;/home/brian/.R/Makevars&quot;
CXX14FLAGS = -O3 -march=native -mtune=native
CXX14FLAGS += -fPIC
CXX14FLAGS += -DSTAN_THREADS
CXX14FLAGS += -pthread</code></pre>
<p>Before fitting a model with threading, we’ll have to tell Stan how many threads are available via the environment variable <code>STAN_NUM_THREADS</code>. We’ll run it now just to be sure.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">Sys.setenv</span>(<span class="dt">STAN_NUM_THREADS =</span> <span class="dv">4</span>)</code></pre></div>
<p>Now we’re all setup for threading.</p>
<h2 id="generate-the-data">Generate the data</h2>
<p>Let’s generate observations from the prior predictive distribution. Skip this section if you’re just interested in the parallelisation. We’ll a similar <a href="./models/ordinal_regression_betancourt.stan">model</a> as described in <a href="https://www.patreon.com/betanalpha/posts">Michael Betancourt’s</a> <a href="https://betanalpha.github.io/assets/case_studies/ordinal_regression.html">case study</a>. The main difference is that we’ll use contrast factors for our latent effect.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m_sim &lt;-<span class="st"> &quot;models/ordinal_regression_sim_betancourt.stan&quot;</span> <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">here</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">stan_model</span>()</code></pre></div>
<p>We’ll generate 20,000 observations, where the only covariate is called <code>factr</code>, of which we have around 50 unique values. Notice that we will end up with a different number of observations for each level of <code>factr</code>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">set.seed</span>(<span class="dv">12096</span>)

N &lt;-<span class="st"> </span><span class="dv">20000</span> <span class="co"># number of observations</span>
K &lt;-<span class="st"> </span><span class="dv">5</span>     <span class="co"># number of ordinal outcomes</span>
L &lt;-<span class="st"> </span><span class="dv">50</span>    <span class="co"># number of unique levels in our factor</span>

<span class="co"># the covariates</span>
df_sim &lt;-<span class="st"> </span><span class="dv">1</span><span class="op">:</span>L <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sample</span>(<span class="dt">size =</span> N, <span class="dt">replace =</span> <span class="ot">TRUE</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(<span class="dt">factr =</span> .) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">factr =</span> factr <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">as_factor</span>() <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">fct_reorder</span>(factr)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">arrange</span>(factr)

<span class="co"># in list-format for stan</span>
data_sim &lt;-<span class="st"> </span><span class="kw">list</span>(
  <span class="dt">N =</span> N,
  <span class="dt">K =</span> K,
  <span class="dt">L =</span> L,
  <span class="dt">factr =</span> <span class="kw">model.matrix</span>(<span class="op">~</span><span class="st"> </span><span class="dv">1</span> <span class="op">+</span><span class="st"> </span>factr, df_sim)[, <span class="dv">2</span><span class="op">:</span>L], <span class="co"># contrast encoding</span>
  <span class="co"># hyperparameters</span>
  <span class="dt">factr_mu =</span> <span class="dv">0</span>,
  <span class="dt">factr_sd =</span> <span class="dv">1</span>,
  <span class="dt">alpha =</span> <span class="kw">c</span>(<span class="dv">2</span>, <span class="dv">4</span>, <span class="dv">8</span>, <span class="dv">4</span>, <span class="dv">2</span>)
)</code></pre></div>
<p>Now we simply draw once from the prior predictive distribution, then extract the parameters and outcome.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># draw from the prior predictive distribution</span>
fit_sim &lt;-<span class="st"> </span>m_sim <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sampling</span>(
    <span class="dt">algorithm =</span> <span class="st">&#39;Fixed_param&#39;</span>,
    <span class="dt">data =</span> data_sim,
    <span class="dt">iter =</span> <span class="dv">1</span>,
    <span class="dt">chains =</span> <span class="dv">1</span>,
    <span class="dt">seed =</span> <span class="dv">43484</span>
  )

<span class="co"># extract the parameters and observations</span>
cutpoints &lt;-<span class="st"> </span>fit_sim <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">spread_draws</span>(c[i]) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(c)

effects &lt;-<span class="st"> </span>fit_sim <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">spread_draws</span>(beta[i]) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(beta)

y &lt;-<span class="st"> </span>fit_sim <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">spread_draws</span>(y[i]) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>(y)

<span class="co"># put covariates and outcome in the one dataset</span>
df &lt;-<span class="st"> </span>df_sim <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">y =</span> y,
    <span class="dt">factr =</span> factr <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">as.integer</span>()
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">arrange</span>(factr)

<span class="co"># as a list for stan</span>
data &lt;-<span class="st"> </span>data_sim <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">list_modify</span>(<span class="dt">y =</span> df<span class="op">$</span>y)</code></pre></div>
<figure>
<img src="speeding_up_bayesian_sampling_with_map_rect_files/figure-markdown/data_plot-1.png" alt="Counts of each outcome variable" /><figcaption>Counts of each outcome variable</figcaption>
</figure>
<h2 id="the-unmapped-model">The unmapped model</h2>
<p>Let’s check that <a href="./models/ordinal_regression.stan">Betancourt’s model</a> <code>m</code> passes some standard diagnostic tests on our data and time how long it takes to fit.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m &lt;-<span class="st"> &quot;models/ordinal_regression_betancourt.stan&quot;</span> <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">here</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">stan_model</span>()</code></pre></div>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">start &lt;-<span class="st"> </span><span class="kw">Sys.time</span>()
fit &lt;-<span class="st"> </span>m <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sampling</span>(
    <span class="dt">data =</span> data,
    <span class="dt">chains =</span> <span class="dv">1</span>,
    <span class="dt">warmup =</span> <span class="dv">500</span>,
    <span class="dt">iter =</span> <span class="dv">2000</span>,
    <span class="dt">seed =</span> <span class="dv">14031</span>
  )
end &lt;-<span class="st"> </span><span class="kw">Sys.time</span>()
duration &lt;-<span class="st"> </span>end <span class="op">-</span><span class="st"> </span>start</code></pre></div>
<p>The fitting took 5.7 minutes.</p>
<p>The HMC diagnostics look good.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">rstan<span class="op">::</span><span class="kw">check_hmc_diagnostics</span>(fit)</code></pre></div>
<pre><code>Divergences:

0 of 1500 iterations ended with a divergence.


Tree depth:

0 of 1500 iterations saturated the maximum tree depth of 10.


Energy:

E-BFMI indicated no pathological behavior.</code></pre>
<p>The rhat is smaller than 1.05 and the bulk/tail ESS are over 100, which is good.</p>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Max/min of ESS and Rhat diagnostics of the unmapped model
</caption>
<thead>
<tr>
<th style="text-align:left;">
variable
</th>
<th style="text-align:right;">
rhat_min
</th>
<th style="text-align:right;">
ess_bulk_min
</th>
<th style="text-align:right;">
ess_tail_min
</th>
<th style="text-align:right;">
rhat_max
</th>
<th style="text-align:right;">
ess_bulk_max
</th>
<th style="text-align:right;">
ess_tail_max
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
beta
</td>
<td style="text-align:right;">
1.00
</td>
<td style="text-align:right;">
165.98
</td>
<td style="text-align:right;">
306.02
</td>
<td style="text-align:right;">
1.01
</td>
<td style="text-align:right;">
254.76
</td>
<td style="text-align:right;">
654.57
</td>
</tr>
<tr>
<td style="text-align:left;">
c
</td>
<td style="text-align:right;">
1.01
</td>
<td style="text-align:right;">
102.99
</td>
<td style="text-align:right;">
179.38
</td>
<td style="text-align:right;">
1.01
</td>
<td style="text-align:right;">
107.56
</td>
<td style="text-align:right;">
214.77
</td>
</tr>
</tbody>
</table>
<p>The cutpoints have been estimated slightly too low, but within reasonable bounds.</p>
<figure>
<img src="speeding_up_bayesian_sampling_with_map_rect_files/figure-markdown/cutpoint_posterior-1.png" alt="Posterior distribution of cutpoints" /><figcaption>Posterior distribution of cutpoints</figcaption>
</figure>
<p>Around 93.9% of the 90% intervals for β contained the true values. This is not bad considering that one error carries the weight of over 2 percentage points.</p>
<h2 id="the-mapped-model">The mapped model</h2>
<p>Now for the <a href="./models/ordinal_regression_mapped.stan">mapped version</a>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">m_mapped &lt;-<span class="st"> &quot;models/ordinal_regression_mapped.stan&quot;</span> <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">here</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">stan_model</span>()</code></pre></div>
<p>We’ll set up a shard for every level of our factor. The function <code>lp</code> for calculating the log-posterior on one shard looks like this. The first entry in our integer array <code>xi</code> is the number of observations <code>M</code> for this level/shard. The data we need is then contained in the next <code>M</code> entries of <code>xi</code>. The cutpoints are the only global parameters we’ll use here. The estimated effect for this level is given by <code>beta</code>, the only local parameter for this shard. The log-likelihood <code>ll</code> is then calculated as usual.</p>
<pre><code>functions {
  vector lp(vector global, vector local, real[] xr, int[] xi) {
    int M = xi[1];             
    int y[M] = xi[2:M+1];      
    vector[4] c = global[1:4]; 
    real beta = local[1];      

    real ll = ordered_logistic_lpmf(y | rep_vector(beta, M), c);

    return [ll]&#39;;
  }
}</code></pre>
<p>The shards are set up in the transformed data section. Since we have a shard for every level, we simply index the shards using the levels. This makes it very easy to keep track of which shard gets the next datapoint. The first entry of each shard is reserved for the number of datapoints used in that shard. To keep track of where to put the next datapoint within a shard, we setup the array <code>j</code>. This starts at 2 because position 1 is reserved for the number of datapoints in the shard. Everytime we add a datapoint to a shard, we increment that shard’s entry in <code>j</code> so that the next datapoint lands in the correct place.</p>
<pre><code>transformed data {
  int&lt;lower = 0, upper = N&gt; counts[L] = count(factr, L); 

  int&lt;lower = 1&gt; M = max(counts) + 1; 

  int xi[L, max(counts) + 1];  
  real xr[L, max(counts) + 1]; 

  int&lt;lower = 1&gt; j[L] = rep_array(2, L); 
  xi[, 1] = counts;
  for (i in 1:N) {
    int shard = factr[i];
    xi[shard, j[shard]] = y[i];
    j[shard] += 1;
  }
}</code></pre>
<p>I really like this way of creating shards because it doesn’t become such a mess of indices.</p>
<p>Now let’s time it.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">start_mapped &lt;-<span class="st"> </span><span class="kw">Sys.time</span>()

fit_mapped &lt;-<span class="st"> </span>m_mapped <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">sampling</span>(
    <span class="dt">data =</span> data <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">list_modify</span>(<span class="dt">factr =</span> df<span class="op">$</span>factr),
    <span class="dt">chains =</span> <span class="dv">1</span>,
    <span class="dt">warmup =</span> <span class="dv">500</span>,
    <span class="dt">iter =</span> <span class="dv">2000</span>,
    <span class="dt">seed =</span> <span class="dv">98176</span>
  )

end_mapped &lt;-<span class="st"> </span><span class="kw">Sys.time</span>()
duration_mapped &lt;-<span class="st"> </span>end_mapped <span class="op">-</span><span class="st"> </span>start_mapped</code></pre></div>
<p>The fitting took 64.8523884 seconds. This is a 5.3-fold speedup!</p>
<p>The HMC diagnostics look good.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">rstan<span class="op">::</span><span class="kw">check_hmc_diagnostics</span>(fit_mapped)</code></pre></div>
<pre><code>Divergences:

0 of 1500 iterations ended with a divergence.


Tree depth:

0 of 1500 iterations saturated the maximum tree depth of 10.


Energy:

E-BFMI indicated no pathological behavior.</code></pre>
<p>The rhat and ESS values are still good.</p>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Max/min of ESS and Rhat diagnostics of the mapped model
</caption>
<thead>
<tr>
<th style="text-align:left;">
variable
</th>
<th style="text-align:right;">
rhat_min
</th>
<th style="text-align:right;">
ess_bulk_min
</th>
<th style="text-align:right;">
ess_tail_min
</th>
<th style="text-align:right;">
rhat_max
</th>
<th style="text-align:right;">
ess_bulk_max
</th>
<th style="text-align:right;">
ess_tail_max
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
beta
</td>
<td style="text-align:right;">
0.999
</td>
<td style="text-align:right;">
439.148
</td>
<td style="text-align:right;">
587.322
</td>
<td style="text-align:right;">
1.005
</td>
<td style="text-align:right;">
634.109
</td>
<td style="text-align:right;">
979.157
</td>
</tr>
<tr>
<td style="text-align:left;">
c
</td>
<td style="text-align:right;">
1.001
</td>
<td style="text-align:right;">
286.037
</td>
<td style="text-align:right;">
422.349
</td>
<td style="text-align:right;">
1.003
</td>
<td style="text-align:right;">
293.793
</td>
<td style="text-align:right;">
481.067
</td>
</tr>
</tbody>
</table>
<p>The posteriors of the cutpoints are much the same as before.</p>
<figure>
<img src="speeding_up_bayesian_sampling_with_map_rect_files/figure-markdown/cutpoint_posterior_mapped-1.png" alt="Posterior distribution of cutpoints using the mapped model" /><figcaption>Posterior distribution of cutpoints using the mapped model</figcaption>
</figure>
<p>The level-effects are as well-calibrated as before, with around 93.9% of the 90% intervals for β containing the true values.</p>
<p>We can measure the similarity of the estimates in two ways:</p>
<ol type="1">
<li>the absolute difference in the point estimates; and</li>
<li>the ratio between the length of the overlap of the two 90% intervals and the length of the shortest of the two 90% intervals.</li>
</ol>
<p>In each case the estimates look roughly the same, especially with respect to the ratio metric. The differences are a bit larger than I would have expected, but I’m not so sure on what scale a ‘good’ difference would be.</p>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Summary statistics for ratio in mapped estimates
</caption>
<thead>
<tr>
<th style="text-align:left;">
metric
</th>
<th style="text-align:right;">
value
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
change_max
</td>
<td style="text-align:right;">
0.0153
</td>
</tr>
<tr>
<td style="text-align:left;">
change_mean
</td>
<td style="text-align:right;">
0.0102
</td>
</tr>
<tr>
<td style="text-align:left;">
change_median
</td>
<td style="text-align:right;">
0.0107
</td>
</tr>
<tr>
<td style="text-align:left;">
change_min
</td>
<td style="text-align:right;">
0.0032
</td>
</tr>
<tr>
<td style="text-align:left;">
ratio_max
</td>
<td style="text-align:right;">
1.0000
</td>
</tr>
<tr>
<td style="text-align:left;">
ratio_mean
</td>
<td style="text-align:right;">
0.9897
</td>
</tr>
<tr>
<td style="text-align:left;">
ratio_median
</td>
<td style="text-align:right;">
0.9960
</td>
</tr>
<tr>
<td style="text-align:left;">
ratio_min
</td>
<td style="text-align:right;">
0.9619
</td>
</tr>
</tbody>
</table>
<h2 id="next-steps">Next steps</h2>
<p>I’m fairly happy with the speedup seen here. Actually, I’m mostly happy I got it working at all. It’s entirely possible that creating 50 shards with only 4 threads to run them on isn’t the most efficient way to use threading, but I’ll keep doing it like this until there’s a more convenient way to do it. Higher up in my priorities right now are:</p>
<ul>
<li>adding more covariates, especially factors; and</li>
<li>putting a hierarchical prior on the factor; e.g. for use in <a href="https://arxiv.org/abs/1906.11323">MRP</a>.</li>
</ul>
<p>The bulk ESS values are a bit on the low side, so there could be a better way to parameterise the model.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>Hierarchical Customer Lifetime Value</title>
    <link href="http://www.briancallander.com/posts/customer_lifetime_value/recency_frequency.html" />
    <id>http://www.briancallander.com/posts/customer_lifetime_value/recency_frequency.html</id>
    <published>2019-05-05T00:00:00Z</published>
    <updated>2019-05-05T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">Hierarchical Customer Lifetime Value</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on  5 May, 2019  by Brian </br>
     Tags: <a href="/tags/customer%20lifetime%20value.html">customer lifetime value</a>, <a href="/tags/recency%20frequency.html">recency frequency</a>, <a href="/tags/hierarchical%20model.html">hierarchical model</a>, <a href="/tags/centred%0Aparameterisation.html">centred
parameterisation</a>, <a href="/tags/non-centred%20parameterisation.html">non-centred parameterisation</a>, <a href="/tags/prior-predictive%0Adistribution.html">prior-predictive
distribution</a>, <a href="/tags/stan.html">stan</a>, <a href="/tags/e-bfmi.html">e-bfmi</a>, <a href="/tags/energy.html">energy</a> </br>
     Category: <a href="/categories/customer_lifetime_value.html">customer_lifetime_value</a> 
    </p>
  </div>
</div>

<p>In a <a href="./pareto-nbd.html">previous post</a>, we described how a model of customer lifetime value (CLV) works, implemented it in Stan, and fit the model to simulated data. In this post, we’ll extend the model to use hierarchical priors in two different ways: <a href="https://mc-stan.org/docs/2_18/stan-users-guide/reparameterization-section.html">centred and non-centred</a> parameterisations. I’m not aware of any other HMC-based implementations of this hierarchical CLV model, so we’ll run some basic tests to check it’s doing the right thing. More specifically, we’ll fit it to a dataset drawn from the prior predictive distribution. The resulting fits pass the main diagnostic tests and the 90% posterior intervals capture about 91% of the true parameter values.</p>
<!--more-->
<p>A word of warning: I came across a number of examples where the model showed severe <a href="https://mc-stan.org/misc/warnings.html#bfmi-low">E-BFMI</a> problems. This seems to happen when the parameters <span class="math inline">\(\mu\)</span> (inverse expected lifetime) and <span class="math inline">\(\lambda\)</span> (expected purchase rate) are fairly similar, but I haven’t pinned down a solid reason for these energy problems yet. I suspect this has something to do with the difficulty in distinguishing a short lifetime from a low purchase rate. This is a topic we’ll leave for a future post.</p>
<p>We’ll work with raw stan, which can be a bit fiddly sometimes. To keep this post within the limits of readability, I’ll define some custom functions to simplify the process. Check out the <a href="./recency_frequency.Rmd">full code</a> to see the details of these functions.</p>
<div>
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial}\DeclareMathOperator{\dbernoulli}{Bernoulli}\DeclareMathOperator{\dpoisson}{Poisson}\DeclareMathOperator{\dnormal}{Normal}\DeclareMathOperator{\dt}{t}\DeclareMathOperator{\dcauchy}{Cauchy}\DeclareMathOperator{\dexponential}{Exp}\DeclareMathOperator{\duniform}{Uniform}\DeclareMathOperator{\dgamma}{Gamma}\DeclareMathOperator{\dinvgamma}{InvGamma}\DeclareMathOperator{\invlogit}{InvLogit}\DeclareMathOperator{\logit}{Logit}\DeclareMathOperator{\ddirichlet}{Dirichlet}\DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<h2 id="data-generating-process">Data Generating Process</h2>
<p>Let’s recap on the story from last time. We have a 2-year old company that has grown linearly over that time to gain a total of 1000 customers.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">set.seed</span>(<span class="dv">65130</span>) <span class="co"># https://www.random.org/integers/?num=2&amp;min=1&amp;max=100000&amp;col=5&amp;base=10&amp;format=html&amp;rnd=new</span>

customers &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">id =</span> <span class="dv">1</span><span class="op">:</span><span class="dv">1000</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">end =</span> <span class="dv">2</span> <span class="op">*</span><span class="st"> </span><span class="dv">365</span>,
    <span class="dt">start =</span> <span class="kw">runif</span>(<span class="kw">n</span>(), <span class="dv">0</span>, end <span class="op">-</span><span class="st"> </span><span class="dv">1</span>),
    <span class="dt">T =</span> end <span class="op">-</span><span class="st"> </span>start
  )</code></pre></div>
<p>Within a customer’s lifetime <span class="math inline">\(\tau\)</span>, they will purchase with Poisson-rate <span class="math inline">\(\lambda\)</span>. We can simulate the time <span class="math inline">\(t\)</span> till last observed purchase and number of purchases <span class="math inline">\(k\)</span> with <code>sample_conditional</code>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sample_conditional &lt;-<span class="st"> </span><span class="cf">function</span>(T, tau, lambda) {
  
  <span class="co"># start with 0 purchases</span>
  t &lt;-<span class="st"> </span><span class="dv">0</span>
  k &lt;-<span class="st"> </span><span class="dv">0</span>
  
  <span class="co"># simulate time till next purchase</span>
  wait &lt;-<span class="st"> </span><span class="kw">rexp</span>(<span class="dv">1</span>, lambda)
  
  <span class="co"># keep purchasing till end of life/observation time</span>
  <span class="cf">while</span>(t <span class="op">+</span><span class="st"> </span>wait <span class="op">&lt;=</span><span class="st"> </span><span class="kw">pmin</span>(T, tau)) {
    t &lt;-<span class="st"> </span>t <span class="op">+</span><span class="st"> </span>wait
    k &lt;-<span class="st"> </span>k <span class="op">+</span><span class="st"> </span><span class="dv">1</span>
    wait &lt;-<span class="st"> </span><span class="kw">rexp</span>(<span class="dv">1</span>, lambda)
  }
  
  <span class="co"># return tabular data</span>
  <span class="kw">tibble</span>(
    <span class="dt">t =</span> t,
    <span class="dt">k =</span> k
  )
}

s &lt;-<span class="st"> </span><span class="kw">sample_conditional</span>(<span class="dv">300</span>, <span class="dv">200</span>, <span class="dv">1</span>) </code></pre></div>
<table class="table table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Example output from sample_conditional
</caption>
<thead>
<tr>
<th style="text-align:right;">
t
</th>
<th style="text-align:right;">
k
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
198.2929
</td>
<td style="text-align:right;">
169
</td>
</tr>
</tbody>
</table>
<p>In the above example, even though the observation time is <span class="math inline">\(T = 300\)</span>, the time <span class="math inline">\(t\)</span> till last purchase will always be below the lifetime <span class="math inline">\(\tau = 200\)</span>. With a purchase rate of 1 per unit time, we expect around <span class="math inline">\(k = 200\)</span> purchases.</p>
<h2 id="model">Model</h2>
<p>We’ll use the same likelihood as before, which says that the probability of customer <span class="math inline">\(i\)</span>’s data given their parameters is</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P(k, t, T \mid \mu_i, \lambda_i)
  &amp;=
  \frac{\lambda_i^k}{\lambda_i + \mu_i}
  \left( \mu_i e^{-t(\lambda_i + \mu_i)} + \lambda_i e^{-T(\lambda_i + \mu_i)} \right)
  \\
  &amp;\propto
  p \dpoisson(k \mid t\lambda_i)S(t \mid \mu_i) 
  \\
  &amp;\hphantom{\propto}
  + (1 - p) \dpoisson(k \mid t\lambda_i)\dpoisson(0 \mid (T-t)\lambda_i)S(T \mid \mu_i)
  ,
  \\
  p
  &amp;:=
  \frac{\mu_i}{\lambda_i + \mu_i}
  ,
\end{align}
\]</span></p>
<p>where <span class="math inline">\(S\)</span> is the exponential survival function.</p>
<p>To turn this into a Bayesian model, we’ll need priors for the parameters. The last time, we put simple gamma priors on the parameters <span class="math inline">\(\mu_i\)</span> and <span class="math inline">\(\lambda_i\)</span>. For example, we could choose <span class="math inline">\(\lambda_i \sim \dgamma(2, 28)\)</span> if we were to use the simple model from last time (similarly for <span class="math inline">\(\mu_i\)</span>). This time we’re going hierarchical. There are various ways to make this hierarchical. Let’s look at two of them.</p>
<p><a href="./models/rf.stan">One method</a> arises directly from the difficulty of specifying the gamma-prior parameters. It involves just turning those parameters into random variables to be simultaneously estimated along with <span class="math inline">\(\mu_i\)</span> and <span class="math inline">\(\lambda_i\)</span>. For example, we say <span class="math inline">\(\lambda_i \sim \dgamma(\alpha, \beta)\)</span>, where <span class="math inline">\(\alpha_i \sim \dgamma(\alpha_\alpha, \beta_\alpha)\)</span> and <span class="math inline">\(\beta_i \sim \dgamma(\alpha_\beta, \beta_\beta)\)</span> (and similarly for <span class="math inline">\(\mu_i\)</span>). We eventually want to incorporate covariates, which is difficult with this parameterisation, so let’s move onto a different idea.</p>
<p>Another solution is to use log-normal priors. This means setting</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \lambda_i 
  &amp;:= 
  \exp(\alpha_i)
  \\
  \alpha_i
  &amp;\sim
  \dnormal(\beta, \sigma)
  \\
  \beta
  &amp;\sim
  \dnormal(m, s_m)
  \\
  \sigma
  &amp;\sim
  \dnormal_+(0, s)
,
\end{align}
\]</span></p>
<p>where <span class="math inline">\(m\)</span>, <span class="math inline">\(s_m\)</span>, and <span class="math inline">\(s\)</span> are constants specified by the user (and similarly for <span class="math inline">\(\mu_i\)</span>). This implies</p>
<ul>
<li>there is an overall mean value <span class="math inline">\(e^\beta\)</span>,</li>
<li>the customer-level effects <span class="math inline">\(\alpha_i\)</span> are deviations from the overall mean, and</li>
<li>the extent of these deviations is controlled by the magnitude of <span class="math inline">\(\sigma\)</span>.</li>
</ul>
<p>With <span class="math inline">\(\sigma \approx 0\)</span>, there can be very little deviation from the mean, so most customers would be the same. On the other hand, large values of <span class="math inline">\(\sigma\)</span> allow for customers to be (almost) completely unrelated to each other. This means that <span class="math inline">\(\sigma\)</span> is helping us to regularise the model.</p>
<p>The above parameterisation is called “centred”, which basically means the prior for <span class="math inline">\(\alpha_i\)</span> is expressed in terms of other parameters (<span class="math inline">\(\beta\)</span>, <span class="math inline">\(\sigma\)</span>). This can be rewritten as a “non-centred” parameterisation as</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \lambda_i 
  &amp;:= 
  \exp(\beta + \sigma \alpha_i)
  \\
  \alpha_i
  &amp;\sim
  \dnormal(0, 1)
  \\
  \beta
  &amp;\sim
  \dnormal(m, s_m)
  \\
  \sigma
  &amp;\sim
  \dnormal_+(0, s)
.
\end{align}
\]</span></p>
<p>Notice the priors now contain no references to any other parameters. This is equivalent to the centred parameterisation because <span class="math inline">\(\beta + \sigma \alpha_i \sim \dnormal(\beta, \sigma)\)</span>. The non-centred parameterisation is interesting because it is known to increase the sampling efficiency of HMC-based samplers (such as Stan’s) in some cases.</p>
<h2 id="centred-stan-implementation">Centred Stan implementation</h2>
<p>Here is a <a href="./models/rf.stan">centred stan implementation</a> of our log-normal hierarchical model.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">centred &lt;-<span class="st"> </span>here<span class="op">::</span><span class="kw">here</span>(<span class="st">&#39;models/rf_centred.stan&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">stan_model</span>()</code></pre></div>
<p>Note that we have introduced the <code>prior_only</code> flag. When we specify that we want <code>prior_only</code>, then stan will not consider the likelihood and will instead just draw from the priors. This allows us to make prior-predictive simulations. We’ll generate a dataset using the prior-predictive distribution, then fit our model to that dataset. The least we can expect from a model is that it fits well to data drawn from its prior distribution.</p>
<h3 id="simulate-the-dataset">Simulate the dataset</h3>
<p>To simulate datasets we’ll use hyperpriors that roughly correspond to the priors from the previous post. In particular, the expected lifetime is around 31 days, and the expected purchase rate around once per fortnight.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">data_hyperpriors &lt;-<span class="st"> </span><span class="kw">list</span>(
  <span class="dt">log_life_mean_mu =</span> <span class="kw">log</span>(<span class="dv">31</span>),
  <span class="dt">log_life_mean_sigma =</span> <span class="fl">0.7</span>,
  <span class="dt">log_life_scale_sigma =</span> <span class="fl">0.8</span>,

  <span class="dt">log_lambda_mean_mu =</span> <span class="kw">log</span>(<span class="dv">1</span> <span class="op">/</span><span class="st"> </span><span class="dv">14</span>),
  <span class="dt">log_lambda_mean_sigma =</span> <span class="fl">0.3</span>,
  <span class="dt">log_lambda_scale_sigma =</span> <span class="fl">0.5</span>
)

data_prior &lt;-<span class="st"> </span>customers <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">t =</span> <span class="dv">0</span>, <span class="dt">k =</span> <span class="dv">0</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span>tidybayes<span class="op">::</span><span class="kw">compose_data</span>(data_hyperpriors, <span class="dt">prior_only =</span> <span class="dv">1</span>)

data_prior <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">str</span>()</code></pre></div>
<pre><code>List of 14
 $ id                    : int [1:1000(1d)] 1 2 3 4 5 6 7 8 9 10 ...
 $ end                   : num [1:1000(1d)] 730 730 730 730 730 730 730 730 730 730 ...
 $ start                 : num [1:1000(1d)] 328 707 408 342 666 ...
 $ T                     : num [1:1000(1d)] 401.6 22.6 322.2 388.5 64.5 ...
 $ t                     : num [1:1000(1d)] 0 0 0 0 0 0 0 0 0 0 ...
 $ k                     : num [1:1000(1d)] 0 0 0 0 0 0 0 0 0 0 ...
 $ n                     : int 1000
 $ log_life_mean_mu      : num 3.43
 $ log_life_mean_sigma   : num 0.7
 $ log_life_scale_sigma  : num 0.8
 $ log_lambda_mean_mu    : num -2.64
 $ log_lambda_mean_sigma : num 0.3
 $ log_lambda_scale_sigma: num 0.5
 $ prior_only            : num 1</code></pre>
<p>Let’s simulate 8 possible datasets from our priors. Notice how the centres and spreads of the datasets can vary.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">centred_prior &lt;-<span class="st"> </span>centred <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">fit</span>( <span class="co"># a wrapper around rstan::sampling to allow caching</span>
    <span class="dt">file =</span> here<span class="op">::</span><span class="kw">here</span>(<span class="st">&#39;models/rf_centred_prior.rds&#39;</span>), <span class="co"># cache</span>
    <span class="dt">data =</span> data_prior,
    <span class="dt">pars =</span> <span class="kw">c</span>(<span class="st">&#39;customer&#39;</span>), <span class="co"># ignore this parameter</span>
    <span class="dt">include =</span> <span class="ot">FALSE</span>,
    <span class="dt">chains =</span> <span class="dv">8</span>,
    <span class="dt">cores =</span> <span class="dv">4</span>,
    <span class="dt">warmup =</span> <span class="dv">1000</span>, <span class="co"># not sure why this needs to be so high</span>
    <span class="dt">iter =</span> <span class="dv">1001</span>, <span class="co"># one more than warmup because we just want one dataset per chain</span>
    <span class="dt">seed =</span> <span class="dv">3901</span> <span class="co"># for reproducibility</span>
  ) 

centred_prior_draws &lt;-<span class="st"> </span>centred_prior <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">get_draws</span>( <span class="co"># rstan::extract but also with energy</span>
    <span class="dt">pars =</span> <span class="kw">c</span>(
    <span class="st">&#39;lp__&#39;</span>, <span class="st">&#39;energy__&#39;</span>,
    <span class="st">&#39;theta&#39;</span>,
    <span class="st">&#39;log_centres&#39;</span>,
    <span class="st">&#39;scales&#39;</span>
    )
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">name_parameters</span>() <span class="co"># add customer id, and idx = 1 (mu) or 2 (lambda)</span></code></pre></div>
<figure>
<img src="recency_frequency_files/figure-markdown/prior_predictive_distributions-1.png" alt="Some prior-predictive draws." /><figcaption>Some prior-predictive draws.</figcaption>
</figure>
<p>Here are the exact hyperparameters used.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">hyper &lt;-<span class="st"> </span>centred_prior_draws <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(<span class="kw">str_detect</span>(parameter, <span class="st">&quot;^log_|scales&quot;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">select</span>(chain, parameter, value) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">spread</span>(parameter, value) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Hyperparameters of the prior-predictive draws.
</caption>
<thead>
<tr>
<th style="text-align:right;">
chain
</th>
<th style="text-align:right;">
log_centres[1]
</th>
<th style="text-align:right;">
log_centres[2]
</th>
<th style="text-align:right;">
scales[1]
</th>
<th style="text-align:right;">
scales[2]
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
3.643546
</td>
<td style="text-align:right;">
-2.057017
</td>
<td style="text-align:right;">
1.0866138
</td>
<td style="text-align:right;">
1.0874820
</td>
</tr>
<tr>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
4.586349
</td>
<td style="text-align:right;">
-2.231530
</td>
<td style="text-align:right;">
1.2064439
</td>
<td style="text-align:right;">
0.2725037
</td>
</tr>
<tr>
<td style="text-align:right;">
3
</td>
<td style="text-align:right;">
2.673924
</td>
<td style="text-align:right;">
-2.475513
</td>
<td style="text-align:right;">
0.8847336
</td>
<td style="text-align:right;">
0.9429385
</td>
</tr>
<tr>
<td style="text-align:right;">
4
</td>
<td style="text-align:right;">
3.490525
</td>
<td style="text-align:right;">
-2.557564
</td>
<td style="text-align:right;">
0.7708666
</td>
<td style="text-align:right;">
1.0124164
</td>
</tr>
<tr>
<td style="text-align:right;">
5
</td>
<td style="text-align:right;">
3.422691
</td>
<td style="text-align:right;">
-2.877842
</td>
<td style="text-align:right;">
1.3232360
</td>
<td style="text-align:right;">
0.2920695
</td>
</tr>
<tr>
<td style="text-align:right;">
6
</td>
<td style="text-align:right;">
4.205884
</td>
<td style="text-align:right;">
-3.196397
</td>
<td style="text-align:right;">
1.9217956
</td>
<td style="text-align:right;">
0.5307348
</td>
</tr>
<tr>
<td style="text-align:right;">
7
</td>
<td style="text-align:right;">
3.381881
</td>
<td style="text-align:right;">
-2.995128
</td>
<td style="text-align:right;">
1.0299251
</td>
<td style="text-align:right;">
0.7266123
</td>
</tr>
<tr>
<td style="text-align:right;">
8
</td>
<td style="text-align:right;">
3.046531
</td>
<td style="text-align:right;">
-2.328561
</td>
<td style="text-align:right;">
1.3993460
</td>
<td style="text-align:right;">
0.4751674
</td>
</tr>
</tbody>
</table>
<p>We’ll add the prior predictive parameter draws from chain 1 to our customers dataset.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">set.seed</span>(<span class="dv">33194</span>)

df &lt;-<span class="st"> </span>centred_prior_draws <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(chain <span class="op">==</span><span class="st"> </span><span class="dv">1</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(name <span class="op">==</span><span class="st"> &#39;theta&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">transmute</span>(
    <span class="dt">id =</span> id <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">as.integer</span>(), 
    <span class="dt">parameter =</span> <span class="kw">if_else</span>(idx <span class="op">==</span><span class="st"> &#39;1&#39;</span>, <span class="st">&#39;mu&#39;</span>, <span class="st">&#39;lambda&#39;</span>),
    value
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">spread</span>(parameter, value) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">tau =</span> <span class="kw">rexp</span>(<span class="kw">n</span>(), mu)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(customers, <span class="dt">by =</span> <span class="st">&#39;id&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(id) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_map</span>(<span class="op">~</span><span class="kw">sample_conditional</span>(.<span class="op">$</span>T, .<span class="op">$</span>tau, .<span class="op">$</span>lambda) <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">bind_cols</span>(.x))

data_df &lt;-<span class="st"> </span>data_hyperpriors <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span>tidybayes<span class="op">::</span><span class="kw">compose_data</span>(df, <span class="dt">prior_only =</span> <span class="dv">0</span>)</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Sample of customers and their properties
</caption>
<thead>
<tr>
<th style="text-align:right;">
id
</th>
<th style="text-align:right;">
t
</th>
<th style="text-align:right;">
k
</th>
<th style="text-align:right;">
lambda
</th>
<th style="text-align:right;">
mu
</th>
<th style="text-align:right;">
tau
</th>
<th style="text-align:right;">
end
</th>
<th style="text-align:right;">
start
</th>
<th style="text-align:right;">
T
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
44.453109
</td>
<td style="text-align:right;">
44
</td>
<td style="text-align:right;">
0.8508277
</td>
<td style="text-align:right;">
0.0383954
</td>
<td style="text-align:right;">
44.669086
</td>
<td style="text-align:right;">
730
</td>
<td style="text-align:right;">
328.4312
</td>
<td style="text-align:right;">
401.56876
</td>
</tr>
<tr>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
21.237790
</td>
<td style="text-align:right;">
5
</td>
<td style="text-align:right;">
0.2202757
</td>
<td style="text-align:right;">
0.0091300
</td>
<td style="text-align:right;">
263.541504
</td>
<td style="text-align:right;">
730
</td>
<td style="text-align:right;">
707.3906
</td>
<td style="text-align:right;">
22.60937
</td>
</tr>
<tr>
<td style="text-align:right;">
3
</td>
<td style="text-align:right;">
0.000000
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.0285432
</td>
<td style="text-align:right;">
0.0583523
</td>
<td style="text-align:right;">
8.405014
</td>
<td style="text-align:right;">
730
</td>
<td style="text-align:right;">
407.8144
</td>
<td style="text-align:right;">
322.18558
</td>
</tr>
<tr>
<td style="text-align:right;">
4
</td>
<td style="text-align:right;">
61.946272
</td>
<td style="text-align:right;">
7
</td>
<td style="text-align:right;">
0.0970620
</td>
<td style="text-align:right;">
0.0424386
</td>
<td style="text-align:right;">
71.617849
</td>
<td style="text-align:right;">
730
</td>
<td style="text-align:right;">
341.5465
</td>
<td style="text-align:right;">
388.45349
</td>
</tr>
<tr>
<td style="text-align:right;">
5
</td>
<td style="text-align:right;">
8.273831
</td>
<td style="text-align:right;">
3
</td>
<td style="text-align:right;">
0.1732173
</td>
<td style="text-align:right;">
0.0608967
</td>
<td style="text-align:right;">
8.747799
</td>
<td style="text-align:right;">
730
</td>
<td style="text-align:right;">
665.5210
</td>
<td style="text-align:right;">
64.47898
</td>
</tr>
<tr>
<td style="text-align:right;">
6
</td>
<td style="text-align:right;">
107.182661
</td>
<td style="text-align:right;">
19
</td>
<td style="text-align:right;">
0.1224131
</td>
<td style="text-align:right;">
0.0159025
</td>
<td style="text-align:right;">
113.792604
</td>
<td style="text-align:right;">
730
</td>
<td style="text-align:right;">
388.0271
</td>
<td style="text-align:right;">
341.97287
</td>
</tr>
</tbody>
</table>
<h3 id="fit-the-model-to-simulations">Fit the model to simulations</h3>
<p>Now we can fit the model to the prior-predictive data <code>df</code>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">centred_fit &lt;-<span class="st"> </span>centred <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">fit</span>( <span class="co"># like rstan::sampling but with file-caching as in brms</span>
    <span class="dt">file =</span> here<span class="op">::</span><span class="kw">here</span>(<span class="st">&#39;models/rf_centred_fit.rds&#39;</span>), <span class="co"># cache</span>
    <span class="dt">data =</span> data_df,
    <span class="dt">chains =</span> <span class="dv">4</span>,
    <span class="dt">cores =</span> <span class="dv">4</span>,
    <span class="dt">warmup =</span> <span class="dv">2000</span>,
    <span class="dt">iter =</span> <span class="dv">3000</span>,
    <span class="dt">control =</span> <span class="kw">list</span>(<span class="dt">max_treedepth =</span> <span class="dv">12</span>),
    <span class="dt">seed =</span> <span class="dv">24207</span>,
    <span class="dt">pars =</span> <span class="kw">c</span>(<span class="st">&#39;customer&#39;</span>),
    <span class="dt">include =</span> <span class="ot">FALSE</span>
  ) 

centred_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">check_hmc_diagnostics</span>()</code></pre></div>
<pre><code>Divergences:

0 of 4000 iterations ended with a divergence.


Tree depth:

0 of 4000 iterations saturated the maximum tree depth of 12.


Energy:

E-BFMI indicated no pathological behavior.</code></pre>
<p>The HMC diagnostics pass. However, in some of the runs not shown here, there were pretty severe problems with the E-BFMI diagnostic (~0.01) and I’ve yet to figure out exactly which kinds of situations cause these energy problems. Let’s check out the pairwise posterior densities of energy with the hyperparameters.</p>
<figure>
<img src="recency_frequency_files/figure-markdown/centred_pairwise-1.png" alt="Pairwise posterior densities of the centred model" /><figcaption>Pairwise posterior densities of the centred model</figcaption>
</figure>
<p>The scale parameter for the expected lifetime (<code>scales[1]</code>) is correlated with energy, which is associated with the energy problems described above. I’m not sure how much of a problem this poses, so let’s check out some more diagnostics.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">neff &lt;-<span class="st"> </span>centred_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">neff_ratio</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(
    <span class="dt">ratio =</span> .,
    <span class="dt">parameter =</span> <span class="kw">names</span>(.)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(ratio <span class="op">&lt;</span><span class="st"> </span><span class="fl">0.5</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">arrange</span>(ratio) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">head</span>(<span class="dv">20</span>) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Parameters with the lowest effective sample size.
</caption>
<thead>
<tr>
<th style="text-align:right;">
ratio
</th>
<th style="text-align:left;">
parameter
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.0937772
</td>
<td style="text-align:left;">
scales[1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.1195873
</td>
<td style="text-align:left;">
lp__
</td>
</tr>
<tr>
<td style="text-align:right;">
0.2592819
</td>
<td style="text-align:left;">
log_centres[1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.2748369
</td>
<td style="text-align:left;">
scales[2]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.3228056
</td>
<td style="text-align:left;">
log_centres[2]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4340080
</td>
<td style="text-align:left;">
theta[574,2]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4381685
</td>
<td style="text-align:left;">
theta[169,1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4800795
</td>
<td style="text-align:left;">
theta[38,1]
</td>
</tr>
</tbody>
</table>
<p>Both the <code>lp__</code> and <code>scales[1]</code> parameters have low effective sample sizes. The rhat values seem fine though.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">centred_rhat &lt;-<span class="st"> </span>centred_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">rhat</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(
    <span class="dt">rhat =</span> .,
    <span class="dt">parameter =</span> <span class="kw">names</span>(.)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(
    <span class="dt">min_rhat =</span> <span class="kw">min</span>(rhat, <span class="dt">na.rm =</span> <span class="ot">TRUE</span>),
    <span class="dt">max_rhat =</span> <span class="kw">max</span>(rhat, <span class="dt">na.rm =</span> <span class="ot">TRUE</span>)
  ) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Most extreme rhat values
</caption>
<thead>
<tr>
<th style="text-align:right;">
min_rhat
</th>
<th style="text-align:right;">
max_rhat
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.9990247
</td>
<td style="text-align:right;">
1.005071
</td>
</tr>
</tbody>
</table>
<p>Let’s now compare the 90% posterior intervals with the true values. Ideally close to 90% of the 90% posterior intervals capture their true value.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">centred_cis &lt;-<span class="st"> </span>centred_draws <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(parameter) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(
    <span class="dt">lo =</span> <span class="kw">quantile</span>(value, <span class="fl">0.05</span>),
    <span class="dt">point =</span> <span class="kw">quantile</span>(value, <span class="fl">0.50</span>),
    <span class="dt">hi =</span> <span class="kw">quantile</span>(value, <span class="fl">0.95</span>)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(<span class="op">!</span><span class="kw">str_detect</span>(parameter, <span class="st">&#39;__&#39;</span>)) <span class="co"># exclude diagostic parameters</span></code></pre></div>
<p>The table below shows we managed to recover three of the hyperparameters. The <code>scales[2]</code> parameter was estimated slightly too high.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">calibration_hyper &lt;-<span class="st"> </span>hyper <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(chain <span class="op">==</span><span class="st"> </span><span class="dv">1</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(parameter, value, <span class="op">-</span>chain) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(centred_cis, <span class="dt">by =</span> <span class="st">&#39;parameter&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">hit =</span> lo <span class="op">&lt;=</span><span class="st"> </span>value <span class="op">&amp;</span><span class="st"> </span>value <span class="op">&lt;=</span><span class="st"> </span>hi)</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
The true hyperparameters and their 90% posterior intervals.
</caption>
<thead>
<tr>
<th style="text-align:left;">
parameter
</th>
<th style="text-align:right;">
value
</th>
<th style="text-align:right;">
lo
</th>
<th style="text-align:right;">
point
</th>
<th style="text-align:right;">
hi
</th>
<th style="text-align:left;">
hit
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
log_centres[1]
</td>
<td style="text-align:right;">
3.643546
</td>
<td style="text-align:right;">
3.6280113
</td>
<td style="text-align:right;">
3.733964
</td>
<td style="text-align:right;">
3.831287
</td>
<td style="text-align:left;">
TRUE
</td>
</tr>
<tr>
<td style="text-align:left;">
log_centres[2]
</td>
<td style="text-align:right;">
-2.057017
</td>
<td style="text-align:right;">
-2.1786705
</td>
<td style="text-align:right;">
-2.090098
</td>
<td style="text-align:right;">
-2.008663
</td>
<td style="text-align:left;">
TRUE
</td>
</tr>
<tr>
<td style="text-align:left;">
scales[1]
</td>
<td style="text-align:right;">
1.086614
</td>
<td style="text-align:right;">
0.9988373
</td>
<td style="text-align:right;">
1.119258
</td>
<td style="text-align:right;">
1.242780
</td>
<td style="text-align:left;">
TRUE
</td>
</tr>
<tr>
<td style="text-align:left;">
scales[2]
</td>
<td style="text-align:right;">
1.087482
</td>
<td style="text-align:right;">
1.0938685
</td>
<td style="text-align:right;">
1.160415
</td>
<td style="text-align:right;">
1.232225
</td>
<td style="text-align:left;">
FALSE
</td>
</tr>
</tbody>
</table>
<p>We get fairly close to 90% of the customer-level parameters.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">true_values &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">select</span>(id, mu, lambda) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(parameter, value, <span class="op">-</span>id) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">idx =</span> <span class="kw">if_else</span>(parameter <span class="op">==</span><span class="st"> &#39;mu&#39;</span>, <span class="dv">1</span>, <span class="dv">2</span>),
    <span class="dt">parameter =</span> <span class="kw">str_glue</span>(<span class="st">&quot;theta[{id},{idx}]&quot;</span>)
  )

centred_calibration &lt;-<span class="st"> </span>centred_cis <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(true_values, <span class="dt">by =</span> <span class="st">&#39;parameter&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">ungroup</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(lo <span class="op">&lt;=</span><span class="st"> </span>value <span class="op">&amp;</span><span class="st"> </span>value <span class="op">&lt;=</span><span class="st"> </span>hi)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">percent</span>()

centred_calibration</code></pre></div>
<pre><code>[1] &quot;91.1%&quot;</code></pre>
<p>This is slightly higher than the ideal value of 90%.</p>
<h2 id="non-centred-stan-implementation">Non-centred Stan implementation</h2>
<p>Here is a <a href="./models/rf_noncentred.stan">non-centred stan implementation</a> of our log-normal hierarchical model. The important difference is in the expression for <span class="math inline">\(\theta\)</span> and in the prior for <span class="math inline">\(\text{customer}\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncentred &lt;-<span class="st"> </span>here<span class="op">::</span><span class="kw">here</span>(<span class="st">&#39;models/rf_noncentred.stan&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">stan_model</span>()</code></pre></div>
<p>Since the non-centred and centred models are equivalent, we can also consider <code>df</code> as a draw from the non-centred prior predictive distribution.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncentred_fit &lt;-<span class="st"> </span>noncentred <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">fit</span>( <span class="co"># like rstan::sampling but with file-caching as in brms</span>
    <span class="dt">file =</span> here<span class="op">::</span><span class="kw">here</span>(<span class="st">&#39;models/rf_noncentred_fit.rds&#39;</span>), <span class="co"># cache</span>
    <span class="dt">data =</span> data_df,
    <span class="dt">chains =</span> <span class="dv">4</span>,
    <span class="dt">cores =</span> <span class="dv">4</span>,
    <span class="dt">warmup =</span> <span class="dv">2000</span>,
    <span class="dt">iter =</span> <span class="dv">3000</span>,
    <span class="dt">control =</span> <span class="kw">list</span>(<span class="dt">max_treedepth =</span> <span class="dv">12</span>),
    <span class="dt">seed =</span> <span class="dv">1259</span>,
    <span class="dt">pars =</span> <span class="kw">c</span>(<span class="st">&#39;customer&#39;</span>),
    <span class="dt">include =</span> <span class="ot">FALSE</span>
  ) 

noncentred_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">check_hmc_diagnostics</span>()</code></pre></div>
<pre><code>Divergences:

0 of 4000 iterations ended with a divergence.


Tree depth:

0 of 4000 iterations saturated the maximum tree depth of 12.


Energy:

E-BFMI indicated no pathological behavior.</code></pre>
<p>Again, the HMC diagnostics indicate no problems. Let’s check the pairwise densities anyway.</p>
<figure>
<img src="recency_frequency_files/figure-markdown/noncentred_pairwise-1.png" alt="Pairwise posterior densities of the non-centred model" /><figcaption>Pairwise posterior densities of the non-centred model</figcaption>
</figure>
<p>The correlation between <code>scales[1]</code> and <code>energy__</code> is smaller with the non-centred parameterisation. This is reflected in the higher effective sample size for <code>scales[1]</code> below. Unfortunately, the effective sample size for the purchase rate hyperpriors has gone down.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">neff &lt;-<span class="st"> </span>noncentred_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">neff_ratio</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(
    <span class="dt">ratio =</span> .,
    <span class="dt">parameter =</span> <span class="kw">names</span>(.)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(ratio <span class="op">&lt;</span><span class="st"> </span><span class="fl">0.5</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">arrange</span>(ratio) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">head</span>(<span class="dv">20</span>) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Parameters with the lowest effective sample size.
</caption>
<thead>
<tr>
<th style="text-align:right;">
ratio
</th>
<th style="text-align:left;">
parameter
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.0631821
</td>
<td style="text-align:left;">
log_centres[2]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.0681729
</td>
<td style="text-align:left;">
scales[2]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.1579867
</td>
<td style="text-align:left;">
lp__
</td>
</tr>
<tr>
<td style="text-align:right;">
0.1776186
</td>
<td style="text-align:left;">
scales[1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.2217369
</td>
<td style="text-align:left;">
log_centres[1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.3910369
</td>
<td style="text-align:left;">
theta[830,1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4767405
</td>
<td style="text-align:left;">
theta[639,1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4792693
</td>
<td style="text-align:left;">
theta[250,2]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4847856
</td>
<td style="text-align:left;">
theta[41,1]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4978518
</td>
<td style="text-align:left;">
theta[231,1]
</td>
</tr>
</tbody>
</table>
<p>Again, the rhat values seem fine.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncentred_rhat &lt;-<span class="st"> </span>noncentred_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">rhat</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(
    <span class="dt">rhat =</span> .,
    <span class="dt">parameter =</span> <span class="kw">names</span>(.)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(
    <span class="dt">min_rhat =</span> <span class="kw">min</span>(rhat, <span class="dt">na.rm =</span> <span class="ot">TRUE</span>),
    <span class="dt">max_rhat =</span> <span class="kw">max</span>(rhat, <span class="dt">na.rm =</span> <span class="ot">TRUE</span>)
  ) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Most extreme rhat values
</caption>
<thead>
<tr>
<th style="text-align:right;">
min_rhat
</th>
<th style="text-align:right;">
max_rhat
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.9990501
</td>
<td style="text-align:right;">
1.013372
</td>
</tr>
</tbody>
</table>
<p>Let’s check how many of the 90% posterior intervals contain the true value.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncentred_cis &lt;-<span class="st"> </span>noncentred_draws <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(parameter) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(
    <span class="dt">lo =</span> <span class="kw">quantile</span>(value, <span class="fl">0.05</span>),
    <span class="dt">point =</span> <span class="kw">quantile</span>(value, <span class="fl">0.50</span>),
    <span class="dt">hi =</span> <span class="kw">quantile</span>(value, <span class="fl">0.95</span>)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(<span class="op">!</span><span class="kw">str_detect</span>(parameter, <span class="st">&#39;__&#39;</span>)) </code></pre></div>
<p>The hyperparameter estimates are much the same as with the centred parameterisation.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncentred_calibration_hyper &lt;-<span class="st"> </span>hyper <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(chain <span class="op">==</span><span class="st"> </span><span class="dv">1</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(parameter, value, <span class="op">-</span>chain) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(noncentred_cis, <span class="dt">by =</span> <span class="st">&#39;parameter&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">hit =</span> lo <span class="op">&lt;=</span><span class="st"> </span>value <span class="op">&amp;</span><span class="st"> </span>value <span class="op">&lt;=</span><span class="st"> </span>hi)</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
The true hyperparameters and their 90% posterior intervals.
</caption>
<thead>
<tr>
<th style="text-align:left;">
parameter
</th>
<th style="text-align:right;">
value
</th>
<th style="text-align:right;">
lo
</th>
<th style="text-align:right;">
point
</th>
<th style="text-align:right;">
hi
</th>
<th style="text-align:left;">
hit
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
log_centres[1]
</td>
<td style="text-align:right;">
3.643546
</td>
<td style="text-align:right;">
3.6325159
</td>
<td style="text-align:right;">
3.735363
</td>
<td style="text-align:right;">
3.838160
</td>
<td style="text-align:left;">
TRUE
</td>
</tr>
<tr>
<td style="text-align:left;">
log_centres[2]
</td>
<td style="text-align:right;">
-2.057017
</td>
<td style="text-align:right;">
-2.1770703
</td>
<td style="text-align:right;">
-2.092537
</td>
<td style="text-align:right;">
-2.014462
</td>
<td style="text-align:left;">
TRUE
</td>
</tr>
<tr>
<td style="text-align:left;">
scales[1]
</td>
<td style="text-align:right;">
1.086614
</td>
<td style="text-align:right;">
0.9970698
</td>
<td style="text-align:right;">
1.109297
</td>
<td style="text-align:right;">
1.235166
</td>
<td style="text-align:left;">
TRUE
</td>
</tr>
<tr>
<td style="text-align:left;">
scales[2]
</td>
<td style="text-align:right;">
1.087482
</td>
<td style="text-align:right;">
1.0963503
</td>
<td style="text-align:right;">
1.159626
</td>
<td style="text-align:right;">
1.234190
</td>
<td style="text-align:left;">
FALSE
</td>
</tr>
</tbody>
</table>
<p>About 91% of customer-level posterior intervals contain the true value.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncentred_calibration &lt;-<span class="st"> </span>noncentred_cis <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(true_values, <span class="dt">by =</span> <span class="st">&#39;parameter&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(lo <span class="op">&lt;=</span><span class="st"> </span>value <span class="op">&amp;</span><span class="st"> </span>value <span class="op">&lt;=</span><span class="st"> </span>hi)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">percent</span>()

noncentred_calibration</code></pre></div>
<pre><code>[1] &quot;91.0%&quot;</code></pre>
<h2 id="discussion">Discussion</h2>
<p>Both centred and non-centred models performed reasonably well on the dataset considered. The non-centred model showed slightly less correlation between <code>scales</code> and <code>energy__</code>, suggesting it might be the better one to tackle the low E-BFMI problems. Since we only checked the fit on one prior-predictive draw, it would be a good idea to check out the fit to more draws. Some casual attempts of mine (not shown here) suggest there are situations that cause severe E-BFMI problems. Identifying these situations would be an interesting next step. It would also be great to see how it performs on some of the benchmarked datasets mentioned in the <a href="https://github.com/mplatzer/BTYDplus">BTYDPlus</a> package.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>BDA3 Chapter 1 Exercise 9</title>
    <link href="http://www.briancallander.com/posts/bda3/chapter_01_exercise_09.html" />
    <id>http://www.briancallander.com/posts/bda3/chapter_01_exercise_09.html</id>
    <published>2019-04-13T00:00:00Z</published>
    <updated>2019-04-13T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">BDA3 Chapter 1 Exercise 9</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on 13 April, 2019  by Brian </br>
     Tags: <a href="/tags/bda%20chapter%201.html">bda chapter 1</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/simulation.html">simulation</a>, <a href="/tags/poisson%20process.html">poisson process</a> </br>
     Category: <a href="/categories/bda3.html">bda3</a> 
    </p>
  </div>
</div>

<p>Here’s my solution to exercise 9, chapter 1, of <a href="https://andrewgelman.com/">Gelman’s</a> <em>Bayesian Data Analysis</em> (BDA), 3rd edition. There are <a href="http://www.stat.columbia.edu/~gelman/book/solutions.pdf">solutions</a> to some of the exercises on the <a href="http://www.stat.columbia.edu/~gelman/book/">book’s webpage</a>.</p>
<!--more-->
<div style="display:none">
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbern}{Bernoulli} \DeclareMathOperator{\dpois}{Poisson} \DeclareMathOperator{\dnorm}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexponential}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvgamma}{InvGamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<p>Suppose there 3 doctors, who open their practice at 09:00 and stop accepting patients at 16:00. If customers arrive in exponentially distributed intervals with mean 10 minutes, and appointment duration is uniformly distributed between 5 and 10 minutes, we want to know:</p>
<ul>
<li>how many patients arrive per day?</li>
<li>how many patients have to wait for their appointment?</li>
<li>how long do patients have to wait?</li>
<li>when does the last patient leave the practice?</li>
</ul>
<p>We do this by simulation. The <code>arrivals</code> function will simulate the arrival times of the patients, in minutes after 09:00. In principle, we should simulate draws from the exponential distribution until the sum of all draws is above 420, the number of minutes the practice accepts patients. However, I couldn’t find any efficient way to run this in R. Instead we’ll draw so many variables such that is is highly unlikely that we have too few, then just filter out what we don’t need.</p>
<p>To calculate a suitably large number, note that the number of patients in one day is <span class="math inline">\(\dpois(\frac{1}{10} \cdot (16 - 9) \cdot 60)\)</span>-distributed. The 99.99999% percentile of this distribution is <code>qpois(0.9999999, (16 - 9) * 6) =</code> 80. We’ll err on the safe side and use <span class="math inline">\(n=100\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">arrivals &lt;-<span class="st"> </span><span class="cf">function</span>(λ, t, <span class="dt">n=</span><span class="dv">100</span>) {
  <span class="kw">rexp</span>(n, λ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">tibble</span>(
      <span class="dt">delay =</span> .,
      <span class="dt">time =</span> <span class="kw">cumsum</span>(delay)
    ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">filter</span>(time <span class="op">&lt;=</span><span class="st"> </span>t) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">pull</span>(time) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">return</span>()
}

λ &lt;-<span class="st"> </span><span class="dv">1</span> <span class="op">/</span><span class="st"> </span><span class="dv">10</span>
t &lt;-<span class="st"> </span>(<span class="dv">16</span> <span class="op">-</span><span class="st"> </span><span class="dv">9</span>) <span class="op">*</span><span class="st"> </span><span class="dv">60</span>

<span class="kw">arrivals</span>(λ, t)</code></pre></div>
<pre><code> [1]   4.854265   4.963889   6.651014   9.518990  17.415709  20.110178
 [7]  28.852188  34.862538  35.970215  44.205468  48.342152  52.934693
[13]  83.072579  86.746318 117.586517 122.811176 133.662687 142.016603
[19] 170.935913 190.999325 202.511439 204.915770 205.191951 208.422873
[25] 219.437526 225.162971 233.122550 235.351649 253.558658 254.097711
[31] 255.639118 256.270049 277.905899 291.055504 291.737173 294.688419
[37] 300.949679 302.681417 329.751112 335.998940 355.506712 361.162687
[43] 381.436543 388.767558 393.072689 393.088807 395.570811 401.669343
[49] 401.911643 408.650710 418.291196</code></pre>
<p>Given the patients that arrive in a day, we now need a function to simulate the appointments. Let’s assume the patients get seen in the order they arrive. As we cycle through the patients, we’ll keep track of</p>
<ul>
<li><code>n_waited</code>, the number of patients who have had to wait for their appointment so far;</li>
<li><code>time_waiting</code>, the sum of all waiting times of the patients so far; and</li>
<li><code>doctors</code>, the next time at which each doctor is free to see another patient.</li>
</ul>
<p>The <code>doctors</code> variable starts at <code>c(0, 0, 0)</code> because they are immediately availble to see patients. The doctor with the smallest availability time is the next doctor to see a patient. The start of the appointment is either the doctor’s availability time or the arrival time of the patient, whichever is greater. The end of the appointment is <span class="math inline">\(\duniform(5, 20)\)</span>-minutes after the start of the appointment. The doctor’s availability time is then set to the end of the appointment. Once all patients have been given an appointment, the closing time is the maximum of the doctors’ next availability times or the closing time <code>(16 - 9) * 60</code>, whichever is greater.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">process &lt;-<span class="st"> </span><span class="cf">function</span>(arrivals, <span class="dt">t=</span><span class="dv">0</span>) {
  
  n_waited &lt;-<span class="st"> </span><span class="dv">0</span>         <span class="co"># number of patients who have had to wait so far</span>
  time_waiting &lt;-<span class="st"> </span><span class="dv">0</span>     <span class="co"># total waiting time so far</span>
  doctors &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="dv">0</span>, <span class="dv">0</span>, <span class="dv">0</span>) <span class="co"># next time at which each doctor is free to see another patient</span>
  
  <span class="cf">for</span>(i <span class="cf">in</span> (<span class="dv">1</span><span class="op">:</span><span class="kw">length</span>(arrivals))) {
    wait &lt;-<span class="st"> </span><span class="kw">pmax</span>(<span class="kw">min</span>(doctors) <span class="op">-</span><span class="st"> </span>arrivals[i], <span class="dv">0</span>) <span class="co"># waiting time of patient i</span>
    time_waiting &lt;-<span class="st"> </span>time_waiting <span class="op">+</span><span class="st"> </span>wait
    n_waited &lt;-<span class="st"> </span>n_waited <span class="op">+</span><span class="st"> </span>(wait <span class="op">&gt;</span><span class="st"> </span><span class="dv">0</span>)
    appointment_start &lt;-<span class="st"> </span><span class="kw">max</span>(<span class="kw">c</span>(<span class="kw">min</span>(doctors), arrivals[i]))
    appointment_end &lt;-<span class="st"> </span>appointment_start <span class="op">+</span><span class="st"> </span><span class="kw">runif</span>(<span class="dv">1</span>, <span class="dv">5</span>, <span class="dv">20</span>)
    doctors[<span class="kw">which.min</span>(doctors)] &lt;-<span class="st"> </span>appointment_end
  }
  
  <span class="kw">list</span>(
    <span class="dt">n_patients =</span> <span class="kw">length</span>(arrivals),
    <span class="dt">n_waited =</span> n_waited,
    <span class="dt">time_waiting =</span> time_waiting,
    <span class="dt">time_waiting_per_patient =</span> time_waiting <span class="op">/</span><span class="st"> </span><span class="kw">length</span>(arrivals),
    <span class="dt">time_waiting_per_waiting_patient =</span> time_waiting <span class="op">/</span><span class="st"> </span>n_waited,
    <span class="dt">closing_time =</span> <span class="kw">pmax</span>(<span class="kw">max</span>(doctors), t)
  ) <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">return</span>()
    
}

<span class="kw">arrivals</span>(λ, t) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">process</span>(t)</code></pre></div>
<pre><code>$n_patients
[1] 39

$n_waited
[1] 0

$time_waiting
[1] 0

$time_waiting_per_patient
[1] 0

$time_waiting_per_waiting_patient
[1] NaN

$closing_time
[1] 426.9273</code></pre>
<p>To simulate the above many times, we’ll use the <code>replicate</code> function. For convenience, we’ll turn this into a <code>tibble</code>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">simulate &lt;-<span class="st"> </span><span class="cf">function</span>(iters, λ, t, <span class="dt">n=</span><span class="dv">100</span>) {
  iters <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">replicate</span>(<span class="kw">process</span>(<span class="kw">arrivals</span>(λ, t, n), t)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">t</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">as_tibble</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">mutate_all</span>(unlist)
}

sims &lt;-<span class="st"> </span><span class="kw">simulate</span>(<span class="dv">1000</span>, λ, t)</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
The first few simulations of a day at the practice.
</caption>
<thead>
<tr>
<th style="text-align:right;">
n_patients
</th>
<th style="text-align:right;">
n_waited
</th>
<th style="text-align:right;">
time_waiting
</th>
<th style="text-align:right;">
time_waiting_per_patient
</th>
<th style="text-align:right;">
time_waiting_per_waiting_patient
</th>
<th style="text-align:right;">
closing_time
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
45
</td>
<td style="text-align:right;">
8
</td>
<td style="text-align:right;">
10.493347
</td>
<td style="text-align:right;">
0.2331855
</td>
<td style="text-align:right;">
1.311668
</td>
<td style="text-align:right;">
421.2221
</td>
</tr>
<tr>
<td style="text-align:right;">
44
</td>
<td style="text-align:right;">
6
</td>
<td style="text-align:right;">
13.226377
</td>
<td style="text-align:right;">
0.3005995
</td>
<td style="text-align:right;">
2.204396
</td>
<td style="text-align:right;">
435.4524
</td>
</tr>
<tr>
<td style="text-align:right;">
29
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1.174172
</td>
<td style="text-align:right;">
0.0404887
</td>
<td style="text-align:right;">
1.174172
</td>
<td style="text-align:right;">
435.9763
</td>
</tr>
<tr>
<td style="text-align:right;">
31
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
9.413756
</td>
<td style="text-align:right;">
0.3036696
</td>
<td style="text-align:right;">
9.413756
</td>
<td style="text-align:right;">
440.1210
</td>
</tr>
<tr>
<td style="text-align:right;">
40
</td>
<td style="text-align:right;">
5
</td>
<td style="text-align:right;">
16.692607
</td>
<td style="text-align:right;">
0.4173152
</td>
<td style="text-align:right;">
3.338521
</td>
<td style="text-align:right;">
431.8950
</td>
</tr>
<tr>
<td style="text-align:right;">
37
</td>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
11.329963
</td>
<td style="text-align:right;">
0.3062152
</td>
<td style="text-align:right;">
5.664981
</td>
<td style="text-align:right;">
420.0000
</td>
</tr>
</tbody>
</table>
<p>Finally, we can calculate the 50% intervals by applying the <code>quantile</code> function to each summary.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sims_summary &lt;-<span class="st"> </span>sims <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(variable, value) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(variable) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(
    <span class="dt">q25 =</span> <span class="kw">quantile</span>(value, <span class="fl">0.25</span>, <span class="dt">na.rm=</span><span class="ot">TRUE</span>),
    <span class="dt">q50 =</span> <span class="kw">quantile</span>(value, <span class="fl">0.5</span>, <span class="dt">na.rm=</span><span class="ot">TRUE</span>),
    <span class="dt">q75 =</span> <span class="kw">quantile</span>(value, <span class="fl">0.75</span>, <span class="dt">na.rm=</span><span class="ot">TRUE</span>),
    <span class="dt">simulations =</span> <span class="kw">n</span>()
  )</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
The median and 50% interval for each summary statistic.
</caption>
<thead>
<tr>
<th style="text-align:left;">
variable
</th>
<th style="text-align:right;">
q25
</th>
<th style="text-align:right;">
q50
</th>
<th style="text-align:right;">
q75
</th>
<th style="text-align:right;">
simulations
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
closing_time
</td>
<td style="text-align:right;">
420.000000
</td>
<td style="text-align:right;">
424.9488049
</td>
<td style="text-align:right;">
430.7023807
</td>
<td style="text-align:right;">
1000
</td>
</tr>
<tr>
<td style="text-align:left;">
n_patients
</td>
<td style="text-align:right;">
38.000000
</td>
<td style="text-align:right;">
42.0000000
</td>
<td style="text-align:right;">
46.2500000
</td>
<td style="text-align:right;">
1000
</td>
</tr>
<tr>
<td style="text-align:left;">
n_waited
</td>
<td style="text-align:right;">
3.000000
</td>
<td style="text-align:right;">
5.0000000
</td>
<td style="text-align:right;">
9.0000000
</td>
<td style="text-align:right;">
1000
</td>
</tr>
<tr>
<td style="text-align:left;">
time_waiting
</td>
<td style="text-align:right;">
8.266744
</td>
<td style="text-align:right;">
19.3983242
</td>
<td style="text-align:right;">
38.9367142
</td>
<td style="text-align:right;">
1000
</td>
</tr>
<tr>
<td style="text-align:left;">
time_waiting_per_patient
</td>
<td style="text-align:right;">
0.212705
</td>
<td style="text-align:right;">
0.4685262
</td>
<td style="text-align:right;">
0.8622254
</td>
<td style="text-align:right;">
1000
</td>
</tr>
<tr>
<td style="text-align:left;">
time_waiting_per_waiting_patient
</td>
<td style="text-align:right;">
2.660497
</td>
<td style="text-align:right;">
3.8266619
</td>
<td style="text-align:right;">
5.1309744
</td>
<td style="text-align:right;">
1000
</td>
</tr>
</tbody>
</table>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>Pareto-NBD Customer Lifetime Value</title>
    <link href="http://www.briancallander.com/posts/customer_lifetime_value/pareto-nbd.html" />
    <id>http://www.briancallander.com/posts/customer_lifetime_value/pareto-nbd.html</id>
    <published>2019-04-06T00:00:00Z</published>
    <updated>2019-04-06T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">Pareto-NBD Customer Lifetime Value</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on  6 April, 2019  by Brian </br>
     Tags: <a href="/tags/customer%20lifetime%20value.html">customer lifetime value</a>, <a href="/tags/pareto-nbd.html">pareto-nbd</a>, <a href="/tags/smc.html">smc</a> </br>
     Category: <a href="/categories/customer_lifetime_value.html">customer_lifetime_value</a> 
    </p>
  </div>
</div>

<p>Suppose you have a bunch of customers who make repeat purchases - some more frequenty, some less. There are a few things you might like to know about these customers, such as</p>
<ul>
<li>which customers are still active (i.e. not yet churned) and likely to continue purchasing from you?; and</li>
<li>how many purchases can you expect from each customer?</li>
</ul>
<p>Modelling this directly is more difficult than it might seem at first. A customer that regularly makes purchases every day might be considered at risk of churning if they haven’t purchased anything in the past week, whereas a customer that regularly puchases once per month would not be considered at risk of churning. That is, churn and frequency of purchasing are closely related. The difficulty is that we don’t observe the moment of churn of any customer and have to model it probabilistically.</p>
<p>There are a number of established models for estimating this, the most well-known perhaps being the <a href="https://pubsonline.informs.org/doi/abs/10.1287/mnsc.33.1.1">SMC model</a> (a.k.a pareto-nbd model). There are already <a href="https://github.com/mplatzer/BTYDplus">some implementations</a> using maximum likelihood or Gibbs sampling. In this post, we’ll explain how the model works, make some prior predictive simulations, and fit a version implemented in <a href="https://mc-stan.org/">Stan</a>.</p>
<!--more-->
<div>
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbern}{Bernoulli} \DeclareMathOperator{\dpois}{Poisson} \DeclareMathOperator{\dnorm}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexp}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvgamma}{InvGamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<h2 id="data-generating-process">Data Generating Process</h2>
<h3 id="likelihood">Likelihood</h3>
<p>Let’s describe the model first by simulation. Suppose we have a company that is 2 years old and a total of 2000 customers, <span class="math inline">\(C\)</span>, that have made at least one purchase from us. We’ll assume a linear rate of customer acquisition, so that the first purchase date is simply a uniform random variable over the 2 years of the company existance. These assumptions are just to keep the example concrete, and are not so important for understanding the model.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">customers &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">id =</span> <span class="dv">1</span><span class="op">:</span><span class="dv">1000</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">end =</span> <span class="dv">2</span> <span class="op">*</span><span class="st"> </span><span class="dv">365</span>,
    <span class="dt">start =</span> <span class="kw">runif</span>(<span class="kw">n</span>(), <span class="dv">0</span>, end <span class="op">-</span><span class="st"> </span><span class="dv">1</span>),
    <span class="dt">T =</span> end <span class="op">-</span><span class="st"> </span>start
  )</code></pre></div>
<p>The <span class="math inline">\(T\)</span>-variable is the total observation time, counted from the date of first joining to the present day.</p>
<p>First the likelihood. Each customer <span class="math inline">\(c \in C\)</span> is assumed to have a certain lifetime, <span class="math inline">\(\tau_c\)</span>, starting on their join-date. During their lifetime, they will purchase at a constant rate, <span class="math inline">\(\lambda_c\)</span>, so that they will make <span class="math inline">\(k \sim \dpois(t\lambda_c)\)</span> purchases over a time-interval <span class="math inline">\(t\)</span>. Once their lifetime is over, they will stop purchasing. We only observe the customer for <span class="math inline">\(T_c\)</span> units of time, and this observation time can be either larger or smaller than the lifetime, <span class="math inline">\(\tau_c\)</span>. Since we don’t observe <span class="math inline">\(\tau_c\)</span> itself, we will assume it follows an exponential distribution, i.e. <span class="math inline">\(\tau_c \sim \dexp(\mu_c)\)</span>.</p>
<p>The following function generates possible observations given <span class="math inline">\(\mu\)</span> and <span class="math inline">\(\lambda\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sample_conditional &lt;-<span class="st"> </span><span class="cf">function</span>(mu, lambda, T) {
  
  <span class="co"># lifetime</span>
  tau &lt;-<span class="st"> </span><span class="kw">rexp</span>(<span class="dv">1</span>, mu)
  
  <span class="co"># start with 0 purchases</span>
  t &lt;-<span class="st"> </span><span class="dv">0</span>
  k &lt;-<span class="st"> </span><span class="dv">0</span>
  
  <span class="co"># simulate time till next purchase</span>
  wait &lt;-<span class="st"> </span><span class="kw">rexp</span>(<span class="dv">1</span>, lambda)
  
  <span class="co"># keep purchasing till end of life/observation time</span>
  <span class="cf">while</span>(t <span class="op">+</span><span class="st"> </span>wait <span class="op">&lt;=</span><span class="st"> </span><span class="kw">pmin</span>(T, tau)) {
    t &lt;-<span class="st"> </span>t <span class="op">+</span><span class="st"> </span>wait
    k &lt;-<span class="st"> </span>k <span class="op">+</span><span class="st"> </span><span class="dv">1</span>
    wait &lt;-<span class="st"> </span><span class="kw">rexp</span>(<span class="dv">1</span>, lambda)
  }
  
  <span class="co"># return tabular data</span>
  <span class="kw">tibble</span>(
    <span class="dt">mu =</span> mu,
    <span class="dt">lambda =</span> lambda,
    <span class="dt">T =</span> T,
    <span class="dt">tau =</span> tau,
    <span class="dt">k =</span> k,
    <span class="dt">t =</span> t
  )
}

s &lt;-<span class="st"> </span><span class="kw">sample_conditional</span>(<span class="fl">0.01</span>, <span class="dv">1</span>, <span class="dv">30</span>) </code></pre></div>
<table class="table table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Example output from sample_conditional
</caption>
<thead>
<tr>
<th style="text-align:right;">
mu
</th>
<th style="text-align:right;">
lambda
</th>
<th style="text-align:right;">
T
</th>
<th style="text-align:right;">
tau
</th>
<th style="text-align:right;">
k
</th>
<th style="text-align:right;">
t
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.01
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
30
</td>
<td style="text-align:right;">
49.63373
</td>
<td style="text-align:right;">
39
</td>
<td style="text-align:right;">
29.21926
</td>
</tr>
</tbody>
</table>
<p>Given <span class="math inline">\(\mu\)</span> and <span class="math inline">\(\lambda\)</span>, the CLV is calculated as follows. The remaining lifetime is the lifetime minus the age of the customer. So if the customer is estimated to have a lifetime of 1 year and has been a customer for 3 months already, then the remaining lifetime will be 9 months.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">lifetime &lt;-<span class="st"> </span><span class="cf">function</span>(n, mu, <span class="dt">age=</span><span class="dv">0</span>) {
  <span class="kw">rexp</span>(n, mu) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    `</span><span class="dt">-</span><span class="st">`</span>(age) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">pmax</span>(<span class="dv">0</span>) <span class="co"># remaining lifetime always &gt;= 0</span>
}</code></pre></div>
<p>The number of purchases in a given timeframe (within the customer’s lifetime) is simply a poisson random variable.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">purchases &lt;-<span class="st"> </span><span class="cf">function</span>(n, lambda, time) {
  <span class="kw">rpois</span>(n, lambda <span class="op">*</span><span class="st"> </span>time)
}</code></pre></div>
<p>To simulate the CLV, we just simulate a possible lifetime remaining, then simulate the number of puchases in that timeframe. Repeating many times gives us the distribution of the total number of purchases the customer is expected to make.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">clv &lt;-<span class="st"> </span><span class="cf">function</span>(n, mu, lambda, <span class="dt">age=</span><span class="dv">0</span>) {
  <span class="kw">lifetime</span>(n, mu, age) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">purchases</span>(n, lambda, .)
} </code></pre></div>
<figure>
<img src="pareto-nbd_files/figure-markdown/clv_plot-1.svg" />
</figure>
<p>The probability of churning can be estimated by the fraction of <code>lifetime</code> draws that are above 0. For example, for a customer with an expected lifetime of 10 (i.e. <span class="math inline">\(\mu = 0.1\)</span>) and a current age of 10, the probability of still being active is</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">mean</span>(<span class="kw">lifetime</span>(<span class="dv">100000</span>, <span class="fl">0.1</span>, <span class="dv">10</span>) <span class="op">&gt;</span><span class="st"> </span><span class="dv">0</span>)</code></pre></div>
<pre><code>[1] 0.36881</code></pre>
<p>which is roughly <span class="math inline">\(\exp(-0.1 * 10)\)</span>, the survival function of the exponential distribution.</p>
<h3 id="priors">Priors</h3>
<p>Now the priors. Typically, <span class="math inline">\(\mu\)</span> and <span class="math inline">\(\lambda\)</span> are given gamma priors, which we’ll use too. However, the expected mean lifetime <span class="math inline">\(\mathbb E (\tau) = \frac{1}{\mu}\)</span> is easier to reason about than <span class="math inline">\(\mu\)</span>, so we’ll put an inverse gamma distribution on <span class="math inline">\(\frac{1}{\mu}\)</span>. The <a href="https://en.wikipedia.org/wiki/Inverse-gamma_distribution#Related_distributions">reciprocal of an inverse gamma distribution</a> has a gamma distribution, so <span class="math inline">\(\mu\)</span> will still end up with a gamma distribution.</p>
<p>The mean expected lifetime in our simulated example will be ~2 months, with a standard deviation of 30. The mean purchase rate will be once a fortnight, with a standard deviation around 0.05.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">set.seed</span>(<span class="dv">2017896</span>)

etau_mean &lt;-<span class="st"> </span><span class="dv">60</span>
etau_variance &lt;-<span class="st"> </span><span class="dv">30</span><span class="op">^</span><span class="dv">2</span>
etau_beta &lt;-<span class="st"> </span>etau_mean<span class="op">^</span><span class="dv">3</span> <span class="op">/</span><span class="st"> </span>etau_variance <span class="op">+</span><span class="st"> </span>etau_mean
etau_alpha &lt;-<span class="st"> </span>etau_mean<span class="op">^</span><span class="dv">2</span> <span class="op">/</span><span class="st"> </span>etau_variance <span class="op">+</span><span class="st"> </span><span class="dv">2</span>

lambda_mean &lt;-<span class="st"> </span><span class="dv">1</span> <span class="op">/</span><span class="st"> </span><span class="dv">14</span>
lambda_variance &lt;-<span class="st"> </span><span class="fl">0.05</span><span class="op">^</span><span class="dv">2</span>
lambda_beta &lt;-<span class="st"> </span>lambda_mean <span class="op">/</span><span class="st"> </span>lambda_variance
lambda_alpha &lt;-<span class="st"> </span>lambda_mean <span class="op">*</span><span class="st"> </span>lambda_beta

df &lt;-<span class="st"> </span>customers <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">etau =</span> <span class="kw">rinvgamma</span>(<span class="kw">n</span>(), etau_alpha, etau_beta),
    <span class="dt">mu =</span> <span class="dv">1</span> <span class="op">/</span><span class="st"> </span>etau,
    <span class="dt">lambda =</span> <span class="kw">rgamma</span>(<span class="kw">n</span>(), lambda_alpha, lambda_beta)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(id) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_map</span>(<span class="op">~</span><span class="kw">sample_conditional</span>(.<span class="op">$</span>mu, .<span class="op">$</span>lambda, .<span class="op">$</span>T)) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Sample of customers and their properties
</caption>
<thead>
<tr>
<th style="text-align:right;">
id
</th>
<th style="text-align:right;">
mu
</th>
<th style="text-align:right;">
lambda
</th>
<th style="text-align:right;">
T
</th>
<th style="text-align:right;">
tau
</th>
<th style="text-align:right;">
k
</th>
<th style="text-align:right;">
t
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0.0241091
</td>
<td style="text-align:right;">
0.2108978
</td>
<td style="text-align:right;">
295.3119
</td>
<td style="text-align:right;">
32.2814622
</td>
<td style="text-align:right;">
6
</td>
<td style="text-align:right;">
29.46052
</td>
</tr>
<tr>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
0.0122084
</td>
<td style="text-align:right;">
0.0135551
</td>
<td style="text-align:right;">
673.2100
</td>
<td style="text-align:right;">
11.5250690
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.00000
</td>
</tr>
<tr>
<td style="text-align:right;">
3
</td>
<td style="text-align:right;">
0.0032994
</td>
<td style="text-align:right;">
0.0789800
</td>
<td style="text-align:right;">
357.1805
</td>
<td style="text-align:right;">
4.7921238
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.00000
</td>
</tr>
<tr>
<td style="text-align:right;">
4
</td>
<td style="text-align:right;">
0.0227431
</td>
<td style="text-align:right;">
0.0980176
</td>
<td style="text-align:right;">
270.0511
</td>
<td style="text-align:right;">
141.4766791
</td>
<td style="text-align:right;">
10
</td>
<td style="text-align:right;">
125.60765
</td>
</tr>
<tr>
<td style="text-align:right;">
5
</td>
<td style="text-align:right;">
0.0270742
</td>
<td style="text-align:right;">
0.0429184
</td>
<td style="text-align:right;">
608.9049
</td>
<td style="text-align:right;">
5.7293256
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.00000
</td>
</tr>
<tr>
<td style="text-align:right;">
6
</td>
<td style="text-align:right;">
0.0208168
</td>
<td style="text-align:right;">
0.0661296
</td>
<td style="text-align:right;">
666.1305
</td>
<td style="text-align:right;">
0.9481004
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.00000
</td>
</tr>
</tbody>
</table>
<p>The lifetimes are mostly under 3 months, but also allow some more extreme values up to around a year.</p>
<figure>
<img src="pareto-nbd_files/figure-markdown/tau_plot-1.svg" alt="Distribution of τ in our dataset." /><figcaption>Distribution of τ in our dataset.</figcaption>
</figure>
<p>The purchase rates are mostly around once a fortnight, but there are also rates as high as 4 purchases per week and ras low as one per quarter.</p>
<figure>
<img src="pareto-nbd_files/figure-markdown/lambda_plot-1.svg" alt="Distribution of λ in our dataset." /><figcaption>Distribution of λ in our dataset.</figcaption>
</figure>
<h2 id="likelihood-1">Likelihood</h2>
<p>The likelihood is somewhat complicated, so we’ll derive a more concise expression for it. Knowing the lifetime simplifies the probabilities, so we’ll marginalise the liklihood over <span class="math inline">\(\tau\)</span>.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P (k, t \mid \mu, \lambda)
  &amp;=
  \int_{\tau = t}^\infty \mathbb P (k, t \mid \mu, \lambda, \tau) \cdot \mathbb P(\tau \mid \mu, \lambda) d\tau
  \\
  &amp;=
  \int_{\tau = t}^T \mathbb P (k, t \mid \mu, \lambda, \tau) \cdot \mathbb P(\tau \mid \mu, \lambda)
  +
  \int_{\tau = T}^\infty \mathbb P (k, t \mid \mu, \lambda, \tau) \cdot \mathbb P(\tau \mid \mu, \lambda)
  \\
  &amp;=
  \int_{\tau = t}^T \dpois(k \mid t\lambda) \cdot \dpois(0 \mid (\tau-t)\lambda) \cdot \dexp(\tau \mid \mu) d\tau
  \\
  &amp;\hphantom{=}
  +
  \int_{\tau = T}^\infty \dpois(k \mid t\lambda) \cdot \dpois(0 \mid (T-t)\lambda) \cdot \dexp(\tau \mid \mu) d\tau
\end{align}
\]</span></p>
<p>The right-hand side is straight forward. The Poisson probabilities can be pulled out of the integral since they are independent of <span class="math inline">\(\tau\)</span>, turning the remaining integral into the survival function of the exponential distribution.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \text{RHS}
  &amp;=
  \int_{\tau = T}^\infty \dpois(k \mid t\lambda) \cdot \dpois(0 \mid (T - t)\lambda) \cdot\dexp(\tau \mid \mu) d\tau
  \\
  &amp;=
  \frac{(t\lambda)^k e^{-t\lambda}}{k!} e^{-(T-t)\lambda}\int_T^\infty \dexp(\tau \mid \mu) d\tau
  \\
  &amp;=
  \frac{(t\lambda)^k e^{-T\lambda}}{k!} e^{-T\mu}
  \\
  &amp;=
  \frac{(t\lambda)^k e^{-T(\lambda + \mu)}}{k!} 
\end{align}
\]</span></p>
<p>The left-hand side is a little more involved.</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \text{LHS}
  &amp;=
  \int_{\tau = t}^T \dpois(k \mid t\lambda) \cdot \dpois(0 \mid (\tau-t)\lambda) \cdot \dexp(\tau \mid \mu) d\tau
  \\
  &amp;=
  \frac{(t\lambda)^k e^{-t\lambda} }{k!}
  \int_t^T e^{-(\tau - t)\lambda} \mu e^{-\tau\mu} d\tau
  \\
  &amp;=
  \frac{(t\lambda)^k e^{-t\lambda} }{k!} e^{t\lambda} \mu 
  \int_t^T e^{-\tau(\lambda + \mu)} d\tau
  \\
  &amp;=
  \frac{(t\lambda)^k }{k!} \mu 
  \left. 
  \frac{ e^{-\tau(\lambda + \mu)}}{-(\lambda + \mu)} \right|_t^T
  \\
  &amp;=
  \frac{(t\lambda)^k }{k!} \mu 
  \frac{ e^{-t(\lambda + \mu)} - e^{-T(\lambda + \mu)}}{\lambda + \mu} 
\end{align}
\]</span></p>
<p>Adding both expressions gives our final expression for the likelihood</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P (k, t \mid \mu, \lambda)
  &amp;=
  \frac{(t\lambda)^k e^{-T(\lambda + \mu)}}{k!} 
  +
  \frac{(t\lambda)^k }{k!} \mu 
  \frac{ e^{-t(\lambda + \mu)} - e^{-T(\lambda + \mu)}}{\lambda + \mu} 
  \\
  &amp;\propto
  \lambda^k e^{-T(\lambda + \mu)}
  +
  \lambda^k \mu 
  \frac{ e^{-t(\lambda + \mu)} - e^{-T(\lambda + \mu)}}{\lambda + \mu} 
  \\
  &amp;=
  \frac{\lambda^k}{\lambda + \mu}
  \left( \mu e^{-t(\lambda + \mu)} - \mu e^{-T(\lambda + \mu)} + \mu e^{-T(\lambda + \mu)} + \lambda e^{-T(\lambda + \mu)} \right)
  \\
  &amp;=
  \frac{\lambda^k}{\lambda + \mu}
  \left( \mu e^{-t(\lambda + \mu)} + \lambda e^{-T(\lambda + \mu)} \right)
  ,
\end{align}
\]</span></p>
<p>where we dropped any factors independent of the parameters, <span class="math inline">\(\lambda, \mu\)</span>. This expression agrees with equation 2 in <a href="https://ieeexplore.ieee.org/document/4344404">ML07</a>.</p>
<p>Another way to view this likelihood is as a mixture of censored observations, but where the mixture probability <span class="math inline">\(p(\mu, \lambda) := \frac{\mu}{\lambda + \mu}\)</span> depends on the parameters. We can write this alternative interpretation as</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
\mathbb P(k, t \mid \mu, \lambda)
&amp;\propto
p \dpois(k \mid t\lambda)S(t \mid \mu) 
\\
&amp;\hphantom{\propto}+ (1 - p) \dpois(k \mid t\lambda)\dpois(0 \mid (T-t)\lambda)S(T \mid \mu)
,
\end{align}
\]</span></p>
<p>where <span class="math inline">\(S\)</span> is the survival function of the exponential distribution. In other words, either we censor at <span class="math inline">\(t\)</span> with probability <span class="math inline">\(p\)</span>, or we censor at <span class="math inline">\(T\)</span> with probability <span class="math inline">\((1 - p)\)</span>. Note that</p>
<ul>
<li>either decreasing the expected lifetime (i.e. increasing <span class="math inline">\(\mu\)</span>) or decreasing the purchase rate increases <span class="math inline">\(p\)</span>;</li>
<li>if <span class="math inline">\(t \approx T\)</span>, then the censored distributions are approximately equal. The smaller <span class="math inline">\(\lambda\)</span> is, the closer the approximation has to be for this to hold.</li>
</ul>
<p>To implement this in stan, we’ll need the log-likelihood, which is given by</p>
<p class="mathjaxWide"><span class="math display">\[
\log\mathbb P (k, t \mid \mu, \lambda)
=
k \log\lambda - \log(\lambda + \mu) + \log\left(\mu e^{-t(\lambda + \mu)} + \lambda e^{-T(\lambda + \mu)} \right)
.
\]</span></p>
<h2 id="what-does-the-likelihood-look-like">What does the likelihood “look like”?</h2>
<p>Let’s plot the likelihood to see how it changes as we vary <span class="math inline">\(k\)</span>, <span class="math inline">\(t\)</span>, and <span class="math inline">\(T\)</span>. We’ll use the following functions to do this.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># calculate the likelihood</span>
likelihood &lt;-<span class="st"> </span><span class="cf">function</span>(mu, lambda, k, t, T) {
    log_likelihood &lt;-<span class="st"> </span>k <span class="op">*</span><span class="st"> </span><span class="kw">log</span>(lambda) <span class="op">-</span><span class="st"> </span><span class="kw">log</span>(lambda <span class="op">+</span><span class="st"> </span>mu) <span class="op">+</span><span class="st"> </span><span class="kw">log</span>(mu <span class="op">*</span><span class="st"> </span><span class="kw">exp</span>(<span class="op">-</span>t <span class="op">*</span><span class="st"> </span>(lambda <span class="op">+</span><span class="st"> </span>mu)) <span class="op">+</span><span class="st"> </span>lambda <span class="op">*</span><span class="st"> </span><span class="kw">exp</span>(<span class="op">-</span>T <span class="op">*</span><span class="st"> </span>(lambda <span class="op">+</span><span class="st"> </span>mu)))
    <span class="kw">return</span>(<span class="kw">exp</span>(log_likelihood))
}

<span class="co"># the grid to calculate values for</span>
grid &lt;-<span class="st"> </span><span class="kw">crossing</span>(
  <span class="dt">mu =</span> <span class="kw">seq</span>(<span class="fl">0.00001</span>, <span class="dv">1</span>, <span class="fl">0.01</span>),
  <span class="dt">lambda =</span> <span class="kw">seq</span>(<span class="fl">0.00001</span>, <span class="dv">1</span>, <span class="fl">0.01</span>)
) 

<span class="co"># plot it all</span>
plot_likelihood &lt;-<span class="st"> </span><span class="cf">function</span>(grid, k, t, T) {
  grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">mutate</span>(<span class="dt">k =</span> k, <span class="dt">t =</span> t, <span class="dt">T =</span> T) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">mutate</span>(<span class="dt">likelihood =</span> <span class="kw">likelihood</span>(mu, lambda, k, t, T)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">ggplot</span>() <span class="op">+</span>
<span class="st">    </span><span class="kw">aes</span>(mu, lambda, <span class="dt">fill =</span> likelihood) <span class="op">+</span>
<span class="st">    </span><span class="kw">geom_raster</span>() <span class="op">+</span>
<span class="st">    </span><span class="kw">geom_contour</span>(<span class="kw">aes</span>(<span class="dt">z =</span> likelihood), <span class="dt">alpha =</span> <span class="fl">0.7</span>) <span class="op">+</span>
<span class="st">    </span><span class="kw">labs</span>(
      <span class="dt">x =</span> <span class="st">&#39;μ&#39;</span>,
      <span class="dt">y =</span> <span class="st">&#39;λ&#39;</span>,
      <span class="dt">title =</span> <span class="kw">str_glue</span>(<span class="st">&quot;Likelihood for k = {k}, t = {t}, T = {T}&quot;</span>),
      <span class="dt">subtitle =</span> <span class="st">&#39;restricted to the unit interval&#39;</span>,
      <span class="dt">fill =</span> <span class="st">&#39;Likelihood&#39;</span>
    )
}</code></pre></div>
<p>If <span class="math inline">\(k = t = 0 \approx T\)</span>, then we have almost no information to inform our estimates (we would rely strongly on our priors in this case). We see that both large and small lifetimes are equally possible, and the parameter estimates are approximately independent of one another.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">plot_likelihood</span>(<span class="dt">k =</span> <span class="dv">0</span>, <span class="dt">t =</span> <span class="dv">0</span>, <span class="dt">T =</span> <span class="fl">0.1</span>) </code></pre></div>
<figure>
<img src="pareto-nbd_files/figure-markdown/unnamed-chunk-1-1.svg" />
</figure>
<p>Adding some observation time changes it up a little. We can increase the purchase rate without changing the likelihood if we also decrease the lifetime (= increase <span class="math inline">\(\mu\)</span>). This trade-off is almost linear. There are almost always many customers that haven’t made a second purchase yet, so this case is likely important to deal with well.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">plot_likelihood</span>(<span class="dt">k =</span> <span class="dv">0</span>, <span class="dt">t =</span> <span class="dv">0</span>, <span class="dt">T =</span> <span class="dv">12</span>) </code></pre></div>
<figure>
<img src="pareto-nbd_files/figure-markdown/unnamed-chunk-2-1.svg" />
</figure>
<p>If, on the other hand, we do observe some purchases in this period, the likelihood quickly shrinks around the average purchase rate. Likewise, the expected lifetime clings around the larger values.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">plot_likelihood</span>(<span class="dt">k =</span> <span class="dv">3</span>, <span class="dt">t =</span> <span class="dv">12</span>, <span class="dt">T =</span> <span class="dv">12</span>) </code></pre></div>
<figure>
<img src="pareto-nbd_files/figure-markdown/unnamed-chunk-3-1.svg" />
</figure>
<p>Once a substantial length of time ellapses without any more purchases, we see the MLE estimate for <span class="math inline">\(\mu\)</span> move away from small values. This makes sense since we would otherwise have observed more recent purchases. The estimate for <span class="math inline">\(\mu\)</span> doesn’t increase too much though since we know the lifetime is at least 12.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">grid <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">plot_likelihood</span>(<span class="dt">k =</span> <span class="dv">3</span>, <span class="dt">t =</span> <span class="dv">12</span>, <span class="dt">T =</span> <span class="dv">100000</span>) </code></pre></div>
<figure>
<img src="pareto-nbd_files/figure-markdown/unnamed-chunk-4-1.svg" />
</figure>
<h2 id="stan-implementation">Stan implementation</h2>
<p>Let’s take a look at our <a href="models/pnbd.stan">Stan implementation</a>. Note that Stan uses the log-likelihood, and we can increment it by incrementing the <code>target</code> variable. We have also used the <a href="https://mc-stan.org/docs/2_18/functions-reference/composed-functions.html"><code>log_sum_exp</code></a> for numeric stability, where <span class="math inline">\(\text{log_sum_exp}(x, y) := \log(e^x + e^y)\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">pnb &lt;-<span class="st"> </span><span class="kw">here</span>(<span class="st">&#39;models/pnbd.stan&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">stan_model</span>() </code></pre></div>
<pre><code>S4 class stanmodel &#39;pnbd&#39; coded as follows:
data {
  int&lt;lower = 1&gt; n;       // number of customers
  vector&lt;lower = 0&gt;[n] t; // time to most recent purchase
  vector&lt;lower = 0&gt;[n] T; // total observation time
  vector&lt;lower = 0&gt;[n] k; // number of purchases observed

  // user-specified parameters
  real&lt;lower = 0&gt; etau_alpha;
  real&lt;lower = 0&gt; etau_beta;
  real&lt;lower = 0&gt; lambda_alpha;
  real&lt;lower = 0&gt; lambda_beta;
}

parameters {
  vector&lt;lower = 0&gt;[n] lambda; // purchase rate
  vector&lt;lower = 0&gt;[n] etau;   // expected mean lifetime
}

transformed parameters {
  vector&lt;lower = 0&gt;[n] mu = 1.0 ./ etau;
}

model {
  // priors
  etau ~ inv_gamma(etau_alpha, etau_beta);
  lambda ~ gamma(lambda_alpha, lambda_beta);

  // likelihood
  target += k .* log(lambda) - log(lambda + mu);
  for (i in 1:n) {
    target += log_sum_exp(
      log(lambda[i]) - (lambda[i] + mu[i]) .* T[i],
      log(mu[i]) - (lambda[i] + mu[i]) .* t[i]
    );
  }
} </code></pre>
<p>Let’s fit the model to our simulated data, using the correct priors.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">pnb_fit &lt;-<span class="st"> </span>rstan<span class="op">::</span><span class="kw">sampling</span>(
    pnb,
    <span class="dt">data =</span> <span class="kw">compose_data</span>(
      df,
      <span class="dt">etau_alpha =</span> etau_alpha,
      <span class="dt">etau_beta =</span> etau_beta,
      <span class="dt">lambda_alpha =</span> lambda_alpha,
      <span class="dt">lambda_beta =</span> lambda_beta
    ),
    <span class="dt">control =</span> <span class="kw">list</span>(<span class="dt">max_treedepth =</span> <span class="dv">15</span>),
    <span class="dt">chains =</span> <span class="dv">4</span>,
    <span class="dt">cores =</span> <span class="dv">4</span>,
    <span class="dt">warmup =</span> <span class="dv">1000</span>,
    <span class="dt">iter =</span> <span class="dv">3000</span>
  ) </code></pre></div>
<p>Using the default <code>max_treedepth</code> of 10 shows problems with the energy diagnostic, with the <code>etau</code> parameters seemingly most problematic. However, increasing it to 15 resolved these issues.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">pnb_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">check_hmc_diagnostics</span>()</code></pre></div>
<pre><code>Divergences:

0 of 8000 iterations ended with a divergence.


Tree depth:

0 of 8000 iterations saturated the maximum tree depth of 15.


Energy:

E-BFMI indicated no pathological behavior.</code></pre>
<p>There are also no problems with the effective sample sizes, although <code>etau</code> typically has the lowest.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">pnb_neff &lt;-<span class="st"> </span>pnb_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">neff_ratio</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(
    <span class="dt">ratio =</span> .,
    <span class="dt">parameter =</span> <span class="kw">names</span>(.)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">arrange</span>(ratio) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">head</span>(<span class="dv">5</span>) </code></pre></div>
<table class="table table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Parameters with the lowest effective sample size
</caption>
<thead>
<tr>
<th style="text-align:right;">
ratio
</th>
<th style="text-align:left;">
parameter
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.3877002
</td>
<td style="text-align:left;">
lp__
</td>
</tr>
<tr>
<td style="text-align:right;">
0.4838375
</td>
<td style="text-align:left;">
etau[716]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.5157888
</td>
<td style="text-align:left;">
etau[442]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.5722499
</td>
<td style="text-align:left;">
etau[367]
</td>
</tr>
<tr>
<td style="text-align:right;">
0.5803245
</td>
<td style="text-align:left;">
etau[443]
</td>
</tr>
</tbody>
</table>
<p>The rhat statistic also looks good.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">pnb_rhat &lt;-<span class="st"> </span>pnb_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">rhat</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tibble</span>(
    <span class="dt">rhat =</span> .,
    <span class="dt">parameter =</span> <span class="kw">names</span>(.)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">min</span>(rhat), <span class="kw">max</span>(rhat)) </code></pre></div>
<table class="table table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
The most extreme rhat values
</caption>
<thead>
<tr>
<th style="text-align:right;">
min(rhat)
</th>
<th style="text-align:right;">
max(rhat)
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0.9995222
</td>
<td style="text-align:right;">
1.001541
</td>
</tr>
</tbody>
</table>
<p>Around 50% of our 50% posterior intervals contain the true value, which is a good sign.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">calibration &lt;-<span class="st"> </span>pnb_fit <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">spread_draws</span>(mu[id], lambda[id]) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mean_qi</span>(<span class="dt">.width =</span> <span class="fl">0.5</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(df, <span class="dt">by =</span> <span class="st">&#39;id&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(
    <span class="dt">mu =</span> <span class="kw">mean</span>(mu.lower <span class="op">&lt;=</span><span class="st"> </span>mu.y <span class="op">&amp;</span><span class="st"> </span>mu.y <span class="op">&lt;=</span><span class="st"> </span>mu.upper),
    <span class="dt">lambda =</span> <span class="kw">mean</span>(lambda.lower <span class="op">&lt;=</span><span class="st"> </span>lambda.y <span class="op">&amp;</span><span class="st"> </span>lambda.y <span class="op">&lt;=</span><span class="st"> </span>lambda.upper)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">gather</span>(parameter, fraction) </code></pre></div>
<table class="table table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Fraction of 50% posterior intervals containing the true value. These should be close to 50%.
</caption>
<thead>
<tr>
<th style="text-align:left;">
parameter
</th>
<th style="text-align:right;">
fraction
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
mu
</td>
<td style="text-align:right;">
0.495
</td>
</tr>
<tr>
<td style="text-align:left;">
lambda
</td>
<td style="text-align:right;">
0.498
</td>
</tr>
</tbody>
</table>
<h2 id="discussion">Discussion</h2>
<p>We described the data generating process behind the Pareto-NBD model, implemented a model in Stan using our derivation of the likelihood, and fit the model to simulated data. The diagnostics didn’t indicate any convergence problems, and around 50% of the 50% posterior intervals contained the true parameter values. However, we used our knowledge of the prior distribution to fit the model. It would be better to use a hierarchical prior to relax this requirement.</p>
<p>As a next step, it would be interesting to extend the model to</p>
<ul>
<li>estimate spend per purchase;</li>
<li>use hierarchical priors on <span class="math inline">\(\mu\)</span> and <span class="math inline">\(\lambda\)</span>;</li>
<li>allow correlation between <span class="math inline">\(\mu\)</span> and <span class="math inline">\(\lambda\)</span>; and</li>
<li>allow covariates, such as cohorts.</li>
</ul>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>BDA3 Chapter 1 Exercise 3</title>
    <link href="http://www.briancallander.com/posts/bda3/chapter_01_exercise_03.html" />
    <id>http://www.briancallander.com/posts/bda3/chapter_01_exercise_03.html</id>
    <published>2019-03-31T00:00:00Z</published>
    <updated>2019-03-31T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">BDA3 Chapter 1 Exercise 3</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on 31 March, 2019  by Brian </br>
     Tags: <a href="/tags/bda%20chapter%201.html">bda chapter 1</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/hardy-weinberg%20principle.html">hardy-weinberg principle</a> </br>
     Category: <a href="/categories/bda3.html">bda3</a> 
    </p>
  </div>
</div>

<p>Here’s my solution to exercise 3, chapter 1, of <a href="https://andrewgelman.com/">Gelman’s</a> <em>Bayesian Data Analysis</em> (BDA), 3rd edition. There are <a href="http://www.stat.columbia.edu/~gelman/book/solutions.pdf">solutions</a> to some of the exercises on the <a href="http://www.stat.columbia.edu/~gelman/book/">book’s webpage</a>.</p>
<!--more-->
<div style="display:none">
<p class="mathjaxWide"><span class="math inline">\(\DeclareMathOperator{\dbinomial}{Binomial} \DeclareMathOperator{\dbern}{Bernoulli} \DeclareMathOperator{\dpois}{Poisson} \DeclareMathOperator{\dnorm}{Normal} \DeclareMathOperator{\dt}{t} \DeclareMathOperator{\dcauchy}{Cauchy} \DeclareMathOperator{\dexponential}{Exp} \DeclareMathOperator{\duniform}{Uniform} \DeclareMathOperator{\dgamma}{Gamma} \DeclareMathOperator{\dinvgamma}{InvGamma} \DeclareMathOperator{\invlogit}{InvLogit} \DeclareMathOperator{\logit}{Logit} \DeclareMathOperator{\ddirichlet}{Dirichlet} \DeclareMathOperator{\dbeta}{Beta}\)</span></p>
</div>
<p>Suppose a particular gene for eye colour has two alleles: a dominant X and a recessive x allele. Having <span class="math inline">\(xx\)</span> gives you blue eyes, otherwise you have brown eyes. Suppose also that the proportion of blue-eyed people is <span class="math inline">\(p^2\)</span>, and the proportion of heterozygotes is <span class="math inline">\(2p(1 - p)\)</span>. There are 3 questions to answer:</p>
<ol type="1">
<li>What is the probability of a brown-eyed child of brown-eyed parents being a heterozygote?</li>
<li>If such a heterozygote, Judy, has n brown-eyed children with a random heterozygote, what’s the probability that Judy is a heterozygote?</li>
<li>Under the conditions of part 2, what is the probability that Judy’s first grandchild has blue eyes?</li>
</ol>
<h2 id="simulation">Simulation</h2>
<p>Let’s first set up some data with which we can verify the results via simulation.</p>
<h3 id="data">Data</h3>
<p>We’ll simulate a large population of individuals where the probability of the recessive allele is 0.2.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">set.seed</span>(<span class="dv">11146</span>)

N &lt;-<span class="st"> </span><span class="dv">5000000</span>
p &lt;-<span class="st"> </span><span class="fl">0.2</span>

alleles &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="st">&#39;x&#39;</span>, <span class="st">&#39;X&#39;</span>)
weights &lt;-<span class="st"> </span><span class="kw">c</span>(p, <span class="dv">1</span> <span class="op">-</span><span class="st"> </span>p)

df &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">id =</span> <span class="dv">1</span><span class="op">:</span>N <span class="op">%&gt;%</span><span class="st"> </span><span class="kw">as.character</span>()) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">allele1 =</span> <span class="kw">sample</span>(alleles, N, <span class="dt">prob =</span> weights, <span class="dt">replace =</span> <span class="ot">TRUE</span>),
    <span class="dt">allele2 =</span> <span class="kw">sample</span>(alleles, N, <span class="dt">prob =</span> weights, <span class="dt">replace =</span> <span class="ot">TRUE</span>),
    <span class="dt">genotype =</span> <span class="kw">if_else</span>(allele1 <span class="op">==</span><span class="st"> </span>allele2, <span class="st">&#39;homozygote&#39;</span>, <span class="st">&#39;heterozygote&#39;</span>),
    <span class="dt">eye_colour =</span> <span class="kw">if_else</span>(allele1 <span class="op">==</span><span class="st"> &#39;x&#39;</span> <span class="op">&amp;</span><span class="st"> </span>allele2 <span class="op">==</span><span class="st"> &#39;x&#39;</span>, <span class="st">&#39;blue&#39;</span>, <span class="st">&#39;brown&#39;</span>)
  ) </code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
id
</th>
<th style="text-align:left;">
allele1
</th>
<th style="text-align:left;">
allele2
</th>
<th style="text-align:left;">
genotype
</th>
<th style="text-align:left;">
eye_colour
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
1
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
homozygote
</td>
<td style="text-align:left;">
brown
</td>
</tr>
<tr>
<td style="text-align:left;">
2
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
heterozygote
</td>
<td style="text-align:left;">
brown
</td>
</tr>
<tr>
<td style="text-align:left;">
3
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
heterozygote
</td>
<td style="text-align:left;">
brown
</td>
</tr>
<tr>
<td style="text-align:left;">
4
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
homozygote
</td>
<td style="text-align:left;">
brown
</td>
</tr>
<tr>
<td style="text-align:left;">
5
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
heterozygote
</td>
<td style="text-align:left;">
brown
</td>
</tr>
<tr>
<td style="text-align:left;">
6
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
homozygote
</td>
<td style="text-align:left;">
brown
</td>
</tr>
</tbody>
</table>
<p>This has the correct distribution of alleles, since <span class="math inline">\(p^2 \approx\)</span> 0.04 and <span class="math inline">\((1-p)^2\approx\)</span> 0.64.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">allele_distribution &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">group_by</span>(allele1, allele2) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">frac =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
allele1
</th>
<th style="text-align:left;">
allele2
</th>
<th style="text-align:right;">
n
</th>
<th style="text-align:right;">
frac
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:right;">
200006
</td>
<td style="text-align:right;">
0.2000018
</td>
</tr>
<tr>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
800015
</td>
<td style="text-align:right;">
0.7999982
</td>
</tr>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:right;">
800802
</td>
<td style="text-align:right;">
0.2002016
</td>
</tr>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
3199177
</td>
<td style="text-align:right;">
0.7997984
</td>
</tr>
</tbody>
</table>
<p>This also has the correct distribution of eye colours.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">eye_colour_distribution &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">group_by</span>(eye_colour) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">frac =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
eye_colour
</th>
<th style="text-align:right;">
n
</th>
<th style="text-align:right;">
frac
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
blue
</td>
<td style="text-align:right;">
200006
</td>
<td style="text-align:right;">
0.0400012
</td>
</tr>
<tr>
<td style="text-align:left;">
brown
</td>
<td style="text-align:right;">
4799994
</td>
<td style="text-align:right;">
0.9599988
</td>
</tr>
</tbody>
</table>
<p>The genotype distribution is also correct, since <span class="math inline">\(2p(1-p) \approx\)</span> 0.32.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">genotype_distribution &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">group_by</span>(genotype) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">frac =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
genotype
</th>
<th style="text-align:right;">
n
</th>
<th style="text-align:right;">
frac
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
heterozygote
</td>
<td style="text-align:right;">
1600817
</td>
<td style="text-align:right;">
0.3201634
</td>
</tr>
<tr>
<td style="text-align:left;">
homozygote
</td>
<td style="text-align:right;">
3399183
</td>
<td style="text-align:right;">
0.6798366
</td>
</tr>
</tbody>
</table>
<h3 id="reproduction">Reproduction</h3>
<p>Let’s also define a couple of functions to simulate reproduction within our population. The <code>pair</code> function matches up random individuals from the first table with random individuals from the second.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">pair &lt;-<span class="st"> </span><span class="cf">function</span>(df1, df2) {
  <span class="kw">inner_join</span>(
      df1 <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">select</span>(<span class="op">-</span><span class="kw">matches</span>(<span class="st">&#39;</span><span class="ch">\\</span><span class="st">.(x|y)$&#39;</span>)) <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">select</span>(<span class="kw">matches</span>(<span class="st">&#39;^(id|allele|genotype|eye)&#39;</span>)) <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">ungroup</span>() <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">sample_frac</span>(<span class="dt">size =</span> <span class="dv">1</span>) <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">mutate</span>(<span class="dt">row =</span> <span class="kw">row_number</span>()),
      df2 <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">select</span>(<span class="op">-</span><span class="kw">matches</span>(<span class="st">&#39;</span><span class="ch">\\</span><span class="st">.(x|y)$&#39;</span>)) <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">select</span>(<span class="kw">matches</span>(<span class="st">&#39;^(id|allele|genotype|eye)&#39;</span>)) <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">ungroup</span>() <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">sample_frac</span>(<span class="dt">size =</span> <span class="dv">1</span>) <span class="op">%&gt;%</span>
<span class="st">        </span><span class="kw">mutate</span>(<span class="dt">row =</span> <span class="kw">row_number</span>()),
      <span class="dt">by =</span> <span class="st">&#39;row&#39;</span>
    ) <span class="op">%&gt;%</span>
<span class="st">    </span><span class="kw">select</span>(<span class="op">-</span>row) <span class="op">%&gt;%</span>
<span class="st">    </span><span class="kw">return</span>()
}</code></pre></div>
<p>The <code>reproduce</code> function then randomly generates a child from the paired individuals.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">reproduce &lt;-<span class="st"> </span><span class="cf">function</span>(pairs, <span class="dt">n=</span><span class="dv">1</span>) {
  pairs <span class="op">%&gt;%</span>
<span class="st">    </span><span class="kw">crossing</span>(<span class="dt">child =</span> <span class="dv">1</span><span class="op">:</span>n) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">    </span><span class="kw">mutate</span>(
      <span class="co"># the variables x and y indicate the allele taken from parent x and y, respectively</span>
      <span class="dt">x =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">1</span>, <span class="fl">0.5</span>) <span class="op">+</span><span class="st"> </span><span class="dv">1</span>,
      <span class="dt">y =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">1</span>, <span class="fl">0.5</span>) <span class="op">+</span><span class="st"> </span><span class="dv">1</span>,
      <span class="dt">allele1 =</span> <span class="kw">if_else</span>(x <span class="op">==</span><span class="st"> </span><span class="dv">1</span>, allele1.x, allele2.x),
      <span class="dt">allele2 =</span> <span class="kw">if_else</span>(y <span class="op">==</span><span class="st"> </span><span class="dv">1</span>, allele1.y, allele2.y),
      <span class="dt">genotype =</span> <span class="kw">if_else</span>(allele1 <span class="op">==</span><span class="st"> </span>allele2, <span class="st">&#39;homozygote&#39;</span>, <span class="st">&#39;heterozygote&#39;</span>),
      <span class="dt">eye_colour =</span> <span class="kw">if_else</span>(allele1 <span class="op">==</span><span class="st"> &#39;x&#39;</span> <span class="op">&amp;</span><span class="st"> </span>allele2 <span class="op">==</span><span class="st"> &#39;x&#39;</span>, <span class="st">&#39;blue&#39;</span>, <span class="st">&#39;brown&#39;</span>),
      <span class="dt">id =</span> <span class="kw">paste</span>(id.x, id.y, child, <span class="dt">sep =</span> <span class="st">&#39;-&#39;</span>)
    ) <span class="op">%&gt;%</span>
<span class="st">    </span><span class="kw">return</span>()
}</code></pre></div>
<p>The <code>kids</code> table then represents the next generation from random mating within the entire population.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">kids &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">pair</span>(df) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">reproduce</span>()</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
allele1.x
</th>
<th style="text-align:left;">
allele2.x
</th>
<th style="text-align:left;">
allele1.y
</th>
<th style="text-align:left;">
allele2.y
</th>
<th style="text-align:left;">
allele1
</th>
<th style="text-align:left;">
allele2
</th>
<th style="text-align:right;">
x
</th>
<th style="text-align:right;">
y
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
2
</td>
</tr>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:left;">
x
</td>
<td style="text-align:left;">
X
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
</tr>
</tbody>
</table>
<p>The parent attributes are contained in the <code>kids</code> table, with the <code>.x</code> suffix for one parent and <code>.y</code> for the other.</p>
<h2 id="part-1">Part 1</h2>
<p>We’ll use <span class="math inline">\(A\)</span> to stand for the allele combination, e.g. <span class="math inline">\(XX\)</span>, or <span class="math inline">\(Xx = xX\)</span>, and <span class="math inline">\(E\)</span> for eye colour. The subscripts <span class="math inline">\(i = 1, 2\)</span> will be used for each of the two parents, and the absence of subscripts will indicate the variable for the child. We need to calculate the probability that the child is heterogenous given that they are brown-eyed with brown-eyed parents:</p>
<p class="mathjaxWide"><span class="math display">\[
\mathbb P (A = Xx \mid E, E_1, E_2 = B).
\]</span></p>
<p>It will be easier to calculate this if we can rewrite it as a probability conditional only on <span class="math inline">\(A_\bullet\)</span>-variables. First note that</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P (A, A_1, A_2)
  &amp;=
  \mathbb P (A \mid A_1, A_2) \mathbb P(A_1, A_2)
  \\
  &amp;=
  \mathbb P (A \mid A_1, A_2) \mathbb P(A_1) \mathbb P (A_2)
\end{align}
\]</span></p>
<p>using the chain rule and the assumption of random mating. Therefore,</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  &amp;
  P (A = Xx \mid E_\bullet = B)
  \\
  &amp;=
  \frac{\mathbb P (E_\bullet = B \mid A = Xx) \cdot \mathbb P (A = Xx)}{\mathbb P (E_\bullet = B)}
  \\
  &amp;=
  \frac{
    \sum_{a_1, a_2} \mathbb P (E_\bullet = B \mid A = Xx, A_1 = a_1, A_2 = a_2) \cdot \mathbb P (A = Xx \mid A_1 = a_1, A_2 = a_2) \cdot \mathbb P (A_1 = a_1) \cdot \mathbb P (A_2 = a_2)
  }{
    \sum_{a, a_1, a_2} \mathbb P (E_\bullet = B \mid A = a, A_1 = a_1, A_2 = a_2) \cdot \mathbb P (A = a \mid A_1 = a_1, A_2 = a_2) \cdot \mathbb P (A_1 = a_1) \cdot \mathbb P (A_2 = a_2)
  },
\end{align}
\]</span></p>
<p>where the numerator is marginalised over possible values of <span class="math inline">\(A_1\)</span> and <span class="math inline">\(A_2\)</span>, and the denominator additionally over <span class="math inline">\(A\)</span>.</p>
<p>The factors involving <span class="math inline">\(E_\bullet\)</span> are either 1 or 0, depending only on whether the given combination of alleles can give rise to brown eyes or not, respectively. Moreover, <span class="math inline">\(\mathbb P (A_i = XX) = (1 - p)^2\)</span> and <span class="math inline">\(\mathbb P (A_i = Xx) = 2p(1 - p)\)</span>, where the case <span class="math inline">\(A_i = xx\)</span> is impossible conditional on everybody having brown eyes. The only non-trivial calculations now involve <span class="math inline">\(\mathbb P (A = a \mid A_1 = a_1, A_2 = a_2)\)</span>:</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  \mathbb P (A = Xx \mid A_1 = Xx, A_2 = Xx)
  &amp;=
  \frac{1}{2}
  \\
  \mathbb P (A = Xx \mid A_1 = Xx, A_2 = XX)
  &amp;=
  \frac{1}{2}
  \\
  \mathbb P (A = Xx \mid A_1 = XX, A_2 = XX)
  &amp;=
  0
  \\
  \mathbb P (A = XX \mid A_1 = Xx, A_2 = Xx)
  &amp;=
  \frac{1}{4}
  \\
  \mathbb P (A = XX \mid A_1 = Xx, A_2 = XX)
  &amp;=
  \frac{1}{2}
  \\
  \mathbb P (A = XX \mid A_1 = XX, A_2 = XX)
  &amp;=
  1,
\end{align}
\]</span></p>
<p>as can be verified by inspection.</p>
<p>Now let’s plug in these values into the formula for the desired probability. The numerator is</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  &amp;
  P (A = Xx \mid E_\bullet = B)
  \\
  &amp;=
  \frac{
    \frac{1}{2} \cdot (2p(1 - p))^2 
    + \frac{1}{2} \cdot 2 \cdot 2p(1 - p)(1 - p)^2
    + 0 \cdot (1 - p)^4
  }{
    (\frac{1}{2} + \frac{1}{4}) \cdot 4p^2(1 - p)^2 
    + (\frac{1}{2} + \frac{1}{2}) \cdot 4p(1 - p)^3
    + (0 + 1) \cdot (1 - p)^4
  }
  \\
  &amp;=
  \frac{(1 - p)^2}{(1 - p)^2}
  \frac{
    2p^2 + 2p(1 - p)
  }{
    3p^2 + 4p(1 - p) + (1 - p)^2
  }
  \\
  &amp;=
  \frac{
    2p^2 + 2p - 2p^2
  }{
    3p^2 + 4p - 4p^2 + 1 + p^2 - 2p
  }
  \\
  &amp;=
  \frac{
    2p
  }{
    1 + 2p
  },
\end{align}
\]</span></p>
<p>as required. This is approximately <span class="math inline">\(2p\)</span> for small <span class="math inline">\(p\)</span>, and is approximatily <span class="math inline">\(\frac{1}{2}\)</span> for large <span class="math inline">\(p\)</span>.</p>
<h2 id="part-1-simulation">Part 1 simulation</h2>
<p>To condition on brown-eyed children from brown-eyed parents, we can just filter the <code>kids</code> table. Such a child is called <code>judy</code> in this exercise.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">judy &lt;-<span class="st"> </span>kids <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">filter</span>(
    eye_colour.x <span class="op">==</span><span class="st"> &#39;brown&#39;</span>,
    eye_colour.y <span class="op">==</span><span class="st"> &#39;brown&#39;</span>,
    eye_colour   <span class="op">==</span><span class="st"> &#39;brown&#39;</span>
  )

judy_genotypes &lt;-<span class="st"> </span>judy <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">group_by</span>(genotype) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">frac =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
genotype
</th>
<th style="text-align:right;">
n
</th>
<th style="text-align:right;">
frac
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
heterozygote
</td>
<td style="text-align:right;">
1280529
</td>
<td style="text-align:right;">
0.2858268
</td>
</tr>
<tr>
<td style="text-align:left;">
homozygote
</td>
<td style="text-align:right;">
3199559
</td>
<td style="text-align:right;">
0.7141732
</td>
</tr>
</tbody>
</table>
<p>This is very close to the theoretical value of <span class="math inline">\(\frac{2p}{1 + 2p}\approx\)</span> 0.286.</p>
<h2 id="part-2">Part 2</h2>
<p>Denote by <span class="math inline">\(E_{C_\bullet} = B\)</span> the condition that all of Judy’s children have brown eyes, and by <span class="math inline">\(A^p = a\)</span> the condition that Judy’s partner has allele combination <span class="math inline">\(a\)</span>. Then</p>
<p class="mathjaxWide"><span class="math display">\[
\begin{align}
  &amp;
  \mathbb P (A = Xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)
  \\
  &amp;=
  \frac{
    \mathbb P (A = Xx \mid E_\bullet = B, A^p = Xx)
    \cdot
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A^p = Xx = A)
  }{
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A^p = Xx)
  }
  \\
  &amp;=
  \frac{
    \mathbb P (A = Xx \mid E_\bullet = B)
    \cdot
    \mathbb P (E_{C_\bullet} = B \mid A^p = Xx = A)
  }{
    \sum_a 
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A^p = Xx, A = a) 
    \cdot
    \mathbb P (A = a \mid E_\bullet = B, A^p = Xx)
  }
  \\
  &amp;=
  \frac{
    \mathbb P (A = Xx \mid E_\bullet = B)
    \cdot
    \mathbb P (E_{C_\bullet} = B \mid A^p = Xx = A)
  }{
    \sum_a 
    \mathbb P (E_{C_\bullet} = B \mid A^p = Xx, A = a) 
    \cdot
    \mathbb P (A = a \mid E_\bullet = B)
  }
  \\
  &amp;=
  \frac{
    \frac{2p}{1 + 2p}
    \cdot
    (\frac{3}{4})^n
  }{
    \mathbb P (E_{C_\bullet} = B \mid A^p = Xx = A) 
    \cdot
    \mathbb P (A = Xx \mid E_\bullet = B)
    +
    \mathbb P (E_{C_\bullet} = B \mid A^p = Xx, A = XX) 
    \cdot
    \mathbb P (A = XX \mid E_\bullet = B)
  }
  \\
  &amp;=
  \frac{
    \frac{2p}{1 + 2p}
    \cdot
    (\frac{3}{4})^n
  }{
    \frac{2p}{1 + 2p}
    \cdot
    (\frac{3}{4})^n
    +
    \frac{1}{1 + 2p}
  }
  \\
  &amp;=
  \frac{2p \cdot (\frac{3}{4})^n}{2p \cdot (\frac{3}{4})^n + 1}
  \\
  &amp;=
  \frac{2p \cdot 3^n}{2p \cdot 3^n + 4^n}
  ,
\end{align}
\]</span></p>
<p>where we have used conditional independence several times for the probability of the child’s alleles given the parents’ alleles. As <span class="math inline">\(n \rightarrow \infty\)</span>, this probability shrinks to 0.</p>
<h2 id="part-2-simulation">Part 2 simulation</h2>
<p>To simulate part 2, we need to pair <code>judy</code> with heterozygotes from the general population, then filter for those children with brown eyes.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">judy_kids &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">filter</span>(genotype <span class="op">==</span><span class="st"> &#39;heterozygote&#39;</span>) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">pair</span>(judy) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">reproduce</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">ungroup</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">filter</span>(eye_colour <span class="op">==</span><span class="st"> &#39;brown&#39;</span>)</code></pre></div>
<p>Amongst <code>judy_kids</code>, Judy’s attributes have the <code>.y</code> suffix. Given the above conditions, the probability of her possible genotypes are then:</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">judy_genotypes_posterior &lt;-<span class="st"> </span>judy_kids <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">group_by</span>(genotype.y) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">tally</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">frac =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;">
genotype.y
</th>
<th style="text-align:right;">
n
</th>
<th style="text-align:right;">
frac
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;">
heterozygote
</td>
<td style="text-align:right;">
343962
</td>
<td style="text-align:right;">
0.2313911
</td>
</tr>
<tr>
<td style="text-align:left;">
homozygote
</td>
<td style="text-align:right;">
1142534
</td>
<td style="text-align:right;">
0.7686089
</td>
</tr>
</tbody>
</table>
<p>This is close to the theoretical value of <span class="math inline">\(\frac{6p}{6p + 4}\approx\)</span> 23.1%.</p>
<h2 id="part-3">Part 3</h2>
<p>Let’s introduce some notation. Let <span class="math inline">\(A_g\)</span> be the alleles of Judy’s first grandchild, the child of <span class="math inline">\(c\)</span> with alleles <span class="math inline">\(A_c\)</span> whose partner has alleles <span class="math inline">\(A_c^p\)</span>. We wish to calculate <span class="math inline">\(\mathbb P (A_g = xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)\)</span>.</p>
<p>First note that</p>
$$
<span class="math display">\[\begin{align}
  &amp;
  \mathbb P (A_c = Xx \mid E_\bullet = E_{C_\bullet} = B, A^p = Xx, A = a)
  \\
  &amp;=
  \frac{
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A_c = Xx = A^p, A = a)
    \cdot
    \mathbb P (A_c = Xx \mid E_\bullet = B, A^p = Xx, A = a, A)
  }{
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A^p = Xx, A = a)
  }
  \\
  &amp;=
  \frac{
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A_c = Xx = A^p, A = a)
    \cdot
    0.5
  }{
    \mathbb P (E_{C_\bullet} = B \mid E_\bullet = B, A^p = Xx, A = a)
  }
  \\
  &amp;=
  \begin{cases}
    \frac{\left(\frac{3}{4}\right)^{n-1} \cdot \frac{1}{2}}{\left(\frac{3}{4}\right)^n}
    &amp;\text{if } A = Xx
    \\
    1 \cdot \frac{1}{2} / 1
    &amp;\text{othewrise}
    
  \end{cases}
  \\
  &amp;=
  \begin{cases}
    \frac{2}{3}
    &amp;\text{if } A = Xx
    \\
    \frac{1}{2}
    &amp;\text{othewrise}
    
  \end{cases}
  .
\end{align}\]</span>
<p>$$</p>
<p>Thus,</p>
$$
<span class="math display">\[\begin{align}
  &amp;
  \mathbb P (A_c = Xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)
  \\
  &amp;=
  \sum_a
  \mathbb P (A_c = Xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx, A = a) 
  \cdot
  \mathbb P (A = a \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx) 
  \\
  &amp;=
  \frac{2}{3} \cdot 
  \frac{2p \cdot (\frac{3}{4})^n}{2p \cdot (\frac{3}{4})^n + 1}
  +
  \frac{1}{2} \cdot 
  \frac{1}{2p \cdot (\frac{3}{4})^n + 1}

  \\
  &amp;=
  \frac{p\left( \frac{3}{4} \right)^{n-1} + 0.5}{2p \cdot \left(\frac{3}{4}\right)^n + 1}
  ,
\end{align}\]</span>
<p>$$</p>
<p>which converges to <span class="math inline">\(\frac{1}{2}\)</span> as <span class="math inline">\(n \rightarrow \infty\)</span>.</p>
<p>The probability that Judy’s first grandchild is a homozygote can then be calculated by marginalising over the allele combinations of the child and their partner:</p>
$$
<span class="math display">\[\begin{align}
  &amp;
  \mathbb P (A_g = xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)
  \\
  &amp;=
  \sum_{a_c, a_c^p} 
  \mathbb P (A_g = xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx, A_c = a_c, A_c^p = a_c^p) 
  \cdot 
  \mathbb P (A_c = a_c, A_c^p = a_c^p \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)
  \\
  &amp;=
  \sum_{a_c, a_c^p} 
  \mathbb P (A_g = xx \mid A_c = a_c, A_c^p = a_c^p) 
  \cdot 
  \mathbb P (A_c^p = a_c^p )
  \cdot 
  \mathbb P (A_c = a_c \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)
  \\
  &amp;=
  \sum_{a_c^p} 
  \mathbb P (A_g = xx \mid A_c = Xx, A_c^p = a_c^p) 
  \cdot 
  \mathbb P (A_c^p = a_c^p )
  \cdot 
  \mathbb P (A_c = Xx \mid E_\bullet = B = E_{C_\bullet}, A^p = Xx)
  
  \\
  &amp;=
  
  \frac{p\left( \frac{3}{4} \right)^{n-1} + 0.5}{2p \cdot \left(\frac{3}{4}\right)^n + 1}
  \cdot 
  \sum_{a_c^p} 
  \mathbb P (A_g = xx \mid A_c = Xx, A_c^p = a_c^p) 
  \cdot 
  \mathbb P (A_c^p = a_c^p )
  
  \\
  &amp;=
  
  \frac{p\left( \frac{3}{4} \right)^{n-1} + 0.5}{2p \cdot \left(\frac{3}{4}\right)^n + 1}
  \cdot 
  \left(
  \mathbb P (A_g = xx \mid A_c = Xx, A_c^p = Xx) 
  \cdot 
  \mathbb P (A_c^p = Xx )
  +
  \mathbb P (A_g = xx \mid A_c = Xx, A_c^p = xx) 
  \cdot 
  \mathbb P (A_c^p = xx )
  \right)
  
  \\
  &amp;=
  
  \frac{p\left( \frac{3}{4} \right)^{n-1} + 0.5}{2p \cdot \left(\frac{3}{4}\right)^n + 1}
  \cdot 
  \left(
  \frac{1}{4}
  \cdot 
  2p(1 - p)
  +
  \frac{1}{2}
  \cdot 
  p^2
  \right)
  
  \\
  &amp;=
  
  \frac{p\left( \frac{3}{4} \right)^{n-1} + 0.5}{2p \cdot \left(\frac{3}{4}\right)^n + 1}
  \cdot
  \frac{p}{2}
  ,
\end{align}\]</span>
<p>$$</p>
<p>since</p>
<ul>
<li><p>the grandchild can only be blue-eyed if the (brown-eyed) child has at least one x-allele, i.e. the child is <span class="math inline">\(Xx\)</span>;</p></li>
<li><p class="mathjaxWide"><span class="math inline">\(A\)</span> and <span class="math inline">\(A^p\)</span> are independent by the random mating assumption; and</p></li>
<li><p class="mathjaxWide"><span class="math inline">\(A_c\)</span> and <span class="math inline">\(A_c^p\)</span> are independent by the random mating assumption.</p></li>
</ul>
<p>As <span class="math inline">\(n \rightarrow \infty\)</span>, this probability converges to <span class="math inline">\(\frac{p}{4}\)</span>.</p>
<h2 id="part-3-simulation">Part 3 simulation</h2>
<p>To simulate Judy’s grandkids, we pair up <code>judy_kids</code> with members of the general population.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">judy_grandkids &lt;-<span class="st"> </span>judy_kids <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pair</span>(df) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">reproduce</span>()

judy_grandkids <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">mean</span>(eye_colour <span class="op">==</span><span class="st"> &#39;blue&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">pull</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">signif</span>(<span class="dv">3</span>)</code></pre></div>
<pre><code>[1] 0.054</code></pre>
<p>The above fraction of grandkids with blue eyes is consistent with the theoretical value of <span class="math inline">\(\frac{4p + 0.5}{6p + 4}\frac{p}{2} \approx\)</span> 0.0538.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>
<entry>
    <title>CIS Primer Question 3.4.1</title>
    <link href="http://www.briancallander.com/posts/causal_inference_in_statistics_primer/question_3_4_1.html" />
    <id>http://www.briancallander.com/posts/causal_inference_in_statistics_primer/question_3_4_1.html</id>
    <published>2019-02-15T00:00:00Z</published>
    <updated>2019-02-15T00:00:00Z</updated>
    <summary type="html"><![CDATA[<h1 class="post-title">CIS Primer Question 3.4.1</h1>

<div class="card post-meta border-0">
  <div class="card-body post-meta">
    <p class="card-text text-muted text-left">
    Posted on 15 February, 2019  by Brian </br>
     Tags: <a href="/tags/CISP%20chapter%203.html">CISP chapter 3</a>, <a href="/tags/solutions.html">solutions</a>, <a href="/tags/front%20door%20criteria.html">front door criteria</a>, <a href="/tags/front%20door%20adjustment.html">front door adjustment</a> </br>
     Category: <a href="/categories/causal_inference_in_statistics_primer.html">causal_inference_in_statistics_primer</a> 
    </p>
  </div>
</div>

<p>Here are my solutions to question 3.4.1 of Causal Inference in Statistics: a Primer (CISP). <span class="math inline">\(\DeclareMathOperator{\do}{do}\)</span></p>
<!--more-->
<p>If we can only measure one additional variable to estimate the causal effect of <span class="math inline">\(X\)</span> on <span class="math inline">\(Y\)</span> in figure 3.8, then we should measure <span class="math inline">\(W\)</span>. From <a href="question_3_3_1.html">question 3.3.1</a> we see that no single variable satisfies the backdoor criteria. Moreover, visual inspection of the graph verifies that <span class="math inline">\(W\)</span> satisfies the frontdoor criteria:</p>
<ol type="1">
<li>it intercepts all (the only) directed paths from <span class="math inline">\(X\)</span> to <span class="math inline">\(Y\)</span>;</li>
<li>there is no unblocked path from <span class="math inline">\(X\)</span> to <span class="math inline">\(W\)</span>; and</li>
<li>all backdoor paths from <span class="math inline">\(W\)</span> to <span class="math inline">\(Y\)</span> are blocked by <span class="math inline">\(X\)</span>.</li>
</ol>
<p>To illustrate this, lets simulate the causal effect in 3 separate ways:</p>
<ol type="1">
<li>by intervention,</li>
<li>via the backdoor, and</li>
<li>via the frontdoor.</li>
</ol>
<p>Here are the data. Note that we have created functions for <span class="math inline">\(W\)</span> and <span class="math inline">\(Y\)</span> for use later.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">N &lt;-<span class="st"> </span><span class="dv">100000</span>

W &lt;-<span class="st"> </span><span class="cf">function</span>(x) {
  N &lt;-<span class="st"> </span><span class="kw">length</span>(x)
  <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="kw">inv_logit</span>(<span class="op">-</span>x))
}

Y &lt;-<span class="st"> </span><span class="cf">function</span>(d, w, z) {
  N &lt;-<span class="st"> </span><span class="kw">length</span>(d)
  <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="kw">inv_logit</span>(<span class="op">-</span>d <span class="op">-</span><span class="st"> </span>w <span class="op">+</span><span class="st"> </span><span class="dv">3</span><span class="op">*</span>z))
}

df &lt;-<span class="st"> </span><span class="kw">tibble</span>(<span class="dt">id =</span> <span class="dv">1</span><span class="op">:</span>N) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">b =</span> <span class="kw">rnorm</span>(N, <span class="dv">0</span>, <span class="dv">1</span>),
    <span class="dt">a =</span> b <span class="op">+</span><span class="st"> </span><span class="kw">rnorm</span>(N, <span class="dv">0</span>, <span class="fl">0.1</span>),
    <span class="dt">c =</span> <span class="kw">rnorm</span>(N, <span class="dv">0</span>, <span class="dv">1</span>),
    <span class="dt">d =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="kw">inv_logit</span>(<span class="op">-</span><span class="dv">1</span> <span class="op">+</span><span class="st"> </span>c)),
    <span class="dt">z =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="kw">inv_logit</span>(<span class="op">-</span><span class="dv">2</span> <span class="op">+</span><span class="st"> </span><span class="dv">2</span><span class="op">*</span>b <span class="op">+</span><span class="st"> </span>c)),
    <span class="dt">x =</span> <span class="kw">rbinom</span>(N, <span class="dv">1</span>, <span class="kw">inv_logit</span>(a <span class="op">+</span><span class="st"> </span>z)),
    <span class="dt">w =</span> <span class="kw">W</span>(x),
    <span class="dt">y =</span> <span class="kw">Y</span>(d, w, z)
  )</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Simulated data for figure 3.8
</caption>
<thead>
<tr>
<th style="text-align:right;">
id
</th>
<th style="text-align:right;">
b
</th>
<th style="text-align:right;">
a
</th>
<th style="text-align:right;">
c
</th>
<th style="text-align:right;">
d
</th>
<th style="text-align:right;">
z
</th>
<th style="text-align:right;">
x
</th>
<th style="text-align:right;">
w
</th>
<th style="text-align:right;">
y
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0.3641297
</td>
<td style="text-align:right;">
0.3917626
</td>
<td style="text-align:right;">
1.0369530
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:right;">
2
</td>
<td style="text-align:right;">
0.0287563
</td>
<td style="text-align:right;">
0.0397299
</td>
<td style="text-align:right;">
0.5736271
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
</tr>
<tr>
<td style="text-align:right;">
3
</td>
<td style="text-align:right;">
-0.7727052
</td>
<td style="text-align:right;">
-0.5993870
</td>
<td style="text-align:right;">
-0.5179657
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:right;">
4
</td>
<td style="text-align:right;">
0.4107888
</td>
<td style="text-align:right;">
0.5737898
</td>
<td style="text-align:right;">
1.2586840
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
</tr>
<tr>
<td style="text-align:right;">
5
</td>
<td style="text-align:right;">
2.3512417
</td>
<td style="text-align:right;">
2.1631719
</td>
<td style="text-align:right;">
0.6746523
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
1
</td>
</tr>
</tbody>
</table>
<h2 id="intervention">Intervention</h2>
<p>In order to simulate an intervention, we assign values to <span class="math inline">\(X\)</span> randomly, then assign new values for all its descendents. After intervention, the causal effect of <span class="math inline">\(X\)</span> on <span class="math inline">\(Y\)</span> is simply <span class="math inline">\(\mathbb P(Y \mid X)\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">intervention &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># intervene on x</span>
<span class="st">  </span><span class="kw">mutate</span>(
    <span class="dt">x =</span> <span class="kw">rbinom</span>(<span class="kw">n</span>(), <span class="dv">1</span>, <span class="fl">0.5</span>),
    <span class="dt">w =</span> <span class="kw">W</span>(x),
    <span class="dt">y =</span> <span class="kw">Y</span>(d, w, z)
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># model P(y | do(x))</span>
<span class="st">  </span><span class="kw">glm</span>(
    <span class="dt">formula =</span> y <span class="op">~</span><span class="st"> </span>x, 
    <span class="dt">family =</span> <span class="kw">binomial</span>(), 
    <span class="dt">data =</span> .
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># predict</span>
<span class="st">  </span><span class="kw">augment</span>(
    <span class="dt">newdata =</span> <span class="kw">tibble</span>(<span class="dt">x =</span> <span class="dv">0</span><span class="op">:</span><span class="dv">1</span>), 
    <span class="dt">type.predict =</span> <span class="st">&#39;response&#39;</span>
  ) </code></pre></div>
<table class="table table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
P(Y | do(X))
</caption>
<thead>
<tr>
<th style="text-align:right;">
x
</th>
<th style="text-align:right;">
.fitted
</th>
<th style="text-align:right;">
.se.fit
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.4637566
</td>
<td style="text-align:right;">
0.0022239
</td>
</tr>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0.5072714
</td>
<td style="text-align:right;">
0.0022422
</td>
</tr>
</tbody>
</table>
<p>We can compare this causal effect to the simple statistical effect to see the difference.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">noncausal &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># model P(y | x)</span>
<span class="st">  </span><span class="kw">glm</span>(
    <span class="dt">formula =</span> y <span class="op">~</span><span class="st"> </span>x, 
    <span class="dt">family =</span> <span class="kw">binomial</span>(), 
    <span class="dt">data =</span> .
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># predict</span>
<span class="st">  </span><span class="kw">augment</span>(
    <span class="dt">newdata =</span> <span class="kw">tibble</span>(<span class="dt">x =</span> <span class="dv">0</span><span class="op">:</span><span class="dv">1</span>), 
    <span class="dt">type.predict =</span> <span class="st">&#39;response&#39;</span>
  ) </code></pre></div>
<table class="table table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
P(Y | X) ≠ P(Y | do(X))
</caption>
<thead>
<tr>
<th style="text-align:right;">
x
</th>
<th style="text-align:right;">
.fitted
</th>
<th style="text-align:right;">
.se.fit
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.3797282
</td>
<td style="text-align:right;">
0.0022595
</td>
</tr>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0.5759927
</td>
<td style="text-align:right;">
0.0021293
</td>
</tr>
</tbody>
</table>
<h2 id="backdoor">Backdoor</h2>
<p>Since <span class="math inline">\(\{X, Z\}\)</span> satisfies the backdoor criteria, we can use it to apply the backdoor adjustment. First we’ll need <span class="math inline">\(\mathbb P(D, Z)\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># P(d, z)</span>
p_d_z &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(d, z) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">count</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">ungroup</span>() <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">p_d_z =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n)) </code></pre></div>
<p>Now we model <span class="math inline">\(\mathbb P(Y \mid X, D, Z)\)</span>, multiply it by <span class="math inline">\(\mathbb P(D, Z)\)</span>, then take the sum for each value of <span class="math inline">\(X\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">backdoor &lt;-<span class="st"> </span><span class="kw">formula</span>(y <span class="op">~</span><span class="st"> </span><span class="dv">1</span> <span class="op">+</span><span class="st"> </span>x <span class="op">+</span><span class="st"> </span>z <span class="op">+</span><span class="st"> </span>d) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># model P(y | x, d, z)</span>
<span class="st">  </span><span class="kw">glm</span>(
    <span class="dt">family =</span> <span class="kw">binomial</span>(),
    <span class="dt">data =</span> df
  ) <span class="op">%&gt;%</span><span class="st">  </span>
<span class="st">  </span><span class="co"># predict</span>
<span class="st">  </span><span class="kw">augment</span>(
    <span class="dt">type.predict =</span> <span class="st">&#39;response&#39;</span>,
    <span class="dt">newdata =</span> 
      <span class="kw">crossing</span>(
        <span class="dt">d =</span> <span class="kw">c</span>(<span class="dv">0</span>, <span class="dv">1</span>),
        <span class="dt">x =</span> <span class="kw">c</span>(<span class="dv">0</span>, <span class="dv">1</span>),
        <span class="dt">z =</span> <span class="kw">c</span>(<span class="dv">0</span>, <span class="dv">1</span>)
      )
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># get P(d, z)</span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">p_y_given_d_x_z =</span> .fitted) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(p_d_z, <span class="dt">by =</span> <span class="kw">c</span>(<span class="st">&#39;d&#39;</span>, <span class="st">&#39;z&#39;</span>)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="co"># backdoor adjustment over d, z</span>
<span class="st">  </span><span class="kw">group_by</span>(x) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="dt">p_y_given_do_x =</span> <span class="kw">sum</span>(p_y_given_d_x_z <span class="op">*</span><span class="st"> </span>p_d_z))</code></pre></div>
<table class="table table-striped table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Backdoor estimates for P(Y | do(X))
</caption>
<thead>
<tr>
<th style="text-align:right;">
x
</th>
<th style="text-align:right;">
p_y_given_do_x
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.4681530
</td>
</tr>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0.5033398
</td>
</tr>
</tbody>
</table>
<p>Note that the backdoor adjusted estimates are similar to the estimates from intervention.</p>
<h2 id="frontdoor">Frontdoor</h2>
<p>To apply the frontdoor adjustment with <span class="math inline">\(W\)</span>, we’ll need <span class="math inline">\(\mathbb P(W \mid X)\)</span>, <span class="math inline">\(\mathbb P(X^\prime)\)</span>, and <span class="math inline">\(\mathbb P(Y \mid X, W)\)</span>.</p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">p_w_given_x &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(x, w) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">count</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(x) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">p_w_given_x =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n)) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">ungroup</span>()

p_xprime &lt;-<span class="st"> </span>df <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(<span class="dt">xprime =</span> x) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">count</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">ungroup</span>() <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">mutate</span>(<span class="dt">p_xprime =</span> n <span class="op">/</span><span class="st"> </span><span class="kw">sum</span>(n))

p_y_given_xprime_w &lt;-<span class="st"> </span><span class="kw">formula</span>(y <span class="op">~</span><span class="st"> </span><span class="dv">1</span> <span class="op">+</span><span class="st"> </span>x <span class="op">+</span><span class="st"> </span>w) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">glm</span>(
    <span class="dt">family =</span> <span class="kw">binomial</span>(),
    <span class="dt">data =</span> df
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">augment</span>(
    <span class="dt">newdata =</span> <span class="kw">crossing</span>(<span class="dt">x =</span> <span class="dv">0</span><span class="op">:</span><span class="dv">1</span>, <span class="dt">w =</span> <span class="dv">0</span><span class="op">:</span><span class="dv">1</span>),
    <span class="dt">type.predict =</span> <span class="st">&#39;response&#39;</span>
  ) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">transmute</span>(
    <span class="dt">xprime =</span> x,
    w,
    <span class="dt">p_y_given_xprime_w =</span> .fitted
  )</code></pre></div>
<p>Now we apply the frontdoor adjustment:</p>
<p class="mathjaxWide"><span class="math display">\[
\mathbb P (Y \mid \do(X))
=
\sum_{x^\prime, w}
\mathbb P(x^\prime)
\cdot
\mathbb P(w \mid x)
\cdot
\mathbb P (y \mid x^\prime, w)
.
\]</span></p>
<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">frontdoor &lt;-<span class="st"> </span>p_w_given_x <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(p_y_given_xprime_w, <span class="dt">by =</span> <span class="st">&#39;w&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">inner_join</span>(p_xprime, <span class="dt">by =</span> <span class="st">&#39;xprime&#39;</span>) <span class="op">%&gt;%</span><span class="st"> </span>
<span class="st">  </span><span class="kw">group_by</span>(x) <span class="op">%&gt;%</span>
<span class="st">  </span><span class="kw">summarise</span>(<span class="kw">sum</span>(p_w_given_x <span class="op">*</span><span class="st"> </span>p_y_given_xprime_w <span class="op">*</span><span class="st"> </span>p_xprime))</code></pre></div>
<table class="table table-hover table-responsive" style="margin-left: auto; margin-right: auto;">
<caption>
Frontdoor estimates of P(Y | do(X))
</caption>
<thead>
<tr>
<th style="text-align:right;">
x
</th>
<th style="text-align:right;">
sum(p_w_given_x * p_y_given_xprime_w * p_xprime)
</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:right;">
0
</td>
<td style="text-align:right;">
0.4623710
</td>
</tr>
<tr>
<td style="text-align:right;">
1
</td>
<td style="text-align:right;">
0.5041105
</td>
</tr>
</tbody>
</table>
<p>Our frontdoor estimates of <span class="math inline">\(\mathbb P(Y \mid \do(X))\)</span> are very similar to the intervention and backdoor estimates.</p>

<div id="disqus_thread"></div>
<script>
/**
 *  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
 *  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables
 */
/*
   var disqus_config = function () {
   this.page.url = PAGE_URL;  // Replace PAGE_URL with your page's canonical URL variable
   this.page.identifier = PAGE_IDENTIFIER; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
   };
 */
(function() {  // DON'T EDIT BELOW THIS LINE
 var d = document, s = d.createElement('script');

 s.src = '//stappit-github-io.disqus.com/embed.js';

 s.setAttribute('data-timestamp', +new Date());
 (d.head || d.body).appendChild(s);
 })();
</script>

<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>

<script id="dsq-count-scr" src="//stappit-github-io.disqus.com/count.js" async></script>
]]></summary>
</entry>

</feed>
