【無相関の検定】棄却有無の境界線を出してみた

# はじめに
統計の勉強で様々な計算式を覚えていく過程で、**無相関の検定**がなかなか覚えられないので、式を睨んでいました。
そして、気になることがあったので、Pythonで計算させて結果を描画してみました。

- 環境
  - Windows-10-10.0.18362-SP0
  - Python 3.7.6
  - pip 19.3.1
  - pandas 1.0.3
  - matplotlib 3.1.2
  - seaborn 0.10.0
  - numpy 1.18.1
  - scipy 1.4.1

# 無相関の検定
#### 標本から得られた相関係数から「母集団にも同様の相関がある」と言えるかどうかを検定するもの。

- **帰無仮説H0** : 母相関係数は0である (同様の相関はない)

- **対立仮説H1** : 母相関係数は0ではない

下記の式から、統計量$t$を求め、$p$値を出します。統計量$t$に対する自由度$ν$は$n-2$です。

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

有意水準$a$を0.05とした場合は、両側検定で、$p$値0.025点を見れば良いことになります。 


<br>
... なかなか使わないこともあって、この式が覚えられないんですよ。
ただ、「これってn(サンプルサイズ)が大きければt値大きくなるじゃん、**結局はサンプルサイズじゃん！！**」と思ったので、サンプルサイズと相関係数を総当りさせて、**どのあたりまでなら帰無仮説が棄却されないのか**を見てみました。

# 準備

```python
#データづくりに使用
import pandas as pd
import numpy as np
import math
from scipy import stats
import itertools

#グラフ描画に使用
import matplotlib.pyplot as plt
import seaborn as sns
from mpl_toolkits.mplot3d import Axes3D


%matplotlib inline


plt.style.use('seaborn-darkgrid')
plt.rcParams['font.family'] = 'Yu Gothic'
plt.rcParams['font.size'] = 20


#相関係数(coef)とサンプルサイズ(n)を入れたら、t値(t)、自由度(df)、p値(p)が返る関数を作成。
def Uncorrelated(coef, n):
    t = (np.abs(coef) * math.sqrt( (n - 2) ) ) / (math.sqrt( ( 1 - (coef**2) ) ) )
    df = (n - 2)
    p = np.round(( 1 - stats.t.cdf(np.abs(t), df) ), 3) #p値丸めてます。
    return coef, n, t, df, p


#サンプル数 10から1000まで10刻み
samplesizes = np.arange(10, 1001, 10)

#相関係数 -0.99から0.99まで0.01刻み
coefficients = np.linspace(-0.99, 0.99, 199)
#print(coefficients)

#上の2つをCrossjoin(直積)
c_s = list(itertools.product(coefficients, samplesizes) )

#相関係数とサンプルサイズを格納したリストをUncorrelated関数へ入れ、帰ってきたものをPandasでDataFrame化
df_prelist = []
for i in range(len(c_s)): 
    df_prelist.append(Uncorrelated(c_s[i][0],c_s[i][1])) 

#準備は完成
df = pd.DataFrame(df_prelist,columns=['coef','sample_size','t','df','p_value'])
```

dfはこんなかんじ

```python
df
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/d79cef10-35b7-e6e6-c678-1f6f7456099e.png)


```python
df.sample(10)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/0fee16a9-e45a-e31d-0043-8783632160be.png)


相関係数-0.99~0.99,サンプルサイズ10~1000までに対しての無相関の検定のt値、自由度、p値が入っています。


# グラフ描画

```python
fig = plt.figure( figsize=(16, 12) )
ax = Axes3D(fig)
cm = plt.cm.get_cmap('RdYlBu')
mappable = ax.scatter( np.array(df['coef']), np.array(df['sample_size']), np.array(df['p_value']), c=np.array(df['p_value']), cmap=cm)
fig.colorbar(mappable, ax=ax)
ax.set_xlabel('相関係数', labelpad=15)
ax.set_ylabel('サンプルサイズ', labelpad=15)
ax.set_zlabel('p値', labelpad=15)
plt.savefig('3次元グラフ.png', bbox_inches='tight', pad_inches=0.3)
plt.show()
```

<img width='800' alt='3次元グラフ.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/055669b5-b7a4-45a7-e185-a3f7e15aeda4.png'>


...青色に近づくほど、p値が高く、棄却されないのですが・・・**分かりづらいですね**

### Judgeカラムを作成し、p値が0.025よりも大きいものを、「H0を棄却しない」としてDataFrameを作り直しました。


```python
#p_valueが0.025以上なら、`H0を棄却しない`をつける
df['judge'] = 'H0を棄却する'
for index, series in df.query('p_value > 0.025').iterrows():
    df.at[index, 'judge'] = 'H0を棄却しない'


#グラフ再描画
grid = sns.FacetGrid( df, hue = 'judge', height=10 )
grid.map(plt.scatter, 'coef', 'sample_size')
grid.add_legend(title='判定')
plt.ylabel('サンプルサイズ')
plt.xlabel('相関係数')
plt.title('相関係数xサンプルサイズ 無相関検定の棄却有無', size=30)

#赤線を引く
plt.vlines(df[df['judge'] == 'H0を棄却しない']['coef'].max(), -50, 50, color='red', linestyles='dashed')
plt.vlines(df[df['judge'] == 'H0を棄却しない']['coef'].min(), -50, 50, color='red', linestyles='dashed')
plt.annotate('|' + str(df[df['judge'] == 'H0を棄却しない']['coef'].max().round(2) ) + '|より外側は、n=10以上なら全て棄却する',
            xy=(df[df['judge'] == 'H0を棄却しない']['coef'].max(), 80), size=15, color='black')
plt.savefig('2次元グラフ.png', bbox_inches='tight', pad_inches=0.3)
plt.show()
```

<img width='800' alt='2次元グラフ.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635079/e33ae3bd-fabe-2bc2-71e0-433d81d08bf2.png'>


なるほど、**標本の相関係数が絶対値0.62より大きければ、n=10でも帰無仮説H0を棄却して、「母相関係数は0ではない」が採択される**($a=0.05$)ということですね！


<br>
<br>
<font size='2'>...ちなみに、「計算式を覚える」という当初の目的はこの記事を書いて覚えました:upside_down:</font>