マン・ホイットニーのU検定(概要とpython実装)

マン・ホイットニーのU検定について

  • 独立2群間の代表値の差の検定
  • 2群間の平均値が独立であり(データに対応がない)、かつ正規分布が仮定できない(ノンパラメトリック)場合に用いる。下記図参照。
  • ウィルコクソンの順位和検定と同様の結論が得られる。
  • 順序尺度に対応している。
  • 各群のサンプル数は一致しなくてよい。

コード

import numpy as np
from scipy import stats
import seaborn as sns

#用いるデータ
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])

#試しにバイオリンプロットを作成
sns.violinplot(x=['A' for i in range(len(A))]+['B' for i in range(len(B))],
y=np.concatenate([A, B]))

# 有意水準を0.05、帰無仮説を「2群間の代表値に差がないこと」とする。
result = stats.mannwhitneyu(A,B,alternative='two-sided')
print('p-value:',round(result.pvalue,5))
# >>> p-value: 0.00183

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

バイオリンプロットはこんな感じ


検定の方法(詳細)

手順

  1. 仮説を設定する。
    帰無仮説(Ho):「2群間に差がない」と仮定する。
    対立仮説(H1):「2群間に差がある」と仮定する。
  2. 有意水準 $\alpha$ を設定する。
  3. 統計量 $U$ を算出する。
  4. 標本サイズに応じて、 $p$ 値を算出する。
    4-a. 比較したい標本の標本サイズがどちらも20以下の時:Mann-Whitner検定表から算出
    4-b. どちらかの標本サイズが20より大きい時:正規分布表から算出
  5. p値と有意水準から帰無仮説の棄却可否を判断する。
    P ≧ α の時:帰無仮説は棄却できない。
    P < α の時:帰無仮説を棄却する。(=2群に有意差あり)

統計量Uの求め方

  1. 標本サイズが小さい方を標本A、もう一方を標本Bとする。
  2. 標本Aの各データについて、標本Bの中でそれよりも大きいをもつデータの数の総和をUとする。
    (もし両群に同じ値があるなら、「相手よりわずかに値が大きい場合」と「相手よりわずかに値が小さい場合」を想定してその平均を算出する)

計算コード

比較したい標本の標本サイズがどちらも20以下の時

#下記のデータを利用する。
A = np.array([6, 10, 13, 15, 18, 20])
B = np.array([2, 3, 6, 8, 9, 12, 16, 17])

#Uを求める
num_bigger_value = []

for i in A:
    # i よりも大きい値がの個数
    bigger_temp = len(np.where(B>i)[0])

    # i と同じ値の個数(平均をとるので2で割る)
    equal_temp = len(np.where(B==i)[0]) / 2
    num_bigger_value.append(bigger_temp + equal_temp)

U = np.array(num_bigger_value).sum()
print('U-value:',U)
# >>> U-value: 12.5

それぞれの標本サイズ n1=6, n2=8、p<0.05としてMann-Whitney検定表(両側検定表)を参照すると、U値の下限有意点は8となり、計算したU値(12.5)はこれよりも大きい。
よって、P≧0.05となり帰無仮説を棄却できない。(「2群に有意差がある」と言えない)

比較したい標本の標本サイズがのどちらかが20以上の時

統計量Uを計算する。

A = np.array([50, 49, 49, 47, 45, 45, 43, 43, 43, 41, 38, 37, 36, 35, 34, 33, 33, 31, 31, 30])
B = np.array([48, 48, 46, 44, 42, 42, 42, 41, 41, 36, 34, 32, 30, 30, 29, 28, 28, 28, 26, 25, 24, 22])

#Uを求める
num_bigger_value = []

for i in A:
    bigger_temp = len(np.where(B>i)[0])
    equal_temp = len(np.where(B==i)[0]) / 2
    num_bigger_value.append(bigger_temp + equal_temp)

U = np.array(num_bigger_value).sum()
print('U-value:',U)
# >>> U-value: 135.0

次の式を用いて、平均値 $\mu_u$、標準偏差$\sigma_u$、$z$ 値を求める。
(この式ではUは近似的に正規分布となる)

$$ \mu_u = \frac{n_1n_2}{2} $$

$$ \sigma_u = \frac{n_1n_2(n_1+n_2+1)}{12} $$

$$ z = \frac{U-\mu}{\sigma} $$

 

n1 = len(A)
n2 = len(B)

#平均値
mu = (n1 * n2)/2
print('平均値:', mu)

#標準偏差
sigma = np.sqrt(n1 * n2 * (n1 + n2 + 1)/12)

print('標準偏差:', round(sigma,2))
z = abs((U - mu)/sigma)
print('z:',round(z,3))
"""output
平均値: 220.0
標準偏差: 39.71
z: 2.141
"""

計算したZ値より、標準正規分布表から確率Pを求めると、P = 0.03236<0.05 となる。
P<0.05なので帰無仮説は棄却、対立仮説が採用される。(「2群に有意差がある」といえる)

参考