独立性の検定 - 特徴量選定

特徴量選定の方法として、前回までは目的変数と説明変数の相関係数に着目してきました。しかし、相関係数は説明変数として妥当だと判断する基準値は持ちません。

そこで、今回は統計的手法である独立性の検定を用いたいと思います。独立性の検定とは、異なる事象の発生に関係性があるかを判定する検定のことです。
つまり、特徴量選定を行う上で、目的変数と説明変数に対し独立性の検定を適用することで、帰無仮説(変数間は独立である)が採択されれば、特徴量として相応しくないと判断し、帰無仮説が棄却されれば、特徴量に選定すべきと判断可能ではないかと考えました。

独立性の検定の適用

今回のデータも前回までと同様、kaggleのタイタニック号生存者予測を用います。
独立性の検定の適用は、相関係数が大きかったSurvivedとSexおよび相関係数が小さいSurvivedとEmbarkedに適用しその結果を比較します。

SurvivedとSex

pythonで独立性の検定を実装していきます。 まずは、検定に必要なクロス集計表を作成します。具体的には、性別の独立性を検定するので、女性かつ生存した人数・女性かつ死亡した人数・男性かつ生存した人数・男性かつ死亡した人数を求めます。

a = (train[train['Survived'] == 1]['Sex'] ==1).sum()
b = (train[train['Survived'] == 1]['Sex'] ==0).sum()
c = (train[train['Survived'] == 0]['Sex'] ==1).sum()
d = (train[train['Survived'] == 0]['Sex'] ==0).sum()

df = pd.DataFrame([[a,b],   
                   [c,d]])
df
[out]
   0   1
0  233 109
1  81  468

上記の値が実測値(実測度数)となります。
独立性の検定では理論度数(独立と仮定したときの値)も必要です。つまり、女性(314人)と男性(577人)それぞれの生存率は全乗客(891人)の生存率と一致するということです。理論度数のクロス集計表は以下のようになります。

#全乗客の生存率
survived = (train['Survived'] == 1).sum()
all = len(train)
rate = survived/all

aa = (a+c)*rate
cc = (a+c)*(1-rate)
bb = (b+d)*rate
dd = (b+d)*(1-rate)

dff = pd.DataFrame([[aa,bb],   
                   [cc,dd]])
dff.round(2)
[out]
      0    1
0  120.53 221.47
1  193.47 355.53

独立性の検定では検定量χ^ 2値が使用されます。χ^ 2値の求め方は\frac{(実測度数-理論度数)^ 2}{理論度数}  を各要素計算した和で表されます。

((a-aa)**2)/aa +((b-bb)**2)/bb +((c-cc)**2)/cc + ((d-dd)**2)/dd
[out]
263.05057407065567

となりました。χ^ 2検定での今回の自由度は1です。しかし、χ^ 2=236は付表に記載されていないのでp値はわかりませんでした。
そこで、ここまでは地道に計算してきましたが、scipyの統計モジュール機能を用いて計算します。

import scipy.stats as st
x2, p, dof, expected = st.chi2_contingency(df,correction=False)

print(f'p値    = {p :.60f}')
print(f'カイ2乗値 = {x2:.2f}')
print(f'自由度   = {dof}')
print(expected)
[out]
p値    = 0.000000000000000000000000000000000000000000000000000000000037
カイ2乗値 = 263.05
自由度   = 1
[[120.52525253 221.47474747]
 [193.47474747 355.52525253]]

計算した結果、p値は10の−60乗ほどと物凄く小さな値となりました。一般に独立性の検定での有意水準は1か5%ほどであるので物凄く小さいです。つまり、この結果から、生存率と性別の関係の実測度数は独立と仮定した場合に対し、10の-60乗ほどの確率でしか起こり得ない事象であることから、帰無仮説を棄却しこの2つの変数には関係があると結論付けられます。
この結果は、相関係数が0.5ほどあったことからも容易に想像できましたが、続いて相関係数が0.2ほどのSurvivedとEmbarkedに関して独立性を確認します。

SurvivedとEmbarked

train['Embarked'] = train['Embarked'].map({'S':0, 'Q':1, 'C':2})

o = (train[train['Survived'] == 0]['Embarked'] ==0).sum()
p = (train[train['Survived'] == 0]['Embarked'] ==1).sum()
q = (train[train['Survived'] == 0]['Embarked'] ==2).sum()
r = (train[train['Survived'] == 1]['Embarked'] ==0).sum()
s = (train[train['Survived'] == 1]['Embarked'] ==1).sum()
t = (train[train['Survived'] == 1]['Embarked'] ==2).sum()

df_embarked = pd.DataFrame([[o,r],   
                            [p,s],
                            [q,t]])
df_embarked
[out]
    0  1
0  427    217
1  47 30
2  75 95

Embarkedを上記のように数値データに変換し、クロス集計表を作成しました。
χ^ 2検定を適用した結果を下に示します。

x2, p, dof, e = st.chi2_contingency(df_embarked,correction=False)
print(f'p値    = {p :.10f}')
print(f'カイ2乗値 = {x2:.2f}')
print(f'自由度   = {dof}')
[out]
p値    = 0.0000008294
カイ2乗値 = 28.01
自由度   = 2

SurvivedとEmbarkedに対し適用したp値は約8×10^-7乗であり、SurvivedとSexと比較し大きくなっていることが確認できました。しかし、それでもなお独立性の検定で一般に定められる有意水準1%と比較すると非常に小さい値であり、EmbarkedはSurvivedに対し、独立ではないと判定することができそうです。

結論

 独立性の検定を相関係数が0.5であるSurvivedとSex、相関係数が0.2であるSurvivedとEmbarkedに対しそれぞれ適用した結果、有意水準を1%とすると検定統計量χ^ 2はどちらのp値も1%には程遠い小さい値となりました。この結果から、SexおよびEmbarkedはSurvivedに対しどちらも独立ではないと判断できます。
また、独立性の検定は主に、変数が独立であるはずのものが、独立ではないのではないかと疑わしい状況において適用されるものです。例えば、A店とB店でドーナツの質量が異なるのではないかなどです。つまり、今回のように相関係数が0.2もある変数間で独立性の検定を適用すれば、当然非常に小さい値になるということです。
 よって、当初の想定ははずれ独立性の検定を特徴量選定に適用するのはあまり有益ではないという結果となりました。しかし、相関係数と独立性の検定でのp値の関係性を掴むことができたことは大きな学びです。