廿TT

譬如水怙牛過窓櫺 頭角四蹄都過了 因甚麼尾巴過不得

フィッシャーの検定がいいか、カイ二乗検定がいいか

クラシックな話題ですが、上記のツイートを見てやってシミュレーションをやってみようと思いました。

フィッシャーの検定(Fisherの正確確率検定)とカイ二乗検定については カイ二乗検定 | Logics of Blue などで丁寧に説明されています。

ある政策に賛成か反対か、男女10人に聞きました。

賛成 反対 合計
3 7 10
6 4 10
合計 9 11 20

こういう分割表についてカイ二乗検定をやるには R ではこうします。

mat <-matrix(c(3,7,6,4),byrow = TRUE,2,2)
chisq.test(mat)

結果はこんな感じ。

> chisq.test(mat)

	Pearson's Chi-squared test with Yates' continuity correction

data:  mat
X-squared = 0.80808, df = 1, p-value = 0.3687

 警告メッセージ: 
 chisq.test(mat):   カイ自乗近似は不正確かもしれません 

「カイ自乗近似は不正確かもしれません 」という警告がでてますね。
あえてこの標本サイズでいきましょう。

表の横合計は10、10で固定して、賛成・反対の確率(それぞれ p1、p2 とおく)を0.1から0.9まで、0.1ずつ変えてシミュレーションしました。

結果、5%水準で有意になった割合は以下の図のようになりました。

f:id:abrahamcow:20180221223343p:plain

まず注目すべきは、色付きテーブルの対角線上です。ここは p1 と p2 が等しい、つまり帰無仮説がただしい状況をシミュレートしています。

帰無仮説がただしい状況で(まちがって)帰無仮説を棄却しちゃう確率をアルファエラーと呼びます。

検定で最も大事なのはアルファエラーが名目上の値と同程度に保たれるかどうかです。

5%水準で検定したときにまちがって5%よりも多く棄却しちゃうような検定はオオカミ少年なので、検定として使えないのです。

見るとどちらの検定も5%より小さめの値がでています。どちらも検定として使えそうです。

対角線以外のところを見ていきます。

帰無仮説がただしくない状況で(ただしく)帰無仮説を棄却する確率を検出力と呼びます。

検出力は……どちらも同程度ですね。

ていうか、どっちもまったく同じ数字が入ってます。
あまりに同じなので、プログラム間違えたかと思いましたが、どうもあっていそうです。
以下に貼ります。

library(parallel)
library(tidyverse)

simfunc <-function(i,n1,n2,p1,p2){
A <-rbinom(1,n1,p1)
B <-rbinom(1,n2,p2)
mat <-matrix(c(A,n1-A,B,n2-B),byrow = TRUE,2,2)
c(chisq=chisq.test(mat)$p.value,fisher=fisher.test(mat)$p.value)
}
simfunc_r <-function(p1,p2){
  simout <-mclapply(1:10000,simfunc,n1=10,n2=10,p1=p1,p=p2,mc.cores = detectCores())
  outmat <-t(simplify2array(simout))
  apply(outmat,2,function(x)sum(x<0.05,na.rm = TRUE)/10000)
}
setp <-expand.grid(1:9/10,1:9/10)
colnames(setp) <- c("p1","p2")
set.seed(1)
system.time({
map0 <-mapply(simfunc_r,setp$p1,setp$p2)
})
# ユーザ   システム       経過  
# 954.779     75.925    279.490 
outdf<-cbind(setp,t(map0)) %>% 
  as.data.frame() %>% 
  gather(method,reject,-p1,-p2)
p_tile <-ggplot(outdf,aes(x=p1,y=p2,fill=reject))+
  geom_tile()+
  geom_text(aes(label=round(reject,2)))+
  facet_grid(method~.)+
  scale_fill_continuous(low="white",high="cornflowerblue")+
  theme_gray(16)
print(p_tile)

フィッシャーの検定がいいか、カイ二乗検定がいいか? ぼくの立場は「どっちでもいい」です。

でも、あれ? フィッシャーの検定は正確に確率を計算しているはずだから、名目上の有意水準とシミュレーションの値が一致しないとおかしいんじゃないの?

はい。でも今回のシミュレーションは離散的で限定的な値しかとらない状況なので、分割表の出現パターンも限られてしまいます。そのため名目上の値とシミュレーションの値がぴったりとは一致しないのです。

あと、フィッシャーの検定が「正確」に計算しているのは、周辺度数(表の横合計と縦合計)が固定されたときの、手持ちのデータよりも偏った分割表が出現する確率です。

今回シミュレーションしたのは表の横合計だけが固定されている状況です。

とはいえ、表の周辺度数が固定されている状況を仮定するのって自然かなあ。あんまりそういう状況ってないんじゃないかな。

冒頭のツイートであったような、カイ二乗検定で有意になるけどフィッシャーの検定で有意にならない結果がでる状況がシミュレーションできればおもしろかったのですが、そういうのは思いつきませんでした(連続性の補正を外したらそうなりそうな気がしますが、それだとおもしろくない)。

(追記)同じようなシミュレーションがより徹底して行われています:Jupyter Notebook Viewer