<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="http://www.r-bloggers.com/understanding-bayesian-ab-testing-using-baseball-statistics/"></div></div><div><a data-url="http://www.r-bloggers.com/understanding-bayesian-ab-testing-using-baseball-statistics/" data-counturl="http://www.r-bloggers.com/understanding-bayesian-ab-testing-using-baseball-statistics/" data-count="horizontal" data-text="Understanding Bayesian A/B testing (using baseball statistics)" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://varianceexplained.org/r/bayesian_ab_baseball/"> Variance Explained</a></strong>, and kindly contributed to <a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><strong>Previously in this series</strong></p>
<ul>
<li><a target="_blank" href="http://varianceexplained.org/statistics/beta_distribution_and_baseball/">Understanding the beta distribution (using baseball statistics)</a></li>
<li><a target="_blank" href="http://varianceexplained.org/r/empirical_bayes_baseball/">Understanding empirical Bayes estimation (using baseball statistics)</a></li>
<li><a target="_blank" href="http://varianceexplained.org/r/credible_intervals_baseball/">Understanding credible intervals (using baseball statistics)</a></li>
<li><a target="_blank" href="http://varianceexplained.org/statistics/beta_distribution_and_baseball/">Understanding the Bayesian approach to false discovery rates (using baseball statistics)</a></li>
</ul>
<p>Who is a better batter: <a target="_blank" href="https://en.wikipedia.org/wiki/Mike_Piazza">Mike Piazza</a> or <a target="_blank" href="https://en.wikipedia.org/wiki/Hank_Aaron">Hank Aaron</a>?</p>
<p>Well, Mike Piazza has a slightly higher career batting average (2127 hits / 6911 at-bats = 0.308) than Hank Aaron (3771 hits / 12364 at-bats = 0.305). But can we say with confidence that his skill is <em>actually</em> higher, or is it possible he just got lucky a bit more often?</p>
<p>In this series of posts about an empirical Bayesian approach to batting statistics, we’ve been estimating batting averages by modeling them as a binomial distribution with a beta prior. But we’ve been looking at a single batter at a time. What if we want to compare <em>two</em> batters, give a probability that one is better than the other, and estimate <em>by how much</em>?</p>
<p>This is a topic rather relevant to my own work and to the data science field, because understanding the difference between two proportions is important in <strong>A/B testing</strong>. One of the most common examples of A/B testing is comparing clickthrough rates (“out of X impressions, there have been Y clicks”)- which on the surface is similar to our batting average estimation problem (“out of X at-bats, there have been Y hits””).<sup><a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fn:bayesianAB">1</a></sup></p>
<p>Here, we’re going to look at an empirical Bayesian approach to comparing two batters.<sup><a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fn:sabermetrics">2</a></sup> We’ll define the problem in terms of the difference between each batter’s posterior distribution, and look at four mathematical and computational strategies we can use to resolve this question. While we’re focusing on baseball here, remember that similar strategies apply to A/B testing, and indeed to many Bayesian models.</p>
<h3>Setup</h3>
<p>I’ll start with some code you can use to catch up if you want to follow along in R. If you want to understand what the code does, check out the previous posts. (All the code in this post, including for the figures where code isn’t shown, can be found <a target="_blank" href="https://github.com/dgrtwo/dgrtwo.github.com/blob/master/_R/2016-05-23-bayesian_ab_baseball.Rmd">here</a>).</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>dplyr</span><span>)</span>
<span>library</span><span>(</span><span>tidyr</span><span>)</span>
<span>library</span><span>(</span><span>Lahman</span><span>)</span>

<span># Grab career batting average of non-pitchers
# (allow players that have pitched &lt;= 3 games, like Ty Cobb)
</span><span>pitchers</span> <span>&lt;-</span> <span>Pitching</span> <span>%>%</span>
  <span>group_by</span><span>(</span><span>playerID</span><span>)</span> <span>%>%</span>
  <span>summarize</span><span>(</span><span>gamesPitched</span> <span>=</span> <span>sum</span><span>(</span><span>G</span><span>))</span> <span>%>%</span>
  <span>filter</span><span>(</span><span>gamesPitched</span> <span>></span> <span>3</span><span>)</span>

<span>career</span> <span>&lt;-</span> <span>Batting</span> <span>%>%</span>
  <span>filter</span><span>(</span><span>AB</span> <span>></span> <span>0</span><span>)</span> <span>%>%</span>
  <span>anti_join</span><span>(</span><span>pitchers</span><span>,</span> <span>by</span> <span>=</span> <span>&quot;playerID&quot;</span><span>)</span> <span>%>%</span>
  <span>group_by</span><span>(</span><span>playerID</span><span>)</span> <span>%>%</span>
  <span>summarize</span><span>(</span><span>H</span> <span>=</span> <span>sum</span><span>(</span><span>H</span><span>),</span> <span>AB</span> <span>=</span> <span>sum</span><span>(</span><span>AB</span><span>))</span> <span>%>%</span>
  <span>mutate</span><span>(</span><span>average</span> <span>=</span> <span>H</span> <span>/</span> <span>AB</span><span>)</span>

