Skip to content

Commit

Permalink
Better commenting and function layout
Browse files Browse the repository at this point in the history
rjjfox committed Feb 27, 2021
1 parent 55f14cf commit 36e6552
Showing 2 changed files with 74 additions and 52 deletions.
83 changes: 49 additions & 34 deletions bayesian.py
Original file line number Diff line number Diff line change
@@ -32,8 +32,9 @@ class Bayesian(object):
Methods
-------
generate_posterior_samples
Creates samples for the posterior distributions for A and B and
their mean probabilities
Creates samples for the posterior distributions for A and B
calculate_probabilities
Calculate the likelihood that the variants are better
plot_bayesian_probabilities
Plots a horizontal bar chart of the likelihood of either variant being
the winner
@@ -54,6 +55,8 @@ def __init__(self, visitors_A, conversions_A, visitors_B, conversions_B):
self.relative_difference = self.variant_cr / self.control_cr - 1

def generate_posterior_samples(self):
"""Creates samples for the posterior distributions for A and B"""

alpha_prior = 1
beta_prior = 1

@@ -71,39 +74,26 @@ def generate_posterior_samples(self):
self.samples_posterior_A = posterior_A.rvs(samples)
self.samples_posterior_B = posterior_B.rvs(samples)

def calculate_probabilities(self):
"""Calculate the likelihood that the variants are better"""

self.prob_A = (self.samples_posterior_A > self.samples_posterior_B).mean()
self.prob_B = (self.samples_posterior_A <= self.samples_posterior_B).mean()

def plot_bayesian_probabilities(self, labels=["A", "B"]):
"""
Plots a horizontal bar chart of the likelihood of either variant being
the winner
"""

fig, ax = plt.subplots(figsize=(10, 4), dpi=150)

snsplot = ax.barh(
labels[::-1], [self.prob_B, self.prob_A], color=["#77C063", "#DC362D"]
)

ax.xaxis.grid(color="lightgrey")
ax.set_axisbelow(True)

ax.xaxis.set_major_formatter(mtick.PercentFormatter(1))
sns.despine(left=True, bottom=True)
ax.tick_params(axis="both", which="both", bottom=False, left=False)

ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.2,
"Bayesian test result",
**roboto_title,
)

ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.1,
"The bars show the likelihood of each variant being the better"
" experience",
**roboto,
)

# Value annotations conditional on size of bars
# Display the probabilities by the bars
# Parameters for ax.text based on relative bar sizes
if self.prob_A < 0.2:
A_xpos = self.prob_A + 0.01
A_alignment = "left"
@@ -126,6 +116,7 @@ def plot_bayesian_probabilities(self, labels=["A", "B"]):
B_alignment = "right"
B_color = "white"

# Plot labels using previous parameters
ax.text(
A_xpos,
snsplot.patches[1].get_y() + snsplot.patches[1].get_height() / 2.1,
@@ -134,7 +125,6 @@ def plot_bayesian_probabilities(self, labels=["A", "B"]):
color=A_color,
**roboto,
)

ax.text(
B_xpos,
snsplot.patches[0].get_y() + snsplot.patches[0].get_height() / 2.1,
@@ -144,11 +134,38 @@ def plot_bayesian_probabilities(self, labels=["A", "B"]):
**roboto,
)

# Title
ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.2,
"Bayesian test result",
**roboto_title,
)

# Subtitle
ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.1,
"The bars show the likelihood of each variant being the better"
" experience",
**roboto,
)

ax.xaxis.grid(color="lightgrey")
ax.set_axisbelow(True)
ax.xaxis.set_major_formatter(mtick.PercentFormatter(1))
sns.despine(left=True, bottom=True)
ax.tick_params(axis="both", which="both", bottom=False, left=False)
fig.tight_layout()

st.write(fig)

def plot_simulation_of_difference(self):
"""
Plots a histogram showing the distribution of the differences between
A and B highlighting how much of the difference shows a positve diff
vs a negative one.
"""

fig, ax = plt.subplots(figsize=(10, 5), dpi=150)

@@ -169,34 +186,32 @@ def plot_simulation_of_difference(self):
ax.yaxis.grid(color="lightgrey")
ax.set_axisbelow(True)
ax.set_ylabel("")

ax.set_xlabel("Relative conversion rate increase")

ax.get_yaxis().set_major_formatter(
mtick.FuncFormatter(lambda x, p: format(x / len(difference), ".0%"))
)

sns.despine(left=True)

ax.xaxis.set_major_formatter(mtick.PercentFormatter(1))

ax.tick_params(axis="both", which="both", length=0)
ax.tick_params(axis="y", colors="lightgrey")

# Title
ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.2,
"Posterior simulation of the difference",
**roboto_title,
)

# Subtitle
ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.12,
"Highlights the relative difference of the posterior" " distributions",
**roboto,
)

ax.xaxis.set_major_formatter(mtick.PercentFormatter(1))
ax.tick_params(axis="both", which="both", length=0)
ax.tick_params(axis="y", colors="lightgrey")
sns.despine(left=True)
fig.tight_layout()

st.write(fig)
43 changes: 25 additions & 18 deletions frequentist.py
Original file line number Diff line number Diff line change
@@ -232,6 +232,7 @@ def plot_power(self):

fig, ax = plt.subplots(figsize=(10, 5), dpi=150)

# Plot the distribution of A
xA = np.linspace(
self.control_cr - 4 * self.control_se,
self.control_cr + 4 * self.control_se,
@@ -240,6 +241,16 @@ def plot_power(self):
yA = scs.norm(self.control_cr, self.control_se).pdf(xA)
ax.plot(xA, yA, label="A")

# Plot the distribution of B
xB = np.linspace(
self.variant_cr - 4 * self.variant_se,
self.variant_cr + 4 * self.variant_se,
1000,
)
yB = scs.norm(self.variant_cr, self.variant_se).pdf(xB)
ax.plot(xB, yB, label="B")

# Label A at its apex
ax.text(
self.control_cr,
max(yA) * 1.03,
@@ -249,7 +260,17 @@ def plot_power(self):
**roboto_bold,
)

# Add critical value lines
# Label B at its apex
ax.text(
self.variant_cr,
max(yB) * 1.03,
"B",
color="tab:orange",
horizontalalignment="center",
**roboto_bold,
)

# Add critical value lines depending on two vs. one tail and left vs. right
if self.tail_direction == "left":
ax.axvline(
x=self.control_cr + self.control_se * self.z,
@@ -311,23 +332,6 @@ def plot_power(self):
**roboto_small,
)

xB = np.linspace(
self.variant_cr - 4 * self.variant_se,
self.variant_cr + 4 * self.variant_se,
1000,
)
yB = scs.norm(self.variant_cr, self.variant_se).pdf(xB)
ax.plot(xB, yB, label="B")

ax.text(
self.variant_cr,
max(yB) * 1.03,
"B",
color="tab:orange",
horizontalalignment="center",
**roboto_bold,
)

# Fill in the power and annotate
if self.variant_cr > self.control_cr:
ax.fill_between(
@@ -348,6 +352,7 @@ def plot_power(self):
alpha=0.2,
)

# Display power value on graph
ax.text(
ax.get_xlim()[0] + (ax.get_xlim()[1] - ax.get_xlim()[0]) * 0.8,
ax.get_ylim()[1] * 0.8,
@@ -356,13 +361,15 @@ def plot_power(self):
**roboto,
)

# Title
ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.25,
"Statistical power",
**roboto_title,
)

# Subtitle
ax.text(
ax.get_xlim()[0],
ax.get_ylim()[1] * 1.17,

0 comments on commit 36e6552

Please sign in to comment.