概要
「独立性の検定」に関するメモ、実施のためのPythonコード、Rコードです。
「カイ2乗検定」と「フィッシャーの直接確率検定」の内容を含みます。
関連エントリ
設定
問題例として、次のような設定(状況)を考えていきたいと思います。
ある学校では、学期末に自由記述欄を含んだ授業評価アンケートを実施している。
このアンケートは、担当教員が「紙形式」か「ウェブ形式」を選んで実施している。今後、アンケートを有効活用していくために、実施形式の違いが、自由記述欄(任意)への記入の有無に対して影響してくるのか?を知りたい。
これを検討するための資料として、現在、手元には次のようなデータ(標本)が得られているとします。表内の数値は観測度数になります。
自由記述欄に記入あり | 自由記述欄に記入なし | |
---|---|---|
紙形式 | 140 | 150 |
ウェブ形式 | 160 | 180 |
カイ2乗検定(独立性の検定)
「実施形式が(自由記述欄に対するコメントの)記入の有無に影響するのか?」、つまり「『実施形式』と『記入の有無』には関連性があるのか、それともそれらは独立していて関連性がないのか?」を判断していきます。この独立性を評価するために、カイ2乗検定($\chi^2$ 検定)を利用することができます(フィッシャーの直接確率検定は後ほど)。
カイ2乗検定では**「変数間に関連性がない」を帰無仮説とします(ここでは「実施形式」と「記入有無」が変数となります)。そして、その「変数間に関連性がない」という仮定が正しいとして、仮に何度も標本を無作為抽出したときに「今回のような標本や、さらに極端な標本が得られるケース」がどの程度の確率で発生するのか?という値($p$ 値)を求め、それと事前設定した有意水準** $\alpha$ を比較して判断します。
なお、「さらに極端な標本」とは「(手元にある標本よりも)変数間に関連性がありそうなことを匂わせる標本」のことです、例えば「紙形式では記入割合が $5%$、ウェブ形式では記入割合が $85%$」のような標本のことです。
Pythonで実行
カイ2乗検定を行なうPythonコードを以下に示します。データはpandasのDataFrameに格納されていることを想定しています。
import pandas as pd
import scipy.stats as st
df = pd.DataFrame([[140,150], # 紙形式 で 記入ありの度数, 記入なしの度数
[160,180]]) # ウェブ形式 で 記入ありの度数, 記入なしの度数
x2, p, dof, e = st.chi2_contingency(df,correction=False)
print(f'p値 = {p :.3f}')
print(f'カイ2乗値 = {x2:.2f}')
print(f'自由度 = {dof}')
p値 = 0.760
カイ2乗値 = 0.09
自由度 = 1
あらかじめ決めておいた有意水準 $\alpha$ が $5%$($=0.05$)とすれば、実行結果は $p\ge0.05$ となるので帰無仮説を採択します。つまり、**統計学的には「実施形式」と「記入の有無」に関連性はない(それらは独立している)**と結論付けます。つまり「アンケートの自由記述欄にコメントが書かれるかどうかは、アンケートの実施形式には無関係」といえそうです。
なお、以下のように行と列を入れ替えても、同じ実行結果となります。
df = pd.DataFrame([[140,160],
[150,180]])
ところで、上記では、chi2_contingency
に引数 correction=False
を指定しています。これは「イェーツの補正(イェーツの連続修正)」を適用しない、というオプションになります。カイ2乗検定の原理について解説しているページなどを見ながら試すような場合には、「イェーツの補正をしない」に設定しておくとよいです。
なお、デフォルトでは correction=True
になります。Wikipediaによれば「イェイツの修正の効果はデータのサンプル数が少ない時に統計学的な重要性を過大に見積もりすぎることを防ぐことである」とのことです。 correction=True
として実行すると、次のような結果となります。
p値 = 0.822
カイ2乗値 = 0.05
自由度 = 1
R版
同様のことを R を使って行ないました。
m=matrix(c(140, 150, 160, 180), nrow=2, byrow=T)
chisq.test(m,correct=F)
Pearson's Chi-squared test
data: m
X-squared = 0.092937, df = 1, p-value = 0.7605
つづいて、イェーツの補正ありのバージョンです。
m=matrix(c(140, 150, 160, 180), nrow=2, byrow=T)
chisq.test(m)
Pearson's Chi-squared test with Yates' continuity correction
data: m
X-squared = 0.050549, df = 1, p-value = 0.8221
どのようにp値は計算されるのか
帰無仮説が正しく「実施形式」と「記入の有無」に変数間に関連性がないとき、つまり変数は独立であるときに期待される度数(これを期待度数という)と、実際の観測度数の差の2乗を、期待度数で割ったものの総和(これをカイ2乗値という)を求め、これとカイ2乗分布から $p$ 値を計算します。
期待度数は、変数が独立であるとすれば、次式が成立するはずということに基づき計算できます。
- 紙形式で記入ありの割合=(紙形式の割合)$\times$(記入ありの割合)
- 紙形式で記入なしの割合=(紙形式の割合)$\times$(記入なしの割合)
- ウェブ形式で記入ありの割合=(ウェブ形式の割合)$\times$(記入ありの割合)
- ウェブ形式で記入なしの割合=(ウェブ形式の割合)$\times$(記入なしの割合)
期待度数を実際に求めてみます。まず、観測度数は次のようになっていました(合計欄を追加しました)。
記入あり | 記入なし | 計 | |
---|---|---|---|
紙形式 | 140 | 150 | 290 |
ウェブ形式 | 160 | 180 | 340 |
計 | 300 | 330 | 630 |
ここで、「紙形式の割合」は表の4列目から $290/630\risingdotseq 0.46$ 、「ウェブ形式の割合」は $340/630\risingdotseq 0.54$ のように求めることができます。また、表の4行目から「記入ありの割合」は $300/630\risingdotseq 0.48$、「記入なしの割合」は $330/630\risingdotseq0.52$ となります。
あとは、これらを使って「紙形式で記入ありの割合=(紙形式の割合)$\times$(記入ありの割合)=$(290/630)\times(300/630)\risingdotseq0.219$」を求めます。そして、それに $630$ をかけると、次のように期待度数が求まります。
記入あり | 記入なし | |
---|---|---|
紙形式 | 138.1 | 151.9 |
ウェブ形式 | 161.9 | 178.1 |
この期待度数と観測度数の差の2乗を、期待度数で割ったものの総和(=カイ2乗値)を求め、これとカイ2乗分布から $p$ 値を計算します(詳細は、別資料参照ください)。なお、期待度数は次のように st.chi2_contingency
の戻値の4番目に格納されています。
import pandas as pd
import scipy.stats as st
df = pd.DataFrame([[140,150], [160,180]])
x2, p, dof, e= st.chi2_contingency(df,correction=False)
print(f'期待度数 : \n {e}')
期待度数 :
[[138.0952381 151.9047619]
[161.9047619 178.0952381]]
フィッシャーの直接確率検定
カイ2乗検定は、一部に極端に小さい観測度数(5未満?)を含んでいる場合に適切な検定ができないことが知られています。特に問題例のように $2\times2$(2行2列)のケースでは、すべての観測度数が10以上であることが望ましいようです(参考資料[5])。そのような場合では、カイ2乗検定ではなく**フィッシャーの直接確率検定(フィッシャーの正確確率検定)**を使用します。
なお、十分な観測度数が得られている標本に対してもフィッシャーの直接確率検定は有効です。ただし、フィッシャーの直接確率検定は、観測度数の階乗計算を含むため、計算が大変になることがデメリットになります(問題例では観測度数に140がありますが、140の階乗はとても大きな数になるため計算に工夫が必要です)。Pythonのライブラリを利用するうえでは、あまり気になりませんが。
import pandas as pd
import scipy.stats as st
df = pd.DataFrame([[140,150], [160,180]])
_, p = st.fisher_exact(df)
print(f'p値 = {p :.3f}')
p値 = 0.810
有意水準 $\alpha$ が $5%$($=0.05$)とすれば、実行結果は $p\ge0.05$ となるので帰無仮説を採択します。
R版
m=matrix(c(140, 150, 160, 180), nrow=2, byrow=T)
fisher.test(m)
Fisher's Exact Test for Count Data
data: m
p-value = 0.8103
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
0.757838 1.454709
sample estimates:
odds ratio
1.049888
結論
PythonやRで独立性の検定を行なう場合は、フィッシャーの直接確率検定を利用するのが良いようです。
参考資料
- [1] 小島寛之 著「完全独習 統計学入門」
- [2] 大村平 著「今日から使える統計解析 普及版」
- [3] 平井明代 編著「教育・心理系研究のためのデータ分析入門」
- [4] 向後千春 著「統計学がわかる ハンバーガーショップでむり無く学ぶ、やさしく楽しい統計学」
- [5] χ2乗検定とFisher正確確率検定 ~χ2乗検定の不適切使用をしていませんか?~