<span># Add player names
</span><span>career</span> <span>&lt;-</span> <span>Master</span> <span>%>%</span>
  <span>tbl_df</span><span>()</span> <span>%>%</span>
  <span>select</span><span>(</span><span>playerID</span><span>,</span> <span>nameFirst</span><span>,</span> <span>nameLast</span><span>)</span> <span>%>%</span>
  <span>unite</span><span>(</span><span>name</span><span>,</span> <span>nameFirst</span><span>,</span> <span>nameLast</span><span>,</span> <span>sep</span> <span>=</span> <span>&quot; &quot;</span><span>)</span> <span>%>%</span>
  <span>inner_join</span><span>(</span><span>career</span><span>,</span> <span>by</span> <span>=</span> <span>&quot;playerID&quot;</span><span>)</span>

<span># Estimate hyperparameters alpha0 and beta0 for empirical Bayes
</span><span>career_filtered</span> <span>&lt;-</span> <span>career</span> <span>%>%</span> <span>filter</span><span>(</span><span>AB</span> <span>>=</span> <span>500</span><span>)</span>
<span>m</span> <span>&lt;-</span> <span>MASS</span><span>::</span><span>fitdistr</span><span>(</span><span>career_filtered</span><span>$</span><span>average</span><span>,</span> <span>dbeta</span><span>,</span>
                    <span>start</span> <span>=</span> <span>list</span><span>(</span><span>shape1</span> <span>=</span> <span>1</span><span>,</span> <span>shape2</span> <span>=</span> <span>10</span><span>))</span>

<span>alpha0</span> <span>&lt;-</span> <span>m</span><span>$</span><span>estimate</span><span>[</span><span>1</span><span>]</span>
<span>beta0</span> <span>&lt;-</span> <span>m</span><span>$</span><span>estimate</span><span>[</span><span>2</span><span>]</span>

<span># For each player, update the beta prior based on the evidence
# to get posterior parameters alpha1 and beta1
</span><span>career_eb</span> <span>&lt;-</span> <span>career</span> <span>%>%</span>
  <span>mutate</span><span>(</span><span>eb_estimate</span> <span>=</span> <span>(</span><span>H</span> <span>+</span> <span>alpha0</span><span>)</span> <span>/</span> <span>(</span><span>AB</span> <span>+</span> <span>alpha0</span> <span>+</span> <span>beta0</span><span>))</span> <span>%>%</span>
  <span>mutate</span><span>(</span><span>alpha1</span> <span>=</span> <span>H</span> <span>+</span> <span>alpha0</span><span>,</span>
         <span>beta1</span> <span>=</span> <span>AB</span> <span>-</span> <span>H</span> <span>+</span> <span>beta0</span><span>)</span> <span>%>%</span>
  <span>arrange</span><span>(</span><span>desc</span><span>(</span><span>eb_estimate</span><span>))</span></code></pre>
</figure>
<p>So let’s take a look at the two batters in question:</p>
<figure>
<pre><code data-lang="r"><span># while we're at it, save them as separate objects too for later:
</span><span>aaron</span> <span>&lt;-</span> <span>career_eb</span> <span>%>%</span> <span>filter</span><span>(</span><span>name</span> <span>==</span> <span>&quot;Hank Aaron&quot;</span><span>)</span>
<span>piazza</span> <span>&lt;-</span> <span>career_eb</span> <span>%>%</span> <span>filter</span><span>(</span><span>name</span> <span>==</span> <span>&quot;Mike Piazza&quot;</span><span>)</span>
<span>two_players</span> <span>&lt;-</span> <span>bind_rows</span><span>(</span><span>aaron</span><span>,</span> <span>piazza</span><span>)</span>

<span>two_players</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## Source: local data frame [2 x 8]
## 
##    playerID        name     H    AB average eb_estimate alpha1 beta1
##       (chr)       (chr) (int) (int)   (dbl)       (dbl)  (dbl) (dbl)
## 1 aaronha01  Hank Aaron  3771 12364   0.305       0.304   3847  8812
## 2 piazzmi01 Mike Piazza  2127  6911   0.308       0.306   2203  5003</code></pre>
</figure>
<p>We see that Piazza has a slightly higher average (), <em>and</em> a higher shrunken empirical bayes estimate (, where  and  are our priors).</p>
<p>But is Piazza’s <em>true</em> probability of getting a hit higher? Or is the difference due to chance? To answer, let’s consider the actual posterior distributions- the range of plausible values for their “true” batting averages after we’ve taken the evidence (their batting record) into account. Recall that these posterior distributions are modeled as <a target="_blank" href="http://varianceexplained.org/statistics/beta_distribution_and_baseball">beta distributions</a> with the parameters .</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>broom</span><span>)</span>
<span>library</span><span>(</span><span>ggplot2</span><span>)</span>
<span>theme_set</span><span>(</span><span>theme_bw</span><span>())</span>

