無相関検定(概要とpython実装)

ある因子(変数)ペアに互に相関があるか検定できる無相関検定についてまとめた。

無相関検定について

  • 標本から得られた相関係数から「母集団にも同様の相関がある」と言えるかどうかを検定するもの。
  • 帰無仮説を「母相関係数は0である (同様の相関はない)」とおき、その棄却可否を調べる。

無相関検定での注意点

無相関検定のp値と相関係数 $r$ は独立に考える。 (無相関検定で評価するのは「相関が0でないかどうか」だけなので、相関が強いかどうかはp値からは主張できない)

相関係数r と p 値のパターンとその解釈

  • rの絶対値が大きく、p値も有意水準を下回っている場合
    => 二つの変数の間になんららかの関係があると解釈するのが妥当
  • rの絶対値が小さいが、p値は有意水準を下回っている場合
    => 相関は存在すると考えられるが、関係の強さは弱いと解釈する。
  • p値が有意水準を上回っている場合
    => 標本から得られたデータからどのようなrの値が得られていても、実際に相関関係があるかどうかはこのデータからは結論付けられない。

pythonコード

scikit-learnのボストンの家賃データを利用する。
有意水準を0.05を定め、選択した二つの変数に相関があるか検定する。

変数の準備と相関のチェック

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_boston
from scipy.stats import pearsonr
from scipy.stats import spearmanr

# データ読み込み
boston = load_boston()
df_X = pd.DataFrame(boston.data, columns=boston.feature_names)
df_y = pd.DataFrame(boston.target,columns=['RENT'])
df = pd.concat([df_X,df_y],axis=1)

#全ての変数ペアの相関係数を求める。
df_pearson = df.corr(method='pearson')

#結果をヒートマップで可視化する
fig, ax = plt.subplots(figsize=(10, 8))
sns.heatmap(df_pearson, square=True, annot=True, fmt='.2f',annot_kws={'size':10},vmax=1, vmin=-1, center=0)
plt.title('Correlation coefficient (pearson)',fontsize=18)
plt.ylim(df_pearson.shape[1],0)
plt.savefig('Correlation_coefficient_pearson.png')
plt.show()


無相関検定を実施

相関係数の高いRENT とLSTATについて無相関検定を実施する。

#相関係数の高いRENT とLSTATについて無相関検定を実施する。
rent = df['RENT'].values
lstat = df['LSTAT'].values

#ピアソンの相関係数とp値を計算する。
result = pearsonr(rent, lstat)

#スピアマンの相関係数とp値を計算する場合
#result = pearsonr(rent, lstat)
r_value = result[0]
p_value = result[1]
print('相関係数:', r_value)
print('p値:', p_value)
"""output
相関係数: -0.7376627261740148
p値: 5.08110339438697e-88
"""

p値 < 有意水準(0.05)であるため帰無仮説は棄却され、二つの変数は無相関ではないだろうと考えられる。

極端にサンプル数を減らしてみる

#サンプル抽出する
rent = df['RENT'].values[:5]
lstat = df['LSTAT'].values[:5]
result = pearsonr(rent, lstat)
r_value = result[0]
p_value = result[1]
print('相関係数:', r_value)
print('p値:', p_value)
"""output
相関係数: -0.7036716841380781
p値: 0.18479027554023453
"""

極端にサンプル数が少ない場合には、p値 > 有意水準(0.05)となり、「母相関係数は0である (同様の相関はない)」という仮説は棄却されない
つまり少数サンプルでは何も結論づけられないとうこと。

詳細(計算方法)

  1. 仮説を設定する。
    帰無仮説H0:母相関係数は0である (同様の相関はない)
    対立仮説H1:母相関係数は0ではない
  2. 有意水準\alphaを定める。
  3. 下記の式から、統計量$t$を求める。
    (統計量tは自由度 $\nu = n-2$ に従う)
  4. p値を求め棄却有無を判定する。

$$ t = \frac{|r|\sqrt{n-2}}{\sqrt{1-r^2}} $$

import numpy as np
from scipy import stats
#相関係数の高いRENT とLSTATについて無相関検定を実施する。
rent = df['RENT'].values[:8]
lstat = df['LSTAT'].values[:8]
r = np.corrcoef(rent, lstat)[0][1]
n = len(rent)
t = abs(r) * np.sqrt(n-2) / np.sqrt(1-r**2)
nu = n-2
print('相関係数r:',r)
print('サンプル数n:',n)
print('統計量t:',t)
print('自由度ν:',nu)
"""output
相関係数r: -0.48538333300088693
サンプル数n: 8
統計量t: 1.3598759326365544
自由度ν: 6
"""
# x軸の等差数列を生成
X = np.linspace(start=-6, stop=6, num=100)
# t分布
t_sf = stats.t.pdf(x=X, df=nu)
#累積確率関数(cdf)と生存関数(sf)でp値を求める。
one_sided_pval1 = stats.t.cdf(t, nu)
one_sided_pval2 = stats.t.sf(t, nu)
# 可視化
plt.plot(X, t_sf)
X_lower = np.linspace(start=-6, stop=t, num=100)
X_upper = np.linspace(start=t, stop=6, num=100)
t_lower = stats.t.pdf(x=X_lower, df=nu)
t_upper = stats.t.pdf(x=X_upper, df=nu)
base = np.zeros(100)
plt.fill_between(X_lower, base, t_lower, facecolor='lime', alpha=0.5)
plt.fill_between(X_upper, base, t_upper, facecolor='yellow', alpha=0.5)
#求めたt値をプロット
plt.plot(t, 0.00009, 's',label='t value')
plt.title('t distribution({})'.format(nu), fontsize=15)
plt.ylim(0,0.005)
plt.xlim(3,6)
plt.ylim(0,0.5)
plt.xlim(-6,6)
plt.legend(fontsize=15)
plt.savefig('無相関検定.png')
plt.show()
print('p-value(lower side):',round(one_sided_pval1,4))
print('p-value(upper side):',round(one_sided_pval2,4))
"""
p-value(lower side): 0.8886
p-value(upper side): 0.1114
"""


算出したp値(黄緑と黄色の面積に該当)はどちらも有意水準(0.05)より大きいので、,「母相関係数は0である (同様の相関はない)」という仮説は棄却されない

参考

関連書籍