【Python】2群間での統計検定手法まとめ

2群間での統計検定手法をまとめました。PythonのScipyモジュールを使った実行例とともに、各手法について説明していきます。
実行例で用いるモジュールはこちらです。

```python
import numpy as np
from scipy import stats
```


## 対応のあるt検定

- 2群間の平均値の差を比較する検定
- 2群間の平均値が独立とはいえない、つまりデータに対応がある(従属である)場合に用いる

**用いるデータ**

Rのデフォルトデータセット「sleep」を用います。
このデータセットは、薬剤1と薬剤2の2種類の睡眠薬を10人の被験者にそれぞれ投与した際に、増加した睡眠時間を記録したものです。
2種類の薬剤を同一被験者に投与しているので、その値には対応があるといえます。

```python
A = np.array([0.7, -1.6, -0.2, -1.2, -0.1, 3.4, 3.7, 0.8, 0.0, 2.0])
B = np.array([1.9, 0.8, 1.1, 0.1, -0.1, 4.4, 5.5, 1.6, 4.6, 3.4])
```

それぞれの平均は、以下の通りです。

- A: 0.75
- B: 2.33

これらの値に有意な差があるかどうかを検定します。
有意水準を0.05、帰無仮説を「2群間の平均値に差がないこと」とします。

```python
stats.ttest_rel(A, B)
```

```
Ttest_relResult(statistic=-4.062127683382037, pvalue=0.00283289019738427)
```

結果、`p < 0.05`なので、帰無仮説は棄却され、2種類の睡眠薬の薬効には差があるといえます。


## Student(スチューデント)のt検定

- 2群間の平均値の差を比較する検定
- 2群間の平均値が独立であり(データに対応がない)、2群間に等分散性が仮定できる場合に用いる

**用いるデータ**

Aの値は平均値9, 標準偏差1.5の正規分布に従う値で、Bの値は平均値3, 標準偏差1.5の正規分布に従う値です。

```python
A = np.array([6.3, 8.1, 9.4, 10.4, 8.6, 10.5, 10.2, 10.5, 10.0, 8.8])
B = np.array([4.8, 2.1, 5.1, 2.0, 4.0, 1.0, 3.4, 2.7, 5.1, 1.4, 1.6])
```

- Aのサンプルサイズ: 10
- Bのサンプルサイズ: 11

なので、少なくとも対応はありません。
次に等分散性を確認するため、F検定を行います。有意水準を0.05、帰無仮説を「対象の2群の分散に差はないこと」とします。
Scipyモジュールには、F検定を直接行うメソッドがないため、少し面倒です。

```python
A_var = np.var(A, ddof=1)  # Aの不偏分散
B_var = np.var(B, ddof=1)  # Bの不偏分散
A_df = len(A) - 1  # Aの自由度
B_df = len(B) - 1  # Bの自由度
f = A_var / B_var  # F比の値
one_sided_pval1 = stats.f.cdf(f, A_df, B_df)  # 片側検定のp値 1
one_sided_pval2 = stats.f.sf(f, A_df, B_df)   # 片側検定のp値 2
two_sided_pval = min(one_sided_pval1, one_sided_pval2) * 2  # 両側検定のp値

print('F:       ', round(f, 3))
print('p-value: ', round(two_sided_pval, 3))
```

```
F:        0.779
p-value:  0.718
```

結果、`p > 0.05`なので、帰無仮説は棄却されず、2群間は等分散であること(少なくとも不等分散でないこと)が示唆されました。
よって、Studentのt検定を行います。有意水準を0.05、帰無仮説を「2群間の平均値に差がないこと」とします。

```python
stats.ttest_ind(A, B)
```

```
Ttest_indResult(statistic=9.851086859836649, pvalue=6.698194360479442e-09)
```

結果、`p < 0.05`なので、帰無仮説は棄却され、2群間には差があるといえます。


## Welch(ウェルチ)のt検定

- 2群間の平均値の差を比較する検定
- 2群間の平均値が独立であり(データに対応がない)、2群間に等分散性が仮定できない場合に用いる

**用いるデータ**

Aの値は平均値9, 標準偏差3.5の正規分布に従う値で、Bの値は平均値3, 標準偏差1.5の正規分布に従う値です。

