TT Lab
はじめる
学ぶ 学習パス コース

開発者の起業 — 作る前に検証する

4つの実験をルールどおりに判定する

TT Labで続きを見る

目標

SRM・z検定・信頼区間・標本サイズ・Holm補正を、標準ライブラリで計算する関数を作り、4つの実験の結果を、決められたルールで判定します。

なぜ重要なのか

小さなチームのA/Bテストは、標本が少なく、毎日覗き込み、結果がなければ分けて見ます。3つとも、偶然を発見に変える習慣です。ルールを先に決めて、そのルールどおりに計算して初めて、実験が製品の意思決定を守ってくれます。

用意するもの

定義

ステップ

  1. /root/founder/ab/ab.pyに、srm(n_a, n_b) → {"chi2": x, "p": y}を作り、/root/founder/ab/srm.jsonに、exp1・exp2それぞれの{"a": n, "b": n, "chi2": x, "p": y, "srm": true/false}を書く。
  2. ab.pyに、ztest(ca, na, cb, nb) → {"diff", "z", "p", "ci_low", "ci_high"}を作る(ca・cbは転換数、na・nbはユーザー数)。
  3. /root/founder/ab/result.jsonに、exp1のa_users,a_conv,b_users,b_conv,diff,p,ci_low,ci_high,decisionを書く。
  4. ab.pyにsample_size(p_base, mde)を作り、/root/founder/ab/power.jsonに、baseline(exp1のAのコンバージョン率、小数第4位)、mde(0.01)、n_per_arm(= sample_size(baseline, 0.01))、exp1_min_arm(exp1の両側のユーザー数のうち小さいほう)、powered(exp1_min_arm ≥ n_per_arm)を書く。
  5. /root/founder/ab/peeking.jsonに、exp3のdaily_p(1日目から累積の合計で計算したp、21個)、first_significant_day(累積p < 0.05の最初の日、なければnull)、final_p、final_decision(最終日の累積値による判定)を書く。
  6. ab.pyに、holm(pvalues)(名前→pの辞書 → 棄却される名前のソート済みリスト)を作り、/root/founder/ab/multi.jsonに、exp4のp(v1–v5それぞれ、controlとの比較)、naive(p < 0.05の名前、ソート済み)、holmを書く。
  7. /root/founder/ab/segments.jsonに、exp1のセグメント10個それぞれのp、naive(p < 0.05、ソート済み)、holmを書く。
  8. /root/founder/ab/decision.jsonに、exp1(判定)、exp2_trustworthy(SRMがなければtrue)、exp3_decision(最終日の判定)、exp4_ship(Holmで棄却されたリスト)、segment_claims(Holmで棄却されたセグメントのリスト)を書く。

参考

標本の比率から確認する

/root/founder/ab/ab.pyにsrm(n_a, n_b)を作り、/root/founder/ab/srm.jsonに、exp1・exp2のa・b・chi2・p・srmを書く。

期待値は(n_a+n_b)/2です。自由度1のカイ二乗の裾の確率は、math.erfc(math.sqrt(chi2/2))で求められます。SRMの基準はp < 0.001です。

2つの比率のz検定と95%信頼区間

ab.pyにztest(ca, na, cb, nb)を作る。diff・z・p(両側)・ci_low・ci_highを小数第6位で。

検定統計量はプール比率の標準誤差、信頼区間は、それぞれの比率の標準誤差(非プール)です。Φはstatistics.NormalDist().cdf、臨界値はinv_cdf(0.975)です。

exp1を判定する

/root/founder/ab/result.jsonに、exp1のa_users・a_conv・b_users・b_conv・diff・p・ci_low・ci_high・decisionを書く。

判定ルール: p < 0.05で下限 > 0ならship_b、p < 0.05で上限 < 0ならkeep_a、それ以外はinconclusiveです。

この実験は、1%ポイントを捉えられるほど大きかったか

ab.pyにsample_size(p_base, mde)を作り、/root/founder/ab/power.jsonに、baseline・mde・n_per_arm・exp1_min_arm・poweredを書く。

p2 = p1 + mde、p̄ = (p1+p2)/2、zの値は、inv_cdf(0.975)とinv_cdf(0.8)です。かっこの中全体をmdeで割って2乗し、切り上げます。

A/A実験を毎日覗き込むと

/root/founder/ab/peeking.jsonに、exp3のdaily_p(累積21個)・first_significant_day・final_p・final_decisionを書く。

exp3_daily.csvは、その日の増分です。1日目から足していき、その日までの累積の合計で、ztestを呼んでください。日付は1から数えます。

バリアント5つ: Holm補正

ab.pyにholm(pvalues)を作り、/root/founder/ab/multi.jsonに、exp4のp(v1–v5)・naive・holmを書く。

各バリアントを、controlとztestします(controlがa側)。Holmは、昇順のk番目(0から)で、p·(m−k) ≤ 0.05を見て、最初に失敗したら止めます。

セグメント10個に分けて見ると

/root/founder/ab/segments.jsonに、exp1のセグメント10個のp・naive・holmを書く。

セグメントごとに、AとBを別々に数えて、同じztestを呼び、10個のpに同じholmを適用します。

実験ごとのデプロイ判断

/root/founder/ab/decision.jsonに、exp1・exp2_trustworthy・exp3_decision・exp4_ship・segment_claimsを書く。

前のステップのファイルから集めます。SRMがある実験は、信頼できない実験です。途中観察の反例の結論は、最初に有意になった日ではなく、最終日の判定です。