Mímisbrunnr知恵の泉

← シミュレーション 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:ブートストラップ法 | 統計:ノンパラメトリック検定(符号・順位和・Wilcoxon)

要点(BLUF)

1. アイデア:ラベルを混ぜて帰無分布を作る

2群 A・B の平均に差があるかを検定したいとします。帰無仮説 H0H_0「両群は同じ分布から来た(差がない)」が正しいなら、各データがA群かB群かというラベルは無意味で、どう振り直しても同じこと(交換可能性)。

そこで、全データをプールしてラベルをランダムに振り直し(並べ替え)、そのたびに群間差を計算します。これを多数回繰り返すと、**「差がない世界での群間差の分布(帰無分布)」**が得られます。観測した実際の差が、この帰無分布のどれくらい端(極端)にあるかが p 値です。

p=#{並べ替え差観測差}(並べ替え回数)p = \frac{\#\{|\text{並べ替え差}| \ge |\text{観測差}|\}}{(\text{並べ替え回数})}
flowchart LR
    D["A群とB群を一つにプール"] --> S["ラベルをシャッフル"]
    S --> C["群間差を計算"]
    C -->|"P回繰り返す"| H["帰無分布"]
    H --> P["観測差の位置 = p値"]

2. 実装:2群の平均差を検定する

A群 N(0,1)\mathcal{N}(0,1)、B群 N(0.5,1)\mathcal{N}(0.5,1)(真に差がある)で検定し、t 検定と比べます。

import numpy as np
from scipy import stats

# 乱数シードを固定
rng = np.random.default_rng(52)

A = rng.normal(0.0, 1.0, 40)
B = rng.normal(0.5, 1.0, 40)
observed = B.mean() - A.mean()

combined = np.concatenate([A, B])
nA = len(A)
P = 20000
perm_diffs = np.empty(P)
for p in range(P):
    rng.shuffle(combined)                       # ラベルをシャッフル
    perm_diffs[p] = combined[nA:].mean() - combined[:nA].mean()

p_perm = (np.abs(perm_diffs) >= np.abs(observed)).mean()   # 両側p値
t_stat, p_t = stats.ttest_ind(B, A)

print(f"観測した差 = {observed:.4f}")
print(f"並べ替え検定 p値 = {p_perm:.4f}")
print(f"t検定 p値        = {p_t:.4f}")

出力:

観測した差 = 0.6730
並べ替え検定 p値 = 0.0006
t検定 p値        = 0.0013

出力の意味:観測した群間差 0.673 は、ラベルをシャッフルして作った帰無分布のごく端(両側 p=0.0006)にあり、有意。正規性を仮定する t 検定(p=0.0013)とほぼ同じ結論ですが、並べ替え検定は分布を一切仮定していません。両者が近いのは、今回データが実際に正規だから。正規でない・小標本・外れ値があるときは、並べ替え検定の方が頑健です。

3. 帰無が正しいときは有意にならない

検定が正しく機能するには、差がないとき(H0H_0 が真)に有意になりすぎないことが必要です。両群を同じ N(0,1)\mathcal{N}(0,1) から取って確かめます。

import numpy as np

# 乱数シードを固定
rng = np.random.default_rng(53)

A = rng.normal(0, 1, 40)
B = rng.normal(0, 1, 40)               # 真に差がない
observed = B.mean() - A.mean()
combined = np.concatenate([A, B])
P = 20000
perm = np.empty(P)
for p in range(P):
    rng.shuffle(combined)
    perm[p] = combined[40:].mean() - combined[:40].mean()

print(f"観測した差 = {observed:.4f}")
print(f"並べ替え検定 p値 = {(np.abs(perm) >= np.abs(observed)).mean():.4f}")

出力:

観測した差 = 0.1801
並べ替え検定 p値 = 0.4869

出力の意味:真に差がない2群では、観測差 0.18 は帰無分布のごく普通の位置にあり、p=0.49(有意でない)。検定が誤って差を主張しない(第一種の過誤を制御している)ことの確認です。並べ替え検定は、H0H_0 の下での正確な(exact、有限標本で厳密な)検定になりうる点が理論的な美点です。

4. 使いどころ

数式の直観的意味

並べ替え検定は「もし群分けが本当に意味を持たないなら、いま観測したような差は偶然どれくらい出るか」を、実際にラベルを混ぜて数える操作です。H0H_0 の核心は交換可能性(exchangeability)——データの並び順・群ラベルが結果に関係ないこと。これが成り立つなら、観測されたラベル配置は「ありうる全配置のひとつ」にすぎず、特別扱いする理由がない。だから全配置(の標本)に対する観測差の順位が、そのまま有意性になる。t 検定が「正規分布という理論的な帰無分布」を使うのに対し、並べ替え検定は「データ自身をシャッフルした経験的な帰無分布」を使う——理論分布をデータ駆動の帰無分布に置き換えたのが本質で、これが頑健性の源です。

⚠️ よくある誤解・落とし穴

対応シミュレーション参照

本文の2群平均差の並べ替え検定(差あり default_rng(52)/差なし default_rng(53))。

関連ノート