power_rng = np.random.default_rng(1515)
power_reps = 20_000
pooled_rate = (y30.sum() + y40.sum()) / (n30 + n40)
def simulate_binomial_difference(n_a, n_b, p_a, p_b):
return (
power_rng.binomial(n_a, p_a, power_reps) / n_a
- power_rng.binomial(n_b, p_b, power_reps) / n_b
)
# 50% mais jogadores em cada grupo, mantendo as taxas observadas.
large_n30 = round(1.5 * n30)
large_n40 = round(1.5 * n40)
large_null = simulate_binomial_difference(
large_n30, large_n40, pooled_rate, pooled_rate
)
large_alt = simulate_binomial_difference(
large_n30, large_n40, y30.mean(), y40.mean()
)
large_critical = np.quantile(np.abs(large_null), .95)
# Efeito de 1,00 p.p., mantendo o tamanho da amostra.
larger_effect = .010
effect_null = simulate_binomial_difference(
n30, n40, pooled_rate, pooled_rate
)
effect_alt = simulate_binomial_difference(
n30, n40, y40.mean() + larger_effect, y40.mean()
)
effect_critical = np.quantile(np.abs(effect_null), .95)
# Teste bilateral com alfa de 1%.
strict_critical = np.quantile(np.abs(null_perm), .99)
scenarios = [
(null_perm, boot_alt, critical, observed,
"Referência\nα = 5%"),
(large_null, large_alt, large_critical, observed,
"50% mais jogadores\nmesmo efeito"),
(effect_null, effect_alt, effect_critical, larger_effect,
"Efeito maior\nΔ = 1,00 p.p."),
(null_perm, boot_alt, strict_critical, observed,
"Teste mais rigoroso\nα = 1%"),
]
comparison_grid = np.linspace(-1.4, 2.0, 700)
fig, axes = plt.subplots(
2, 2, figsize=(11.5, 7.2), sharex=True, sharey=True
)
for index, (ax, scenario) in enumerate(zip(axes.flat, scenarios)):
null_values, alt_values, cutoff, effect, title = scenario
null_curve = gaussian_kde(100 * null_values)(comparison_grid)
alt_curve = gaussian_kde(100 * alt_values)(comparison_grid)
rejection = np.abs(comparison_grid) >= 100 * cutoff
scenario_power = np.mean(np.abs(alt_values) >= cutoff)
ax.plot(comparison_grid, null_curve, color="#0f6b78",
linewidth=2.5, label="$H_0$")
ax.plot(comparison_grid, alt_curve, color="#d95f02",
linewidth=2.5, label="$H_A$")
ax.fill_between(
comparison_grid, 0, alt_curve,
where=rejection, color="#d95f02", alpha=.30,
label="área do poder",
)
ax.axvline(-100 * cutoff, color="#17324d", linestyle="--",
label="limites críticos")
ax.axvline(100 * cutoff, color="#17324d", linestyle="--")
ax.axvline(100 * effect, color="#6a4c93", linewidth=2.2,
label="efeito sob $H_A$")
ax.set_title(title)
ax.text(.97, .92, f"poder = {scenario_power:.1%}",
transform=ax.transAxes, ha="right", va="top",
fontweight="bold")
if index % 2 == 0:
ax.set_ylabel("Densidade")
handles, labels = axes.flat[0].get_legend_handles_labels()
fig.supxlabel("Diferença de retenção em 7 dias (p.p.)", y=.075)
fig.legend(handles, labels, loc="lower center", ncol=5,
frameon=False, bbox_to_anchor=(.5, .005))
fig.tight_layout(rect=(0, .13, 1, 1))
plt.show()