Scipyでカイ二乗検定をする場合は、イェイツの補正(Yate's continuity correction)に気を付ける

f:id:ts0818:20210502125216p:plain

https://en.wikipedia.org/wiki/Chi-square_distribution

⇧「自由度」が「k」の「カイ二乗分布」は「k個の独立した標準正規確率変数の2乗の合計の分布です」ということで、「カイ二乗分布」に従うらしい「カイ二乗検定」というものを試してみました。

ちなみに「自由度」はというと、

自由度(じゆうど、英語degree of freedom)とは、一般に、変数のうち独立に選べるものの数、すなわち、全変数の数から、それら相互間に成り立つ関係式(束縛条件、拘束条件)の数を引いたものである。数学的に言えば、多様体の次元である。「自由度1」、「1自由度」などと表現する。

自由度 - Wikipedia

自由度は、力学機構学統計学などで使用され、意味は上記の定義に準じるが、それぞれの具体的に示唆する処は異なる。

自由度 - Wikipedia

⇧ 分野で変わってくるみたいね。

統計学」では、

統計学では、各種の統計量に関して自由度を定義している。

自由度 - Wikipedia

大きさ n の標本における観測データ (x1x2, ..., xn) の自由度は n とする。それらから求めた標本平均 x についても同じ。

自由度 - Wikipedia

不偏分散

については、

という関係式(ここで x は母集団平均 μ の推定量である)があるから、自由度は 1 少ない n − 1 となる。そのため分母には n − 1 を用いている。

自由度 - Wikipedia

⇧ ってことみたいね。

それでは、レッツトライ~。
 

カイ二乗検定って?

Wikipediaさんに聞いてみる。

カイ二乗検定(カイにじょうけんてい、カイじじょうけんてい、Chi-squared test)、または検定とは、帰無仮説が正しければ検定統計量が漸近的にカイ二乗分布に従うような統計検定法の総称である。

カイ二乗検定 - Wikipedia

次のようなものを含む。

カイ二乗検定 - Wikipedia

⇧「仮説検定」で「検定統計量」を求める手法の中の一つってことですかね。 

  • これらはいずれも

    (ここで"expected" という語は期待値そのものではなく観測値から求められる期待値の推定量あるいは理論値を指すことが多い)

    という形の検定統計量「カイ二乗(χ2)」を含む。

カイ二乗検定 - Wikipedia

⇧「 X^2」とか変数名が紛らわしいな...

 

イェイツの補正(Yate's continuity correction)って?

Wikipediaさんに聞いてみた。

統計学において, イェイツの修正 (またはイェイツのカイ二乗検定)は分割表において独立性を検定する際にしばしば用いられる。場合によってはイェイツの修正は補正を行いすぎることがあり、現在は用途は限られたものになっている。

イェイツのカイ二乗検定 - Wikipedia

歴史を見てみると、 

この推測はそこまで正確なものではなく、誤りを起こすこともある。 この推測の際の誤りによる影響を減らすため、英国の統計家であるフランク・イェイツは、2 × 2 分割表の各々の観測値とその期待値との間の差から0.5を差し引くことによりカイ二乗検定の式を調整する修正を行うことを提案した。

イェイツのカイ二乗検定 - Wikipedia

これは計算の結果得られるカイ二乗値を減らすことになりp値を増加させる。イェイツの修正の効果はデータのサンプル数が少ない時に統計学的な重要性を過大に見積もりすぎることを防ぐことである。

イェイツのカイ二乗検定 - Wikipedia

⇧ ってな感じで、「サンプル数」が少ないときを考慮して考案されたらしい。

だが、しかし!

この式は主に分割表の中の少なくとも一つの期待度数が5より小さい場合に用いられる。不幸なことに、イェイツの修正は修正しすぎる傾向があり、このことは全体として控えめな結果となり帰無仮説を棄却すべき時に棄却し損なってしまうことになりえる(第2種の過誤)。

イェイツのカイ二乗検定 - Wikipedia

そのため、イェイツの修正はデータ数が非常に少ない時でさえも必要ないのではないかとも提案されている。

イェイツのカイ二乗検定 - Wikipedia

⇧ 何と言うことでしょう!「第2種の過誤」が起こり得る可能性も上げることになってしまうんだとか... 

 

実際に「カイ二乗検定」してみる

というわけで、実際に「カイ二乗検定」してみますか。 

⇧ 上記サイト様を参考に、実施していきます。

帰無仮説」は以下となるようです。 

「二組の比率の差の検定」は「カイ二乗検定」を使っておけば良いんですかね? 

というわけで、実際に試してみた。

qiita.com

wagtail.cds.tohoku.ac.jp

⇧ 上記サイト様を参考にさせていただきました。

Visual Studio Code」で実施しましたが、 「Google Colaboratry」とかでもコード自体は動くかと。(グラフの拡大とかが、「Google Colaboratry」だと無理っぽいかも)

Visual Studio Code」を使う場合は、各種ライブラリを事前にインストールしておかないと、importできないので注意ですかね。

from scipy.stats import chi2
from scipy.stats import chi2_contingency
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

pd.set_option("display.unicode.east_asian_width", True)

# 元のデータが無いので、クロス集計がされた体で
result_crossed_df = pd.DataFrame([
      [27, 293, 320],
      [45, 235, 280],
      [72, 528, 600]
    ],
    index=["殺菌石けん", "普通の石けん", "合計"],
    columns=["2次感染を起こした数", "2次感染を起こさなかった数", "合計"]
)

target_df = result_crossed_df.loc["殺菌石けん":"普通の石けん", ["2次感染を起こした数", "2次感染を起こさなかった数"]]

# 有意水準
significance_level = 0.01

print(target_df)
#手計算で「カイ二乗検定」
print("■手計算")
print(result_crossed_df["合計"].iat[2])
# x1 = 600*(27*235-293*45)**2/(320*280*72*528)
x2_manual_calculation = result_crossed_df["合計"].iat[2] * (result_crossed_df["2次感染を起こした数"].iat[0] * result_crossed_df["2次感染を起こさなかった数"].iat[1]-result_crossed_df["2次感染を起こさなかった数"].iat[0] * result_crossed_df["2次感染を起こした数"].iat[1])**2 / (result_crossed_df["合計"].iat[0] * result_crossed_df["合計"].iat[1] * result_crossed_df["2次感染を起こした数"].iat[2] * result_crossed_df["2次感染を起こさなかった数"].iat[2])
dof_manual_calculation = (len(target_df) -1) * (len(target_df.columns) -1)
print("カイ二乗値は %(x2_manual_calculation)s" %locals() )
print("自由度は %(dof_manual_calculation)s" %locals() )

# Scipyで「カイ二乗検定」
x2_yates_no, p_yates_no, dof_yates_no, expected_yates_no = chi2_contingency(target_df, correction=False)
x2_yates_yes, p_yates_yes, dof_yates_yes, expected_yates_yes = chi2_contingency(target_df)

print("■Scipy(イェイツの補正なし)")
print("カイ二乗値は %(x2_yates_no)s" %locals() )
print("確率は %(p_yates_no)s" %locals() )
print("自由度は %(dof_yates_no)s" %locals() )
print( expected_yates_no )

if p_yates_no < significance_level:
    print("有意な差があります")
else:
    print("有意な差がありません")

print("■Scipy(イェイツの補正あり)")
print("カイ二乗値は %(x2_yates_yes)s" %locals() )
print("確率は %(p_yates_yes)s" %locals() )
print("自由度は %(dof_yates_yes)s" %locals() )
print( expected_yates_yes )

if p_yates_yes < significance_level:
    print("有意な差があります")
else:
    print("有意な差がありません")

k = dof_yates_no
xc = chi2.ppf(1-significance_level, k)
print("Chi-square({0})={1}".format(significance_level, xc))

x_1 = np.linspace(0, xc*1.5, 100)
y_1 = chi2.pdf(x_1, k)
x_2 = np.linspace(xc, xc*1.5, 20)
y_2 = chi2.pdf(x_2, k)

y_max = round(np.max(y_1[y_1 != np.inf]), 1)

fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid()
ax.plot(x_1, y_1, '-', color="blue", linewidth=1.0, label="k="+str(k))
ax.fill_between(x_2, y_2, '-', color="red")
ax.set_title("CHI-SQUARE DISTRIBUTION")
yticks = np.arange(0.0, y_max+0.1, 0.1)
yticklabels = ["%.2f" % x_1 for x_1 in yticks]
ax.set_yticks(yticks)
ax.set_yticklabels(yticklabels)
ax.legend()
ax.set_xlabel("x")
ax.set_ylabel("p(x)")
plt.show()

⇧ ってな感じで保存して、実行してみる。

f:id:ts0818:20210430125759p:plain

⇧「検定統計量(今回は、『カイ二乗値』のこと)」が、確かに「イェイツの補正」のありなしで変わってきますと。

グラフについては、

f:id:ts0818:20210430112558p:plain

ルーペのアイコンを選択するとグラフの中で選択した部分を拡大できるので、f:id:ts0818:20210430113255p:plain を選択します。

f:id:ts0818:20210430112701p:plain

マウスでドラッグして、拡大したい範囲を選択で。

f:id:ts0818:20210430112751p:plain

拡大された範囲を確認すると、赤い色で囲まれた面積の左端の  p(X) 有意水準1%地点になるらしく検定統計量は X = 6.64 って値になるらしく(Scipyの結果は、 Chi-square(0.01)=6.6348966010212145 だけど)、今回の「カイ二乗検定」で算出した検定統計量が X_2 = 8.24 (Scipyの結果は、 X_2 = 8.241172889610388 だけど)なので、「帰無仮説」を「棄却」できるってことみたい。

f:id:ts0818:20210430112815p:plain

解答は、以下のような感じ。

⇧ ってな感じで、「イェイツの補正(Yate's continuity correction)」ありの場合の「検定統計量(今回は『カイ二乗値』)」も「7.534116274350646」だから、「有意水準」が「1%」の場合の「検定統計量(今回は『カイ二乗値』)」が「6.64」だから「帰無仮説」が「棄却」できるけども、「イェイツの補正(Yate's continuity correction)」には気を付ける必要がありますかね。

今回はこのへんで。