を拝見した。こちらの記事は、Sample Ratio Mismatchの詳細についてわかりやすく解説がなされていた。
Sample Ratio Mismatchは以下のようなものだ。
なぜこれが起こったかを調べたところ、実験開始後に、A/Bテストに割り当てられたTreatmentユーザ数がControlユーザ数と比べて有意に少なかったことが原因でした。それが起こってしまった原因を特定し(後に理由はでてきます)、正しく検証した結果、期待どおりのPositiveな差を検出することができました。
まさにこの現象のこと、Sample Ratio Mismatch(SRM) と言います。つまり、A/Bテストのために割当したControl / Treatmentの2つの集団で、サンプルサイズが 期待どおりの比率で集まらなかった ことで、誤った結果を導いてしまう現象です。
「Control / Treatmentの2つの集団で、サンプルサイズが 期待どおりの比率で集まったかどうか」を検定したい。
この記事ではA/BテストのA群、B群が1:1になっていることを検定する方法について扱う。
検定方法は**「適合度検定」**である。
Pythonのscipy
ライブラリ内のscipy.stats.chisquare
を使うことで検定ができる。
例としてA/Bテストをしようとしていて、
A群が10000人のユーザー、B群が9900人のユーザーがいたとして、これが期待どおりの比率の1:1になっているかを検証する。
import scipy
a_num = 10000
b_num = 9900
expect = (a_num + b_num)/2
observed_values=scipy.array([a_num, b_num])
expected_values=scipy.array([expect, expect])
scipy.stats.chisquare(observed_values, f_exp=expected_values)
これを実行すると Power_divergenceResult(statistic=0.5025125628140703, pvalue=0.4783981994489356)
という結果を得られる。
統計量が0.503
でp値が0.47
。
有意水準を5%とすると、棄却できないため、A群とB群のサンプルには差がないと分かる。
試しに差がありそうなデータで実施してみる。
a_num = 10000
b_num = 9000
expect = (a_num + b_num)/2
observed_values=scipy.array([a_num, b_num])
expected_values=scipy.array([expect, expect])
scipy.stats.chisquare(observed_values, f_exp=expected_values)
Power_divergenceResult(statistic=52.63157894736842, pvalue=4.023672190684225e-13)
となり、p値が0.05未満であり、「差がある」つまりSRMが起こっていると言える。
JavaScriptでやる場合
JSの統計ライブラリであるjstatを利用する。
カイ二乗を算出し、分布表を参照する必要がある。
const jStat = require('jstat');
const a = 10000
const b = 9000
const expected = (a+b)/2
const statistics = (a - expected)**2 / expected + (b - expected)**2 / expected
// 52.63157894736842
const df = 1
const pValue = 1 - jStat.chisquare.cdf(chi_2, df)
// 4.0234482412415673e-13
参考
いくつかの検定
https://toukei.link/programmingandsoftware/statistics_by_python/chisqtest_by_python/