「ダイエットプログラムの前後で体重は変わったか」「新しい教育法は成績を向上させたか」。このように同じ対象に対して2回の測定を行い、その差に意味があるかを調べたい場面は多い。対応のあるt検定はこのような問題に対する標準的な手法だが、正規分布の仮定が必要である。
正規性を仮定できない場合に用いられるのが、符号付き順位検定と符号検定である。符号付き順位検定は1945年にフランク・ウィルコクソン(Frank Wilcoxon, 1892–1965)が順位和検定と同時に提案したもので、1956年にシドニー・シーゲルの教科書によって広く普及した。一方、符号検定はさらに古い歴史をもつ。1710年、イギリスの医師ジョン・アーバスノットが男女出生比率の分析で用いたのが、最初のノンパラメトリック検定ともいわれている。
両手法はいずれも対応のあるデータに対するノンパラメトリック検定だが、データの使い方が異なる。符号付き順位検定は差の大きさと符号の両方を利用し、符号検定は符号のみを利用する。本記事では両手法を具体例で比較しながら解説する。
符号付き順位検定
基本的な考え方
ウィルコクソンの符号付き順位検定(Wilcoxon signed-rank test)は、対応のあるデータの差 D = X_{\text{後}} - X_{\text{前}} に対して、その分布の中央値が0であるかを検定する。順位和検定と同様に並べ替えの考え方を用いるが、差の符号にも着目する点が特徴である。
なお、この検定では差 D の分布が対称であることを仮定する。あまりにも歪みのある分布に適用するのは望ましくない。
計算手順
あるダイエットプログラムの効果を検証するため、6人の参加者の体重変化(プログラム前 − プログラム後、単位:kg)を測定した。正の値は体重が減少したことを意味する。
帰無仮説を「差の中央値 = 0(プログラムに効果なし)」、対立仮説を「差の中央値 > 0(体重が減少した)」として片側検定を行う。
Step 1:差が0の観測値を除外する
差が0になった観測値は除外し、サンプルサイズ n を減らす。本例では0の値がないため n = 6 のまま進む。
Step 2:絶対値の小さい順に並べ、順位を付ける
| 差 D | −0.5 | 1.0 | 2.0 | −2.5 | 3.5 | 4.0 |
|---|---|---|---|---|---|---|
| 絶対値 |D| | 0.5 | 1.0 | 2.0 | 2.5 | 3.5 | 4.0 |
| 順位 | 1 | 2 | 3 | 4 | 5 | 6 |
| 符号付き順位 | −1 | +2 | +3 | −4 | +5 | +6 |
Step 3:正順位和 T_+ を求める
正の符号付き順位の合計 T_+ を検定統計量とする。
なお、負の順位和は T_- = 1 + 4 = 5 であり、T_+ + T_- = 16 + 5 = 21 = \dfrac{6 \times 7}{2} が成り立つ。
Step 4:P値を求める
帰無仮説のもとでは、1から6までの各順位が正か負かはランダムに決まる。したがって 2^6 = 64 通りの符号パターンが等確率で生じる。対立仮説のもとでは T_+ は大きな値をとるので、片側P値は
有意水準5%では帰無仮説を棄却できない。このデータだけでは、ダイエットプログラムに効果があるとはいえない。
帰無仮説が正しければ、各順位が正になる確率は \dfrac{1}{2} なので、T_+ の期待値は全順位の和の半分、すなわち \dfrac{n(n+1)}{4} 程度の値をとる。本例では \dfrac{6 \times 7}{4} = 10.5 であり、実測値 T_+ = 16 は期待値より大きいが、P値から判断すると偶然の範囲内である。
正規近似
サンプルサイズ n が大きくなると 2^n 通りの列挙は現実的でなくなる。この場合、帰無仮説のもとでの T_+ の分布を正規分布で近似する。タイがない場合、
であり、n が大きいとき
は近似的に標準正規分布に従う。
30人の患者にリハビリを行い、リハビリ前後の握力差を測定した。5人は差が0であったため除外し、有効サンプルサイズ n = 25 で検定を行う。正順位和は T_+ = 220 であった。「リハビリにより握力が向上した」という片側対立仮説を有意水準5%で検定せよ。
【解答】
標準正規分布の上側5%点は1.645であり、Z = 1.55 < 1.645 なので帰無仮説を棄却できない。有意水準5%では、リハビリによる握力の向上があったとはいえない。
符号検定
基本的な考え方
符号検定(sign test)は、符号付き順位検定と同じく対応のあるデータの検定に用いるが、差の大きさを無視し、符号(正か負か)のみを利用する点が異なる。分布の対称性も仮定しない。
差が0でないデータのサンプルサイズを n とし、正の差の個数を T_+ とすると、帰無仮説「中央値 = 0」のもとで T_+ は二項分布 \text{Bin}(n, 0.5) に従う。
計算例
先ほどのダイエットプログラムのデータで符号検定を行う。
差が0のものを除くと n = 6 で、正の差は4個(1.0, 3.5, 4.0, 2.0)である。帰無仮説のもとで T_+ \sim \text{Bin}(6, 0.5) に従うので、片側P値は
有意水準5%では帰無仮説を棄却できない。
符号付き順位検定と符号検定の比較
同じデータに対して、符号付き順位検定のP値は約0.156、符号検定のP値は約0.344であった。符号付き順位検定の方がP値が小さい。これは差の大きさの情報を利用しているためであり、一般に符号付き順位検定の方が検出力(帰無仮説が偽のときに棄却できる確率)が高い。
| 符号付き順位検定 | 符号検定 | |
|---|---|---|
| 利用する情報 | 差の符号と大きさ(順位) | 差の符号のみ |
| 分布の仮定 | 差の分布が対称 | 仮定なし |
| 検出力 | 高い | 低い |
| 帰無分布 | 2^n 通りの符号パターン | 二項分布 \text{Bin}(n, 0.5) |
| 適用場面 | 差の分布が概ね対称のとき | 差の分布が歪んでいるとき |
練習問題
符号付き順位検定を用いて、「補習の効果がある(差の中央値 > 0)」を有意水準5%の片側検定で検定せよ。
差が0のものはないので n = 5 である。絶対値の小さい順に並べ替え、符号付き順位を付ける。
| 差 | −1 | 2 | 4 | 5 | 6 |
|---|---|---|---|---|---|
| 順位 | 1 | 2 | 3 | 4 | 5 |
| 符号付き順位 | −1 | +2 | +3 | +4 | +5 |
正順位和:T_+ = 2 + 3 + 4 + 5 = 14
組合せ総数:2^5 = 32
T_+ \geq 14 となるのは、5つ全てが正のとき(T_+ = 15)と、順位1のみが負のとき(T_+ = 14)の2通りである。
結論:有意水準5%では帰無仮説を棄却できない(P値 ≈ 0.063 > 0.05)。
n = 20 より
標準正規分布の上側5%点は1.645であり、Z = 1.87 > 1.645 なので帰無仮説を棄却する。
結論:有意水準5%で、トレーニングの効果があると判断できる。
まとめ
| 項目 | 符号付き順位検定 | 符号検定 |
|---|---|---|
| 目的 | 対応のあるデータの差の中央値が0か検定 | |
| 検定統計量 | 正順位和 T_+ | 正の差の個数 T_+ |
| 帰無分布 | 2^n 通りの符号パターン | \text{Bin}(n, 0.5) |
| 正規近似の期待値 | \dfrac{n(n+1)}{4} | \dfrac{n}{2} |
| 正規近似の分散 | \dfrac{n(n+1)(2n+1)}{24} | \dfrac{n}{4} |
| 分布の仮定 | 差が対称 | 仮定なし |
Python実装
SciPyを使った符号付き順位検定と符号検定の実装例を示す。
import numpy as np
from scipy import stats
# === 符号付き順位検定 ===
D = np.array([-2.5, 1.0, 3.5, -0.5, 4.0, 2.0])
print("=== 符号付き順位検定 ===")
print(f"差データ: {D}")
stat, p_value = stats.wilcoxon(D, alternative='greater')
print(f"T+ = {stat}")
print(f"P値(片側)= {p_value:.4f}")
print()
# === 符号検定 ===
print("=== 符号検定 ===")
n_pos = np.sum(D > 0)
n_total = np.sum(D != 0)
print(f"正の差の個数: {n_pos}")
print(f"有効n: {n_total}")
# Bin(n, 0.5)の上側確率
p_sign = stats.binom.sf(n_pos - 1, n_total, 0.5)
print(f"P値(片側)= {p_sign:.4f}")
print()
# === 正規近似の例 ===
print("=== 正規近似の例 ===")
n = 25
T_plus = 220
E_T = n * (n + 1) / 4
Var_T = n * (n + 1) * (2 * n + 1) / 24
Z = (T_plus - E_T) / np.sqrt(Var_T)
p_norm = 1 - stats.norm.cdf(Z)
print(f"n = {n}, T+ = {T_plus}")
print(f"E[T+] = {E_T:.1f}")
print(f"Var(T+) = {Var_T:.2f}")
print(f"Z = {Z:.4f}")
print(f"P値(片側)= {p_norm:.4f}")
print()
# === 検出力の比較 ===
print("=== 検出力の比較(同じデータ)===")
print(f"符号付き順位検定のP値: {p_value:.4f}")
print(f"符号検定のP値: {p_sign:.4f}")
print("→ 符号付き順位検定の方がP値が小さい(検出力が高い)")