A/Bテストの評価を簡単にブラウザ上でできるようにしたい。ということで実装してみた。
そういえばGoogleスプレッドシートでもカイ2乗検定はできないのね。
これを使えばスプレッドシートから値を持ってきて簡単に検定できるかも。
A/Bテストの技術的整理
A/Bテスト(2群の比率の差の検定)をするとき、比率を扱うので2項分布を使う方法もあるが、クロス表で扱うこともできる。
たとえば
creative | imp | click |
---|---|---|
A | $x_0$ | $x_1$ |
B | $x_2$ | $x_3$ |
において
クリエイティブAとBとでCTRが変わらない
すなわち
クリエイティブの違い(行)とクリックのしやすさ(列)は独立
かどうかを検定したい。一般に検定で用いられるクロス表は
グループ | ○○する | ○○しない |
---|---|---|
A | ||
B |
という形式になるので、
クリックのしやすさは「クリックする or クリックしない」だから
creative | クリックする | クリックしない | imp(周辺度数) |
---|---|---|---|
A | $x_0-x_1$ | $x_1$ | $x_0$ |
B | $x_2-x_3$ | $x_3$ | $x_2$ |
というクロス表の独立性の検定をすることになる。
実装
/**
* Returns p-value of x.
* @param {Array} x [[nTrial1, nOccurrence1], [nTrial2, nOccurrence2]]
* @returns {Number} p-value
*/
function getChisq(x){
if(x !== undefined){
// Observations
var o = [
x[0][0] - x[0][1],
x[0][1],
x[1][0] - x[1][1],
x[1][1],
];
var s = o[0]+o[1]+o[2]+o[3];
// Expectations
var e = [
(o[0]+o[1]) * (o[0]+o[2]) / s,
(o[0]+o[1]) * (o[1]+o[3]) / s,
(o[2]+o[3]) * (o[0]+o[2]) / s,
(o[2]+o[3]) * (o[1]+o[3]) / s,
];
var chisq = 0;
for (i=0; i<=3; i++){
chisq += (o[i] - e[i]) * (o[i] - e[i]) / e[i];
}
return chisq;
}
}
// Cumulative distribution function of Normal distribution
// See http://qiita.com/gigamori/items/e17e6f9faffb78822c56
function cdf(x) {
// constants
var p = 0.2316419;
var b1 = 0.31938153;
var b2 = -0.356563782;
var b3 = 1.781477937;
var b4 = -1.821255978;
var b5 = 1.330274429;
var t = 1 / (1 + p * Math.abs(x));
var Z = Math.exp(-x * x / 2) / Math.sqrt(2 * Math.PI);
var y = 1 - Z * ((((b5 * t + b4) * t + b3) * t + b2) * t + b1) * t;
return (x > 0) ? y : 1 - y;
}
// Example
cdf(Math.sqrt(getChisq([[10000,100],[5000,45]])));
cdf()
は正規分布の累積分布関数。自由度1のカイ2乗分布は平方根が片側標準正規分布になるのでcdf(Math.sqrt(...)
としている。
http://qiita.com/gigamori/items/e17e6f9faffb78822c56
GoogleスプレッドシートでABテスト
2x2のセルを指定して実行すればOK!
var values = SpreadsheetApp.getActiveSheet().getRange('A1:B2').getValues();
var p = cdf(Math.sqrt(getChisq(values)));
Logger.log(p);