(注意:筆者は統計については素人レベルなので、この関数を利用した検定の正確性について保証することはできません)
ExcelやGoogleスプレッドシートではカイ二乗検定のためにCHISQ.TESTという関数がありますが、第1引数に観測度数の範囲、第2引数に期待度数の範囲を渡す必要があります。結果として、カイ二乗検定でのp値を返してくれます。
CHISQ.TEST(観測度数範囲, 期待度数範囲)
観測度数が分かれば期待度数も自明なのにわざわざ別々にデータを用意しなくてはいけないのが面倒くさかったので、観測度数から期待度数を返してくれるGoogleスプレッドシート関数をGoogle Apps Script(GAS)で作りました。備忘録として残しておきます。
function getExpectedFreq(range) {
/**
* 数値文字列の配列から合計値を計算するための内部関数。
* 整数へのparseに失敗したらエラーを投げる
*/
const sumStrArray = (arr) => (arr.reduce((prev, current) => {
const num = parseInt(current);
if (isNaN(num)) {
throw `failed to parse string to int: ${current}`;
} else {
return prev + current;
}
}, 0));
/* 整数の配列から合計値を計算するための内部関数 */
const sumIntArray = (arr) => (arr.reduce((prev, current) => prev + current));
/* スプレッドシートで渡された引数が配列だったら処理を続ける。配列ではなかったらエラーを返す */
if (Array.isArray(range)) {
/* 横(行)の周辺度数を計算する */
let marginX;
try {
marginX = range.map(row => sumStrArray(row));
} catch(e) {
throw e;
}
/* ref. [JavaScriptで二次元配列の行列を転置するワンライナー](https://qiita.com/kznr_luk/items/790f1b154d1b6d4de398) */
const transpose = a => a[0].map((_, c) => a.map(r => r[c]));
/* 縦(列)の周辺度数を計算する。計算のために行列を転置しておく */
const transposedRange = transpose(range);
let marginY;
try {
marginY = transposedRange.map(row => sumStrArray(row));
} catch(e) {
throw e;
}
/* 期待度数を計算する */
const sumY = sumIntArray(marginY);
return marginX.map(x => marginY.map(y => x * y / sumY));
} else {
throw 'expected range input, but got cell input';
}
}
こんな感じで使えます。
注意点
2x2のクロス集計表では上手く動作していそうなのを確認しました。それ以上の多次元配列でも正しく動作するように実装したつもりですが、ちゃんと試していないので保証はできません。
また、期待度数表のチェックは怠らないようにしましょう。期待度数が少ないと、カイ二乗検定が有効ではないと考えられるケースがあります。
その基準については諸説あるようですが、そのうち一つを引用にて紹介しておきます。
A.期待度数が1未満のセルがある
B.期待度数が5未満のセルが、全体のセルの20%以上ある
出典:独立性の検定―最もポピュラーなカイ二乗検定(統計WEB、2017年)
そして繰り返しになりますが、筆者は統計については素人レベルなので、この関数を利用した検定の正確性について保証することはできません。
(統計に詳しい方からのコメントをお待ちしています)