```python
A = np.array([13.8, 10.2, 4.6, 10.0, 4.2, 16.1, 14.4, 4.9, 7.7, 11.4])
B = np.array([3.3, 2.6, 4.0, 4.7, 1.9, 2.9, 4.7, 5.3, 4.3, 3.0, 2.0])
```

- Aのサンプルサイズ: 10
- Bのサンプルサイズ: 11

なので、少なくとも対応はありません。
次に等分散性を確認するため、F検定を行います。有意水準を0.05、帰無仮説を「対象の2群の分散に差はないこと」とします。

```python
A_var = np.var(A, ddof=1)  # Aの不偏分散
B_var = np.var(B, ddof=1)  # Bの不偏分散
A_df = len(A) - 1  # Aの自由度
B_df = len(B) - 1  # Bの自由度
f = A_var / B_var  # F比の値
one_sided_pval1 = stats.f.cdf(f, A_df, B_df)  # 片側検定のp値 1
one_sided_pval2 = stats.f.sf(f, A_df, B_df)   # 片側検定のp値 2
two_sided_pval = min(one_sided_pval1, one_sided_pval2) * 2  # 両側検定のp値

print('F:       ', round(f, 3))
print('p-value: ', round(two_sided_pval, 4))
```

```
F:        13.925
p-value:  0.0003
```

結果、`p < 0.05`なので、帰無仮説は棄却され、2群間は不等分散であることが示唆されました。
よって、Welchのt検定を行います。有意水準を0.05、帰無仮説を「2群間の平均値に差がないこと」とします。
Welchのt検定を行う場合には、ttest_indメソッドで`equal_var=False`とします。

```python
stats.ttest_ind(A, B, equal_var=False)
```

```
Ttest_indResult(statistic=4.426442804187721, pvalue=0.0012285738375064346)
```

結果、`p < 0.05`なので、帰無仮説は棄却され、2群間には差があるといえます。


## Mann-Whitney(マンホイットニー)のU検定(Wilcoxon(ウィルコクソン)の順位和検定)

- 2群間の平均値が独立であり(データに対応がない)、正規分布が仮定できない(ノンパラメトリック)場合に用いる
- 順序尺度に対応
- 独立2群間の**代表値**の差の検定
- 各群のサンプル数は一致しなくてよい

**用いるデータ**

```python
A = np.array([1.83, 1.50, 1.62, 2.48, 1.68, 1.88, 1.55, 3.06, 1.30, 2.01, 3.11])
B = np.array([0.88, 0.65, 0.60, 1.05, 1.06, 1.29, 1.06, 2.14, 1.29])
```

有意水準を0.05、帰無仮説を「2群間の代表値に差がないこと」とします。

```python
stats.mannwhitneyu(A, B, alternative='two-sided')
```

```
MannwhitneyuResult(statistic=91.0, pvalue=0.0018253610099931035)
```

結果、`p < 0.05`なので、帰無仮説は棄却され、2群の代表値には差があるといえます。


## Wilcoxon(ウィルコクソン)の符号付順位和検定

- 2群間の平均値が独立ではなく(データに対応がある)、正規分布が仮定できない(ノンパラメトリック)場合に用いる
- 順序尺度に対応
- 独立2群間の**代表値**の差の検定


**用いるデータ**

```python
A = np.array([1.83, 1.50, 1.62, 2.48, 1.68, 1.88, 1.55, 3.06, 1.30])
B = np.array([0.88, 0.65, 0.60, 1.05, 1.06, 1.29, 1.06, 2.14, 1.29])
```

有意水準を0.05、帰無仮説を「2群間の代表値に差がないこと」とします。

```python
stats.wilcoxon(A, B)
```

```
WilcoxonResult(statistic=0.0, pvalue=0.007685794055213263)
```

結果、`p < 0.05`なので、帰無仮説は棄却され、2群の代表値には差があるといえます。

**注意点**

正規分布への近似を用いて計算を行っているため、サンプル数は大きくなければなりません。
サンプル数が`n < 20`の場合、以下の警告が出ます。

```
UserWarning: Warning: sample size too small for normal approximation.
warnings.warn("Warning: sample size too small for normal approximation.")
```


## 参考

[データ科学便覧](https://data-science.gr.jp/implementation.html#ist)