比率の差の検定におけるサンプルサイズの計算
概要
A/B テストなど、比率の差を検定する場合に、検定を行うのに十分なサンプルサイズを算出する以下式については、ネットを検索すると日本語のページもいくつか見つかります[1] (各変数の意味については後述します)。
ですが、この式の導出方法についてはネットを検索してもなかなか見つけることができなかったため、導出方法についてまとめ、また実際に Python で計算してみました。
動機
A/B テストでは、二つの施策 A と B のいずれかをユーザに提示し、A と B のどちらでよりユーザが反応するか検証します[2]。両施策でどちらがより効果があったかは、両施策における反応率の差の検定で確認することができます。
A/B テストを実施するときに、検定において十分な検出力 (施策 A と B の反応率に差があったときに、それを検知できる確率) を保証するためには、全部で何人のユーザに施策を提示すればよいかを知る必要があります。
これは比率の差の検定を実施する場合の、所望の検出力を達成するために必要なサンプルサイズを求めることと同義となります。
検定の設定
今二つの二項母集団があり、各々は母比率
であり、
比率の差の検定では帰無仮説を
で与えられ、これは標準正規分布します。ただし今回は帰無仮説を
ここで A/B テストの場合、両群のサンプルサイズが等しい (
サンプルサイズの算出
この検定では有意水準
また、対立仮説
従って検出力
例
サンプルサイズを求める関数を Python で実装してみます[5]。
import math
from scipy.stats import norm
def sample_power_probtest(
p1: float,
p2: float,
power: float = 0.8,
sig: float = 0.05
) -> int:
z_half_alpha = norm.isf([sig / 2])
z_beta = -1 * norm.isf([power])
p = (p1 + p2) / 2
return math.ceil(
(2 * p * (1 - p) * ((z_half_alpha + z_beta) ** 2))
/ ((p1 - p2) ** 2)
)
ここで scipy.stats.norm.isf
は生存関数の逆関数 (Inverse survival function) です。生存関数は norm.isf([sig / 2])
により
同様に nprm.isf([power])
は、
A/B テストを実施する場合に、A 群の比率が
sample_power_probtest(0.1, 0.11) # >>>> 14752
よって A/B テストを仮定した場合、
仮に B 群の比率が
sample_power_probtest(0.1, 0.12) # >>>> 3843
statsmodels.stats.power での計算
statsmodels.stats.power には同等の計算をする関数があります。
import math
from statsmodels.stats.power import normal_sample_size_one_tail
p1 = 0.1
p2 = 0.11
p = (p1 + p2) / 2
std = math.sqrt(2 * p * (1 - p))
normal_sample_size_one_tail(
diff=0.1 - 0.11,
power=0.8,
alpha=0.05 / 2,
std_null=std,
std_alternative=std,
) # >>>> 14751.969460709131
-
Wang, Hansheng, and Shein‐Chung Chow. “Sample size calculation for comparing proportions.” Encyclopedia of Statistical Sciences (2004): 1-14. ↩︎
-
stack overflow - Is there a python (scipy) function to determine parameters needed to obtain a target power? ↩︎
Discussion