from scipy.stats import bernoulli
= 100
size_1 = 100
size_2
# the "true" CTR of both layouts
= 0.7
p_1 = 0.9
p_2
= bernoulli.rvs(p_1, size=size_1)
population_1 = bernoulli.rvs(p_2, size=size_2) population_2
A/B Testing
Running Example
A classical use-case of A/B tesing is optimizing the click through rate of a e-commerse website given different layout designs.
Some common questions we want to answer: - which layout is better ? - how many data should we collect ? - how much better ?
Generated Data
Assuming layout 2 is better and we generate data according to this assumption. Let’s try to analyze the generated data to recover our assumption.
Bayesian Analysis
Let’s model the CTR as a beta distribution since it is always between 0 and 1, and assume we know nothing about how the CTR look like and hence uniformly distributed across the interval [0,1]
import pymc as pm
import arviz as az
import matplotlib.pyplot as plt
"fivethirtyeight") az.style.use(
with pm.Model() as model:
= pm.Beta("ctr1", alpha=1, beta=1)
ctr1 = pm.Beta("ctr2", alpha=1, beta=1)
ctr2 = pm.Binomial("click1", p=ctr1, n=size_1, observed=sum(population_1))
click1 = pm.Binomial("click2", p=ctr2, n=size_2, observed=sum(population_2))
click2 = pm.Deterministic("diff", ctr2-ctr1)
diff = pm.sample() t
Auto-assigning NUTS sampler...
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [ctr1, ctr2]
100.00% [8000/8000 00:02<00:00 Sampling 4 chains, 0 divergences]
Sampling 4 chains for 1_000 tune and 1_000 draw iterations (4_000 + 4_000 draws total) took 2 seconds.
= plt.subplots(2, 1, figsize=(7, 7), sharex=True)
fig, axs "ctr1"], ax=axs[0])
az.plot_posterior(t.posterior[0].set_title("Click Trough Rate (Layout 1)", fontsize=20)
axs["ctr2"], ax=axs[1])
az.plot_posterior(t.posterior[1].set_title(C) axs[
Text(0.5, 1.0, 'Click Trough Rate (Layout 2)')
=["diff"])
az.plot_posterior(t, var_names"Difference between CTR", fontsize=20) plt.title(
Text(0.5, 1.0, 'Difference between CTR')