なぜA/Bは形骸化するのか ― 自分で実験を回す前に
A/Bテストは多くの企業が回していますが、「途中で止めて誤判定」「サンプル不足」「指標設計の不在」といった理由で形骸化しがちです。観測データから因果に迫る因果連載に対し、本連載は介入を設計して因果を測る側。連載の地図と棲み分けを示します。
by Shin
A/Bを回しているのに、なぜ意思決定が当たらないのか。多くの場合、答えは「ツールが悪い」ではなく「統計の使い方が形骸化している」です。「途中で止める(peeking)」「サンプルが足りない」「何を成功とするか先に決めていない」——この3つだけで、有意差は簡単に誤読されます。この連載は、観測データから因果に迫る因果編と互いを補う記事として、自分で実験を設計して回す側の統計と基盤を扱います。第0回では、A/Bが形骸化する典型と、連載全体の地図、そして因果連載との棲み分けを先に示します。
最初に断っておくと、本稿は「A/Bは無意味だ」という煽りではありません。むしろ逆で、正しく回せばA/Bは介入因果を最短距離で取れる強力な道具です。ただし、それは統計の前提を踏んだときの話で、踏まないまま回すと「数字は出るが意思決定には使えない実験」が量産されます。ここを立て直すのが連載の目的です。
A/Bが形骸化する3つの理由
形骸化の原因は無数にあるように見えて、実務では3つに集約できます。順に、覗き見(peeking)・サンプル不足・指標設計の不在です。最初の2つは数字で確かめられるので、シミュレーションで一次データを出しながら見ます。
覗き見(peeking)で誤判定
最も多く、最も自覚されにくい事故が覗き見です。実験を走らせながら結果を何度も覗き、「有意になった瞬間に止める」と、偽陽性率(本当は差が無いのに「差あり」と誤判定する確率)が跳ね上がります。
直感的には「何度も判定すれば、当たりやすくなる」のと同じことが偽陽性側で起きます。検定は1回の判定で偽陽性を 5%(有意水準 alpha = 0.05)に抑える設計なので、独立に近い判定を何度も繰り返せば、そのどこかで偶然 5% を引く確率は累積していきます。
実際に、真の差が無いA/Aテスト(両群とも同じCVR 5%)で、覗く回数だけを変えて偽陽性率を測ったのが次のコードです。
import numpy as np
from scipy import stats
rng = np.random.default_rng(42)
def peeking_fpr(n_looks, n_sim=3000, n_per_group=20000, p=0.05, alpha=0.05):
"""真の差がないA/Aテストで、n_looks回覗いて初めて有意になった時点で
止めた場合の偽陽性率を返す。"""
hits = 0
for _ in range(n_sim):
a = rng.binomial(1, p, n_per_group)
b = rng.binomial(1, p, n_per_group)
looks = np.linspace(n_per_group // n_looks, n_per_group, n_looks).astype(int)
for k in looks:
ca, cb = a[:k].sum(), b[:k].sum()
pbar = (ca + cb) / (2 * k)
se = np.sqrt(pbar * (1 - pbar) * (2 / k))
z = (ca / k - cb / k) / se
pval = 2 * (1 - stats.norm.cdf(abs(z)))
if pval < alpha: # 有意になった瞬間に止める=peeking
hits += 1
break
return hits / n_sim
for nl in (1, 5, 10, 20):
print(f"{nl:>2}回覗く: 偽陽性率 {peeking_fpr(nl):.1%}")手元での実行結果(一次データ・乱数により多少ぶれます)が以下です。
| 覗く回数 | 偽陽性率 |
|---|---|
| 1回(最後だけ判定) | 約 5% |
| 5回 | 約 13% |
| 10回 | 約 18〜20% |
| 20回 | 約 25% |
最後に1回だけ判定すれば偽陽性は名目どおり約 5% に収まります。ところが10回覗いて止めると約2割、20回覗くと約4分の1まで膨らみます。「毎日ダッシュボードを見て、勝った瞬間にリリースを決めている」運用は、構造的にこの右側にいます。差が無い施策の2割前後を「効いた」と誤認していれば、意思決定が当たらないのは当然です。
サンプル不足
次に多いのが、そもそも検出したい差に対してサンプルが足りていないケースです。「2週間回したが有意差が出なかった=効果が無い」という結論は、しばしば「効果を検出できるだけの件数を集めていなかった」だけです。差が無いことと、差を見つけられないことは別物です。
必要サンプル数は、見たい差の大きさ(最小検出効果=MDE)の2乗にほぼ反比例します。式で言えば で、小さな差を見ようとするほど必要件数は急激に増えます。ベースラインCVR 5%、検出力80%、alpha = 0.05 で逆算したのが次です。
import numpy as np
from scipy import stats
def sample_size(p1, p2, alpha=0.05, power=0.8):
"""2標本の比率差を検出するのに必要な1群あたりサンプル数。"""
z_a = stats.norm.ppf(1 - alpha / 2)
z_b = stats.norm.ppf(power)
pbar = (p1 + p2) / 2
num = (z_a * np.sqrt(2 * pbar * (1 - pbar))
+ z_b * np.sqrt(p1 * (1 - p1) + p2 * (1 - p2))) ** 2
return num / (p1 - p2) ** 2
base = 0.05
for rel in (0.30, 0.20, 0.10, 0.05):
n = sample_size(base, base * (1 + rel))
print(f"相対+{int(rel*100)}%: 1群あたり約 {n:,.0f} 件")| 見たい差(相対) | CVR | 1群あたり必要件数 |
|---|---|---|
| +30%(5.0%→6.5%) | 大きい | 約 3,800 |
| +20%(5.0%→6.0%) | 中 | 約 8,200 |
| +10%(5.0%→5.5%) | 小 | 約 31,000 |
| +5%(5.0%→5.25%) | 微小 | 約 122,000 |
ここで読むべきは絶対値ではなく増え方です。検出したい差を半分(+10%→+5%)にすると、必要件数はほぼ4倍に跳ねます。多くのチームが期待する「数%の改善」を有意に検出するには、各群に数万件規模が要るということです。週あたりの流入がその水準に届かない施策で2週間だけ回しても、初めから検出力が足りていません。
指標設計の不在
3つ目は統計以前の問題です。「何をもって成功とするか」を実験の前に決めていないと、走らせた後に都合のいい指標を拾えてしまいます。CVRは動かなかったが滞在時間は伸びた、全体では差が無いが特定セグメントでは勝っている——こうした事後の指標選び・セグメント探しは、見るほど偽陽性を増やします(多重比較。第3回で扱います)。
成功の定義は、主要指標(北極星)を1つ、壊していないかを見張るガードレールを数個、実験前に固定するのが原則です。指標を後から選べる状態は、結論を後から選べる状態と同じで、そこに統計の厳密さを足しても土台が砂のままです。
観測 vs 介入(因果連載との棲み分け)
ここで連載どうしの役割を明確にしておきます。同じ「因果を測る」でも、入口が正反対だからです。
| 因果連載(観測) | 本連載(介入) | |
|---|---|---|
| 立ち位置 | 実験が打てない現場 | 自分で実験を設計する現場 |
| 反実仮想の作り方 | 観測データから推定(DiD・CausalImpact等) | ランダム割付で直接作る |
| 主な前提 | 比較可能な単位・明確な介入時点 | 十分なサンプル・分けられる単位 |
| 典型の構造 | 取引件数が少なく単一市場のB2B | 取引件数が多く割付可能なD2C/プロダクト |
因果連載は「ランダム化できない/実験が打てない」現場で、観測データから因果に迫る道具箱でした。本連載はその反対側——介入を自分で設計し、ランダム割付で反実仮想を直接作る側です。A/Bは原理的に最も強い因果測定で、できるならまずこちらを選ぶべきです。できない構造のときに観測手法へ降りる、という順序になります。
棲み分けは単純です。たとえばDiD(差分の差分)はユーザー単位で分けられないときの地域実験(第6回)の文脈で本連載にも出てきますが、観測データへの適用は因果連載に譲り、本連載では「介入設計としてどう割り付けるか」だけを扱います。
連載の地図
本連載は、実験を「設計 → 実行 → 効率化 → 分けられないときの設計 → 組織への定着」の順で降りていきます。各回の到達点を俯瞰しておきます。
| 回 | テーマ | この回で持ち帰るもの |
|---|---|---|
| 第1回 | 実験設計の統計 | 検出力・MDEから必要サンプル数を逆算できる |
| 第2回 | メトリクス設計 | 北極星・ガードレールを事前固定できる |
| 第3回 | A/Bの実務と罠 | 割付・SRM・多重比較の落とし穴を防げる |
| 第4回 | 逐次検定と覗き見 | いつ止めてよいかを設計できる |
| 第5回 | 分散削減(CUPED) | 少ないサンプルで検出力を稼げる |
| 第6回 | 地域実験・switchback | 分けられない施策の効果を測れる |
| 第7回 | 実験を意思決定と文化に | 単発の実験を組織の力に変えられる |
地図として押さえてほしいのは、第0回で挙げた3つの形骸化要因が、そのまま連載の骨格に対応していることです。サンプル不足は第1回・第5回で、覗き見は第4回で、指標設計の不在は第2回・第3回で、それぞれ手当てします。そして第4回の「逐次に学びながら止める」発想は、固定A/Bの先にある逐次最適化(バンディット)へ繋がり、ここはKaggle実務連載へ送り出します。最終回では実験を単発で終わらせず、因果連載・活性化連載まで含めた一連の流れに組み込みます。
章末チェックリスト
- 形骸化の3理由(覗き見・サンプル不足・指標未設計)を自社の運用で点検したか
- 結果を覗いて「勝った瞬間に止める」運用になっていないか
- 検出したい差に対して、必要サンプル数を見積もっているか
- 主要指標とガードレールを実験前に固定しているか
- 観測(因果連載)と介入(本連載)の違いを言えるか
- 連載の地図を俯瞰し、自社に効く回の見当をつけたか
次回(第1回)は、実験設計の統計から始めます。第一種・第二種の誤りを実務の言葉で整理し、検出力・MDE・有意水準から必要サンプル数を逆算する——走らせる前に件数を決める、形骸化しない実験の出発点です。実験が打てない構造で観測データから因果に迫る側は、対になる因果編(本記事のbridge先)へ。