データ分析系プログラマーのブログ

主にPythonを使ったデータ分析や機械学習をやっています。

Pythonを使った独立性のカイ二乗検定統計量の求め方

検定には、母平均、母比率、母分散を用いた検定の他に、二項分布、ポアソン分布、適合度、独立性の検定があります。このうち、カイ二乗統計量を用いた独立性の検定は、2つ以上の分類基準を持つクロス集計表において、分類基準間に関連があるかどうかを検定することをいいます。独立性の検定では、カイ二乗分布を用いて検定を行います。この記事では、Pythonを使って、独立性におけるカイ二乗の統計検定量の求め方と独立性の検定の行い方について紹介しています。

独立性の検定

独立性の検定は、2つ以上の分類基準を持つクロス集計表において、分類基準間に関連があるかどうかを検定することです。この場合も、カイ二乗分布を使用します。検定統計量は、理論値を求め、ズレを計算し、すべてのズレの和を計算することで求められます。

理論値は、i列目の度数の合計を「fi」、j行目の度数合計を「fj」、すべての度数の合計をnとすると、i列・j行目の「理論値」は以下の式から求められます。


理論値=\frac{f_i\times f_j}{n}

すべてのズレの和は以下のようになります。


\chi^2=\frac{(実測値_1-理論値_1)^2}{理論値_1}+\frac{(実測値_2-理論値_2)^2}{理論値_2}+\dots+\\ \frac{(実測値_n-理論値_n)^2}{理論値_n}

自由度は、m行、n行とした場合、(m-1)/(n-1)となります。

例えば、ランダムに選ばれた男女各100人の血液型について次のようなデータが得られた時、性別と血液型に関連があるといえるかどうかは以下のようになります。

血液型 A型 O型 B型 AB型
男性 50 24 17 9 100
女性 45 28 22 5 100

理論値を計算するために各血液型の合計を計算します。

血液型 A型 O型 B型 AB型
男性 50 24 17 9 100
女性 45 28 22 5 100
95 52 39 14 200

理論値は以下のようになります。


理論値=\frac{f_i\times f_j}{n}
血液型 A型 O型 B型 AB型
男性 47.5 26 19.5 7 100
女性 47.5 26 19.5 7 100

ズレの和は以下のようになります。


\chi^2=\frac{(50-47.5)^2}{47.5}+\frac{(24-26)^2}{26}+\frac{(17-19.5)^2}{19.5}+\frac{(9-7)^2}{7}\\
+\frac{(45-47.5)^2}{47.5}+\frac{(28-26)^2}{26}+\frac{(22-19.5)^2}{19.5}+\frac{(5-7)^2}{7}\\
=0.1315+0.1538+0.3205+0.571+0.1315+0.1538+0.3205+0.571=2.3536

自由度は、(2-1)/(4-1)となります。


\chi^2_{0.05}(3)

は、片側検定なので、7.815となります。

よって、有意水準5%において、帰無仮説を棄却しない」という結果になるので、性別と血液型は独立である(関連がない)」と結論づけられます。

Pythonを使った独立性のカイ二乗検定統計量の求め方

pythonを使って独立性のカイ二乗検定統計量を求める場合は以下のようになります。リストを使って計算する場合は、まず、男性と女性のデータをそれぞれ用意します。次に、for文を使って、男性と女性の血液型ごとの合計を求めます。次に、男性、女性それぞれの理論値をfor文で求めます。そして、男女それぞれのデータと理論値を使ってカイ二乗統計検定量を計算します。最後に、有意水準0.05、自由度からカイ二乗の値をscipyのstats.chi2.ppfで求めて、有意水準0.05の片側検定で検定を行います。また、独立性におけるカイ二乗統計検定量は、numpyでデータを用意して、scipyのchi2_contingencyを使用することでも求められます。

data1 = [50,24,17,9]
data2 = [45,28,22,5]

data12 = []

for i, j in zip(data1, data2):
    k = i + j
    data12.append(k)
print("男性と女性の血液型ごとの合計 = ", data12)

data1_all = sum(data1)
data2_all = sum(data2)
data12_all = sum(data12)

data1_theo = []
data2_theo = []

for i in data12:
    k = i*data1_all/data12_all
    data1_theo.append(k)
    
for i in data12:
    k = i*data2_all/data12_all
    data2_theo.append(k)

print("男性の理論値 = ", data1_theo)
print("女性の理論値 = ", data2_theo)

chi2 = 0

for i, j in zip(data1, data1_theo):
    chi2 += ((i - j)**2)/j

for i, j in zip(data2, data2_theo):
    chi2 += ((i - j)**2)/j

print("カイ二乗統計検定量 = ", chi2)

男性と女性の血液型ごとの合計 = [95, 52, 39, 14]
男性の理論値 = [47.5, 26.0, 19.5, 7.0]
女性の理論値 = [47.5, 26.0, 19.5, 7.0]
カイ二乗統計検定量 = 2.3547329863119337

from scipy import stats
alpha = 0.05 #有意水準
df = (2-1)*(len(data1)-1) # 自由度 (n-1)×(m-1)

chi2_value = stats.chi2.ppf(1-alpha, df)

if chi2 < chi2_value:
    print("カイ二乗の値は", chi2_value, "なので、帰無仮説を採択し、対立仮説を棄却するという結果になり、",
          "性別と血液型は独立である(関連がない)」と結論づけられます。")
    
else:
    print("カイ二乗の値は", chi2_value, "なので、帰無仮説を棄却し、対立仮説を採択するという結果になり、",
          "性別と血液型は独立とは言えない(関連がある)」と結論づけられます。")

カイ二乗の値は 7.814727903251179 なので、帰無仮説を採択し、対立仮説を棄却するという結果になり、 性別と血液型は独立である(関連がない)」と結論づけられます。

from scipy import stats
import numpy as np
array = np.array([[50,24,17,9], [45,28,22,5]])
result = stats.chi2_contingency(array)

print("カイ二乗の統計量",result[0])
print("p値",result[1])
print("自由度",result[2])
print("期待度数",result[3])

カイ二乗の統計量 2.3547329863119337
p値 0.5021166806663782
自由度 3
期待度数 [[47.5 26. 19.5 7. ]
[47.5 26. 19.5 7. ]]

参考

統計学の時間 | 統計WEB