<span>two_players</span> <span>%>%</span>
  <span>inflate</span><span>(</span><span>x</span> <span>=</span> <span>seq</span><span>(</span><span>.28</span><span>,</span> <span>.33</span><span>,</span> <span>.00025</span><span>))</span> <span>%>%</span>
  <span>mutate</span><span>(</span><span>density</span> <span>=</span> <span>dbeta</span><span>(</span><span>x</span><span>,</span> <span>alpha1</span><span>,</span> <span>beta1</span><span>))</span> <span>%>%</span>
  <span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>x</span><span>,</span> <span>density</span><span>,</span> <span>color</span> <span>=</span> <span>name</span><span>))</span> <span>+</span>
  <span>geom_line</span><span>()</span> <span>+</span>
  <span>labs</span><span>(</span><span>x</span> <span>=</span> <span>&quot;Batting average&quot;</span><span>,</span> <span>color</span> <span>=</span> <span>&quot;&quot;</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="http://i2.wp.com/varianceexplained.org/figs/2016-05-23-bayesian_ab_baseball/unnamed-chunk-3-1.png?w=456" data-recalc-dims="1"></p>
<p>This posterior is a probabilistic representation of our <em>uncertainty</em> in each estimate. Thus, when asking the probability Piazza is better, we’re asking “if I drew a random draw from Piazza’s and a random draw from Aaron’s, what’s the probability Piazza is higher”?</p>
<p>Well, notice that those two distributions overlap <em>a lot</em>! There’s enough uncertainty in each of those estimates that Aaron could easily be better than Piazza.</p>
<p>Let’s throw another player in, retired Yankee Hideki Matsui:</p>
<p><img alt="center" src="http://i0.wp.com/varianceexplained.org/figs/2016-05-23-bayesian_ab_baseball/unnamed-chunk-4-1.png?w=456" data-recalc-dims="1"></p>
<p>Hideki Matsui is a fine batter (above average for major league baseball), but not up to the level of Aaron and Piazza: notice that his posterior distribution barely overlaps theirs. If we took a random draw from Matsui’s distribution and from Piazza’s, it’s very unlikely Matsui’s would be higher.</p>
<h3>Posterior Probability</h3>
<p>We may be interested in the probability that Piazza is better than Aaron within our model. We can already tell from the graph that it’s greater than 50%, but probably not much greater. How could we quantify it?</p>
<p>We’d need to know the <em>probability one beta distribution is greater than another</em>. This question is not trivial to answer, and I’m going to illustrate four routes that are common lines of attack in a Bayesian problem:</p>
<ul>
<li>Simulation of posterior draws</li>
<li>Numerical integration</li>
<li>Closed-form solution</li>
<li>Closed-form approximation</li>
</ul>
<p>Which of these approaches you choose depends on your particular problem, as well as your computational constraints. In many cases an exact closed-form solution may not be known or even exist. In some cases (such as running machine learning in production) you may be heavily constrained for time, while in others (such as drawing conclusions for a scientific paper) you care more about precision.</p>
<h4>Simulation of posterior draws</h4>
<p>If we don’t want to do any math today (I hear you), we could simply try simulation. We could use each player’s  and  parameters, draw a million items from each of them using <code>rbeta</code>, and compare the results:</p>
<figure>
<pre><code data-lang="r"><span>piazza_simulation</span> <span>&lt;-</span> <span>rbeta</span><span>(</span><span>1e6</span><span>,</span> <span>piazza</span><span>$</span><span>alpha1</span><span>,</span> <span>piazza</span><span>$</span><span>beta1</span><span>)</span>
<span>aaron_simulation</span> <span>&lt;-</span> <span>rbeta</span><span>(</span><span>1e6</span><span>,</span> <span>aaron</span><span>$</span><span>alpha1</span><span>,</span> <span>aaron</span><span>$</span><span>beta1</span><span>)</span>

<span>sim</span> <span>&lt;-</span> <span>mean</span><span>(</span><span>piazza_simulation</span> <span>></span> <span>aaron_simulation</span><span>)</span>
<span>sim</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 0.607</code></pre>
</figure>
<p>So about 60.7% probability Piazza is better than Aaron! An answer like this is often good enough, depending on your need for precision and the computational efficiency. You could turn up or down the number of draws depending on how much you value speed vs precision.</p>
<p>Notice we didn’t have to do any mathematical derivation or proofs. Even if we had a much more complicated model, the process for simulating from it would still have been pretty straightforward. This is one of the reasons Bayesian simulation approaches like MCMC have become popular: computational power has gotten very cheap, while doing math is as expensive as ever.</p>
<h4>Integration</h4>
<p>These two posteriors each have their own (independent) distribution, and together they form a <em>joint distribution</em>– that is, a density over particular pairs of  and . That joint distribution could be imagined as a density cloud:</p>
<p><img alt="center" src="http://i1.wp.com/varianceexplained.org/figs/2016-05-23-bayesian_ab_baseball/unnamed-chunk-6-1.png?w=456" data-recalc-dims="1"></p>
<p>Here, we’re asking what fraction of the joint probability density lies below that black line, where Piazza’s average is greater than Aaron’s. Notice that more of it lies below than above: that’s confirming the posterior probability that Piazza is better is about 60%.</p>
<p>The way to calculate this quantitatively is numerical integration, which is how <a target="_blank" href="https://web.archive.org/web/20150419163005/http://www.bayesianwitch.com/blog/2014/bayesian_ab_test.html">Chris Stucchio approaches the problem in this post</a> and <a target="_blank" href="https://gist.github.com/stucchio/9090456">this Python script</a>. A simple approach in R would be something like:</p>
<figure>
<pre><code data-lang="r"><span>d</span> <span>&lt;-</span> <span>.00002</span>
<span>limits</span> <span>&lt;-</span> <span>seq</span><span>(</span><span>.29</span><span>,</span> <span>.33</span><span>,</span> <span>d</span><span>)</span>
<span>sum</span><span>(</span><span>outer</span><span>(</span><span>limits</span><span>,</span> <span>limits</span><span>,</span> <span>function</span><span>(</span><span>x</span><span>,</span> <span>y</span><span>)</span> <span>{</span>
  <span>(</span><span>x</span> <span>></span> <span>y</span><span>)</span> <span>*</span>
    <span>dbeta</span><span>(</span><span>x</span><span>,</span> <span>piazza</span><span>$</span><span>alpha1</span><span>,</span> <span>piazza</span><span>$</span><span>beta1</span><span>)</span> <span>*</span>
    <span>dbeta</span><span>(</span><span>y</span><span>,</span> <span>aaron</span><span>$</span><span>alpha1</span><span>,</span> <span>aaron</span><span>$</span><span>beta1</span><span>)</span> <span>*</span>
    <span>d</span> <span>^</span> <span>2</span>
<span>}))</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 0.606</code></pre>
</figure>
<p>Like simulation, this is a bit on the “brute force” side. (And unlike simulation, the approach becomes intractable in problems that have many dimensions, as opposed to the two dimensions here).</p>
<h4>Closed-form solution</h4>
<p>You don’t need to be great at calculus to be a data scientist. But it’s useful to know how to find people that <em>are</em> great at calculus. When it comes to A/B testing, the person to find is often <a target="_blank" href="http://www.evanmiller.org/">Evan Miller</a>.</p>
<p><a target="_blank" href="http://www.evanmiller.org/bayesian-ab-testing.html#binary_ab_derivation">This post</a> lays out a closed-form solution Miller derived for the probability a draw from one beta distribution is greater than a draw from another:</p>
<p></p>
<p></p>
<p></p>
<p>(Where  is the <a target="_blank" href="https://en.wikipedia.org/wiki/Beta_function">beta function</a>). If you’d like an intuition behind this formula… well, you’re on your own. But it’s pretty straightforward to implement in R (I’m borrowing notation from <a target="_blank" href="https://www.chrisstucchio.com/blog/2014/bayesian_ab_decision_rule.html">this post</a> and calling it ):</p>
<figure>
<pre><code data-lang="r"><span>h</span> <span>&lt;-</span> <span>function</span><span>(</span><span>alpha_a</span><span>,</span> <span>beta_a</span><span>,</span>
              <span>alpha_b</span><span>,</span> <span>beta_b</span><span>)</span> <span>{</span>
  <span>j</span> <span>&lt;-</span> <span>seq.int</span><span>(</span><span>0</span><span>,</span> <span>round</span><span>(</span><span>alpha_b</span><span>)</span> <span>-</span> <span>1</span><span>)</span>
  <span>log_vals</span> <span>&lt;-</span> <span>(</span><span>lbeta</span><span>(</span><span>alpha_a</span> <span>+</span> <span>j</span><span>,</span> <span>beta_a</span> <span>+</span> <span>beta_b</span><span>)</span> <span>-</span> <span>log</span><span>(</span><span>beta_b</span> <span>+</span> <span>j</span><span>)</span> <span>-</span>
               <span>lbeta</span><span>(</span><span>1</span> <span>+</span> <span>j</span><span>,</span> <span>beta_b</span><span>)</span> <span>-</span> <span>lbeta</span><span>(</span><span>alpha_a</span><span>,</span> <span>beta_a</span><span>))</span>
  <span>1</span> <span>-</span> <span>sum</span><span>(</span><span>exp</span><span>(</span><span>log_vals</span><span>))</span>
<span>}</span>

<span>h</span><span>(</span><span>piazza</span><span>$</span><span>alpha1</span><span>,</span> <span>piazza</span><span>$</span><span>beta1</span><span>,</span>
  <span>aaron</span><span>$</span><span>alpha1</span><span>,</span> <span>aaron</span><span>$</span><span>beta1</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 0.608</code></pre>
</figure>
<p>Having an exact solution is pretty handy!<sup><a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fn:exactc">3</a></sup> So why did we even look at simulation/integration approaches? Well, the downsides are:</p>
<ul>
<li><em>Not every problem has a solution like this.</em> And even if it does, we may not know it. That’s why it’s worth knowing how to run a simulation. (If nothing else, they let us check our math!)</li>
<li><em>This solution is slow for large , and not straightforward to vectorize</em>: notice that term that iterates from 0 to . If we run A/B tests with thousands of clicks, this step is going to constrain us (though it’s still usually faster than simulation or integration).</li>
</ul>
<h4>Closed-form approximation</h4>
<p>As <a target="_blank" href="http://www.johndcook.com/fast_beta_inequality.pdf">this report points out</a>, there’s a much faster approximation we can use. Notice that when  and  are both fairly large, the beta starts looking a lot like a normal distribution, so much so that it can be closely approximated. In fact, if you draw the normal approximation to the two players we’ve been considering (shown as dashed line), they are <em>visually indistinguishable</em>:</p>
<p><img alt="center" src="http://i2.wp.com/varianceexplained.org/figs/2016-05-23-bayesian_ab_baseball/unnamed-chunk-8-1.png?w=456" data-recalc-dims="1"></p>
<p>And the probability one normal is greater than another is <em>very easy to calculate</em>– much easier than the beta!</p>
<figure>
<pre><code data-lang="r"><span>h_approx</span> <span>&lt;-</span> <span>function</span><span>(</span><span>alpha_a</span><span>,</span> <span>beta_a</span><span>,</span>
                     <span>alpha_b</span><span>,</span> <span>beta_b</span><span>)</span> <span>{</span>
  <span>u1</span> <span>&lt;-</span> <span>alpha_a</span> <span>/</span> <span>(</span><span>alpha_a</span> <span>+</span> <span>beta_a</span><span>)</span>
  <span>u2</span> <span>&lt;-</span> <span>alpha_b</span> <span>/</span> <span>(</span><span>alpha_b</span> <span>+</span> <span>beta_b</span><span>)</span>
  <span>var1</span> <span>&lt;-</span> <span>alpha_a</span> <span>*</span> <span>beta_a</span> <span>/</span> <span>((</span><span>alpha_a</span> <span>+</span> <span>beta_a</span><span>)</span> <span>^</span> <span>2</span> <span>*</span> <span>(</span><span>alpha_a</span> <span>+</span> <span>beta_a</span> <span>+</span> <span>1</span><span>))</span>
  <span>var2</span> <span>&lt;-</span> <span>alpha_b</span> <span>*</span> <span>beta_b</span> <span>/</span> <span>((</span><span>alpha_b</span> <span>+</span> <span>beta_b</span><span>)</span> <span>^</span> <span>2</span> <span>*</span> <span>(</span><span>alpha_b</span> <span>+</span> <span>beta_b</span> <span>+</span> <span>1</span><span>))</span>
  <span>pnorm</span><span>(</span><span>0</span><span>,</span> <span>u2</span> <span>-</span> <span>u1</span><span>,</span> <span>sqrt</span><span>(</span><span>var1</span> <span>+</span> <span>var2</span><span>))</span>
<span>}</span>

<span>h_approx</span><span>(</span><span>piazza</span><span>$</span><span>alpha1</span><span>,</span> <span>piazza</span><span>$</span><span>beta1</span><span>,</span> <span>aaron</span><span>$</span><span>alpha1</span><span>,</span> <span>aaron</span><span>$</span><span>beta1</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## [1] 0.607</code></pre>
</figure>
<p>This calculation is very fast, and (in R terms) it’s <em>vectorizable</em>.</p>
<p>The disadvantage is that for low  or low , the normal approximation to the beta is going to fit rather poorly. While the simulation and integration approaches were inexact, this one will be <em>systematically biased</em>: in some cases it will always give too high an answer, and in some cases too low. But when we have priors  and , as we do here, our parameters are never going to be low, so we’re safe using it.</p>
<h3>Confidence and credible intervals</h3>
<p>In classical (frequentist) statistics, you may have seen this kind of “compare two proportions” problem before, perhaps laid out as a “contingency table”:</p>
<table>
<thead>
<tr>
<th>Player</th>
<th>Hits</th>
<th>Misses</th>
</tr>
</thead>
<tbody>
<tr>
<td>aaronha01</td>
<td>3771</td>
<td>8593</td>
</tr>
<tr>
<td>piazzmi01</td>
<td>2127</td>
<td>4784</td>
</tr>
</tbody>
</table>
<p>One of the most common classical ways to approach these contingency table problems is with Pearson’s chi-squared test, implemented in R as <code>prop.test</code>:</p>
<figure>
<pre><code data-lang="r"><span>prop.test</span><span>(</span><span>two_players</span><span>$</span><span>H</span><span>,</span> <span>two_players</span><span>$</span><span>AB</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## 
## 	2-sample test for equality of proportions with continuity
## 	correction
## 
## data:  two_players$H out of two_players$AB
## X-squared = 0.1, df = 1, p-value = 0.7
## alternative hypothesis: two.sided
## 95 percent confidence interval:
##  -0.0165  0.0109
## sample estimates:
## prop 1 prop 2 
##  0.305  0.308</code></pre>
</figure>
<p>We see a non-significant p-value of .70. We won’t talk about p-values here (we talked a little about ways to translate between p-values and posterior probabilities in <a target="_blank" href="http://varianceexplained.org/statistics/beta_distribution_and_baseball">the last post</a>). But we can agree it would have been strange if the p-value were significant, given that the posterior distributions overlapped so much.</p>
<p>Something else useful that <code>prop.test</code> gives you is a confidence interval for the difference between the two players. We learned in <a target="_blank" href="http://varianceexplained.org/r/credible_intervals_baseball">a previous post</a> about <strong>credible intervals</strong> in terms of each player’s average. Now we’ll use empirical Bayes to compute the credible interval about the <em>difference</em> in these two players.</p>
<p>We could do this with simulation or integration, but let’s use our normal approximation approach (we’ll also compute our posterior probability while we’re at it):</p>
<figure>
<pre><code data-lang="r"><span>credible_interval_approx</span> <span>&lt;-</span> <span>function</span><span>(</span><span>a</span><span>,</span> <span>b</span><span>,</span> <span>c</span><span>,</span> <span>d</span><span>)</span> <span>{</span>
  <span>u1</span> <span>&lt;-</span> <span>a</span> <span>/</span> <span>(</span><span>a</span> <span>+</span> <span>b</span><span>)</span>
  <span>u2</span> <span>&lt;-</span> <span>c</span> <span>/</span> <span>(</span><span>c</span> <span>+</span> <span>d</span><span>)</span>
  <span>var1</span> <span>&lt;-</span> <span>a</span> <span>*</span> <span>b</span> <span>/</span> <span>((</span><span>a</span> <span>+</span> <span>b</span><span>)</span> <span>^</span> <span>2</span> <span>*</span> <span>(</span><span>a</span> <span>+</span> <span>b</span> <span>+</span> <span>1</span><span>))</span>
  <span>var2</span> <span>&lt;-</span> <span>c</span> <span>*</span> <span>d</span> <span>/</span> <span>((</span><span>c</span> <span>+</span> <span>d</span><span>)</span> <span>^</span> <span>2</span> <span>*</span> <span>(</span><span>c</span> <span>+</span> <span>d</span> <span>+</span> <span>1</span><span>))</span>
  
  <span>mu_diff</span> <span>&lt;-</span> <span>u2</span> <span>-</span> <span>u1</span>
  <span>sd_diff</span> <span>&lt;-</span> <span>sqrt</span><span>(</span><span>var1</span> <span>+</span> <span>var2</span><span>)</span>
  
  <span>data_frame</span><span>(</span><span>posterior</span> <span>=</span> <span>pnorm</span><span>(</span><span>0</span><span>,</span> <span>mu_diff</span><span>,</span> <span>sd_diff</span><span>),</span>
             <span>estimate</span> <span>=</span> <span>mu_diff</span><span>,</span>
             <span>conf.low</span> <span>=</span> <span>qnorm</span><span>(</span><span>.025</span><span>,</span> <span>mu_diff</span><span>,</span> <span>sd_diff</span><span>),</span>
             <span>conf.high</span> <span>=</span> <span>qnorm</span><span>(</span><span>.975</span><span>,</span> <span>mu_diff</span><span>,</span> <span>sd_diff</span><span>))</span>
<span>}</span>

<span>credible_interval_approx</span><span>(</span><span>piazza</span><span>$</span><span>alpha1</span><span>,</span> <span>piazza</span><span>$</span><span>beta1</span><span>,</span> <span>aaron</span><span>$</span><span>alpha1</span><span>,</span> <span>aaron</span><span>$</span><span>beta1</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## Source: local data frame [1 x 4]
## 
##   posterior estimate conf.low conf.high
##       (dbl)    (dbl)    (dbl)     (dbl)
## 1     0.607 -0.00185  -0.0152    0.0115</code></pre>
</figure>
<p>It’s not particularly exciting for this Piazza/Aaron comparison (notice it’s very close to the confidence interval we calculated with <code>prop.test</code>). So let’s select 20 random players, and compare each of them to Mike Piazza. We’ll also calculate the confidence interval using <code>prop.test</code>, and compare them.</p>
<p><img alt="center" src="http://i0.wp.com/varianceexplained.org/figs/2016-05-23-bayesian_ab_baseball/unnamed-chunk-12-1.png?w=456" data-recalc-dims="1"></p>
<p>Notice the same pattern we saw in the <a target="_blank" href="http://varianceexplained.org/r/credible_intervals_baseball">credible intervals post</a>. When we don’t have a lot of information about a player, their credible interval ends up smaller than their confidence interval, because we’re able to use the prior to adjust our expectations (Dad Lytle’s batting average may be lower than Mike Piazza’s, but we’re confident it’s not .25 lower). When we do have a lot of information, the credible intervals and confidence intervals converge almost perfectly.<sup><a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fn:derivation">4</a></sup></p>
<p>Thus, we can think of empirical Bayes A/B credible intervals as being a way to “shrink” frequentist confidence intervals, by sharing power across players.</p>
<h3>Bayesian FDR control</h3>
<p>Suppose we were a manager considering trading Piazza for another player (and suppose we could pick anyone from history). How many players in MLB history are we confident are better than Mike Piazza?</p>
<p>Well, we can compute the posterior probability and credible interval for each of them.</p>
<figure>
<pre><code data-lang="r"><span>career_eb_vs_piazza</span> <span>&lt;-</span> <span>bind_cols</span><span>(</span>
  <span>career_eb</span><span>,</span>
  <span>credible_interval_approx</span><span>(</span><span>piazza</span><span>$</span><span>alpha1</span><span>,</span> <span>piazza</span><span>$</span><span>beta1</span><span>,</span>
                           <span>career_eb</span><span>$</span><span>alpha1</span><span>,</span> <span>career_eb</span><span>$</span><span>beta1</span><span>))</span> <span>%>%</span>
  <span>select</span><span>(</span><span>name</span><span>,</span> <span>posterior</span><span>,</span> <span>conf.low</span><span>,</span> <span>conf.high</span><span>)</span>

<span>career_eb_vs_piazza</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## Source: local data frame [10,388 x 4]
## 
##                    name posterior conf.low conf.high
##                   (chr)     (dbl)    (dbl)     (dbl)
## 1               Ty Cobb  7.63e-17   0.0441    0.0716
## 2        Rogers Hornsby  2.81e-11   0.0345    0.0640
## 3  Shoeless Joe Jackson  8.42e-08   0.0279    0.0613
## 4           Ross Barnes  3.61e-05   0.0214    0.0633
## 5          Ed Delahanty  7.03e-07   0.0219    0.0518
## 6          Tris Speaker  1.57e-07   0.0225    0.0505
## 7          Ted Williams  1.45e-06   0.0206    0.0504
## 8        Billy Hamilton  6.91e-06   0.0190    0.0503
## 9          Levi Meyerle  4.01e-03   0.0087    0.0580
## 10       Harry Heilmann  7.15e-06   0.0180    0.0476
## ..                  ...       ...      ...       ...</code></pre>
</figure>
<p>While Piazza is an excellent batter, it looks like some do give him a run for his money. For instance, Ty Cobb has a batting average that’s about .04%-.07% better, with only a miniscule posterior probability that we’re wrong.</p>
<p>In order to get a set of players we’re confident are better (a set of candidates for trading), we can use the same approach to setting a false discovery rate (FDR) that we did in <a target="_blank" href="http://varianceexplained.org/r/bayesian_fdr_baseball/">this post</a>: taking the cumulative mean of the posterior error probability to compute the q-value.</p>
<figure>
<pre><code data-lang="r"><span>career_eb_vs_piazza</span> <span>&lt;-</span> <span>career_eb_vs_piazza</span> <span>%>%</span>
  <span>arrange</span><span>(</span><span>posterior</span><span>)</span> <span>%>%</span>
  <span>mutate</span><span>(</span><span>qvalue</span> <span>=</span> <span>cummean</span><span>(</span><span>posterior</span><span>))</span></code></pre>
</figure>
<p>Recall that the way we find a set of hypotheses with a given false discovery rate (FDR) is by filtering for a particular q-value:</p>
<figure>
<pre><code data-lang="r"><span>better</span> <span>&lt;-</span> <span>career_eb_vs_piazza</span> <span>%>%</span>
  <span>filter</span><span>(</span><span>qvalue</span> <span>&lt;</span> <span>.05</span><span>)</span>

<span>better</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## Source: local data frame [65 x 5]
## 
##                    name posterior conf.low conf.high   qvalue
##                   (chr)     (dbl)    (dbl)     (dbl)    (dbl)
## 1               Ty Cobb  7.63e-17   0.0441    0.0716 7.63e-17
## 2        Rogers Hornsby  2.81e-11   0.0345    0.0640 1.41e-11
## 3  Shoeless Joe Jackson  8.42e-08   0.0279    0.0613 2.81e-08
## 4          Tris Speaker  1.57e-07   0.0225    0.0505 6.03e-08
## 5          Ed Delahanty  7.03e-07   0.0219    0.0518 1.89e-07
## 6          Ted Williams  1.45e-06   0.0206    0.0504 3.99e-07
## 7         Willie Keeler  4.62e-06   0.0183    0.0473 1.00e-06
## 8        Billy Hamilton  6.91e-06   0.0190    0.0503 1.74e-06
## 9        Harry Heilmann  7.15e-06   0.0180    0.0476 2.34e-06
## 10           Lou Gehrig  1.43e-05   0.0167    0.0461 3.54e-06
## ..                  ...       ...      ...       ...      ...</code></pre>
</figure>
<p>This gives us 65 players we can say are better than Piazza, with an FDR of 5%. (That is, we expect we’re wrong on about 5% of this list of players).</p>
<h3>What’s Next: Hierarchical modeling</h3>
<p>We’re treating all baseball players as making up one homogeneous pool, whether they played in 1916 or 2016, and whether they played for the New York Yankees or the Chicago Cubs. This is mathematically convenient, but it’s ignoring a lot of information about players. One especially important piece of information it’s ignoring is how long someone played. Someone who’s been up to bat 5 or 6 times is generally <em>not</em> as good as someone with a 10-year career. This leads to a substantial bias where empirical Bayes tends to overestimate players with very few at-bats.</p>
<p>In the next post, we’ll talk about <strong>Bayesian hierarchical modeling</strong>, where rather than every player having the same prior, we allow the prior to depend on other known information. This will get us more accurate and reliable batting average estimates, while also extracting useful insights about factors that influence batters.</p>
<h3>Further Reading</h3>
<p>Above I’ve linked to a few great posts about Bayesian A/B testing, but here they are rounded up:</p>
<ul>
<li><a target="_blank" href="https://web.archive.org/web/20150419163005/http://www.bayesianwitch.com/blog/2014/bayesian_ab_test.html">Agile A/B testing with Bayesian Statistics and Python</a>, by Chris Stucchio (the Bayesian Witch site appears to be down, so this links to an Internet Archive version)</li>
<li><a target="_blank" href="http://www.evanmiller.org/bayesian-ab-testing.html">A Formula for Bayesian A/B Testing</a>, by Evan Miller</li>
<li><a target="_blank" href="https://www.chrisstucchio.com/blog/2014/bayesian_ab_decision_rule.html">Easy Evaluation of Decision Rules in Bayesian A/B testing</a>, by Chris Stucchio</li>
</ul>
<h3>Footnotes</h3>
<div>
<ol>
<li>
<p>The differences between frequentist and Bayesian A/B testing is a topic I’ve <a target="_blank" href="http://varianceexplained.org/r/bayesian-ab-testing/">blogged about before</a>, particularly about the problem of early stopping <a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fnref:bayesianAB">↩</a></p>
</li>
<li>
<p>Don’t forget that I’m focusing on the elementary statistical concepts, not the baseball, in these posts. I’m not actually any good at sabermetrics- in a real analysis comparing players, you would control for many factors like the pitchers each faced and the stadiums they played in. <a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fnref:sabermetrics">↩</a></p>
</li>
<li>
<p>Note that this solution is exact only for integer values of : we’re rounding it here, which is a trivial difference in most of our examples but may matter in others. <a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fnref:exactc">↩</a></p>
</li>
<li>
<p>This can be derived mathematically, based on the fact that <code>prop.test</code>’s confidence interval is in fact very similar to our normal approximation along with an uninformative prior and a small continuity correction, but it’s left as an exercise for the reader. <a target="_blank" href="http://varianceexplained.org/r/bayesian_ab_baseball/#fnref:derivation">↩</a></p>
</li>
</ol>
</div>
<p><div><div><div><div data-width="55" data-show-faces="false" data-send="true" data-layout="box_count" data-height="62" data-href="http://www.r-bloggers.com/understanding-bayesian-ab-testing-using-baseball-statistics/"></div></div><div><a data-url="http://www.r-bloggers.com/understanding-bayesian-ab-testing-using-baseball-statistics/" data-counturl="http://www.r-bloggers.com/understanding-bayesian-ab-testing-using-baseball-statistics/" data-count="vertical" data-text="Understanding Bayesian A/B testing (using baseball statistics)" class="twitter-share-button" data-via="rbloggers" href="https://twitter.com/share"></a></div><div></div></div><div></div></div>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://varianceexplained.org/r/bayesian_ab_baseball/"> Variance Explained</a></strong>.</div>
<hr>
<a rel="nofollow" href="http://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="http://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="http://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="http://www.r-bloggers.com/?s=data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="http://www.r-bloggers.com/?s=Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="http://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="http://www.r-bloggers.com/?s=map">maps</a>, <a title="Animation in R" rel="nofollow" href="http://www.r-bloggers.com/?s=animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="http://www.r-bloggers.com/?s=sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="http://www.r-bloggers.com/?s=LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="http://www.r-bloggers.com/?s=SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="http://www.r-bloggers.com/?s=eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="http://www.r-bloggers.com/?s=git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="http://www.r-bloggers.com/?s=hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="http://www.r-bloggers.com/?s=Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="http://www.r-bloggers.com/?s=regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="http://www.r-bloggers.com/?s=PCA">PCA</a>, <a title="Time series" rel="nofollow" href="http://www.r-bloggers.com/?s=time+series">time series</a>, <a title="finance trading" rel="nofollow" href="http://www.r-bloggers.com/?s=trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/QwkRme2TAQw"></a></div>