ノンパラメトリック検定の周辺概念をクイックアクセス:
このページを高速ナビゲートするための索引チップです。クリックで該当セクションへ。
🍰 まずはやさしく
データの形を決めない自由な検定です。
どんな分布のデータでも分析するために使います。
極端に高い買い物などの外れ値がある時に便利です。
この章ではノンパラメトリック検定の結論を学びます。
ノンパラメトリック検定は、 母集団分布について強い仮定をしない検定群。 「データが正規分布に従う」必要がない。
| パラメトリック | ノンパラメトリック | 用途 |
|---|---|---|
| 1標本 t検定 | Wilcoxon符号付き順位 | 中央値の検定 |
| 対応のあるt検定 | Wilcoxon符号付き順位 | 前後比較 |
| 独立2標本 t検定 | Mann-Whitney U(Wilcoxon順位和) | 2群比較 |
| 一元配置 ANOVA | Kruskal-Wallis | 3群以上比較 |
| 反復測定 ANOVA | Friedman 検定 | 3条件以上 |
| Pearson相関 | Spearman, Kendall | 順位相関 |
🍰 まずはやさしく
分布に縛られない統計の手法です。
データの形が分からない時に正しく判断するために使います。
部活のアンケートなど、順位だけのデータに役立ちます。
このページでは用語の意味と使い方を解説します。
論文中に 「ノンパラメトリック検定」として登場する用語。
ノンパラメトリック検定 とは:分布の形を仮定しない検定法(順位ベース等)。外れ値や非正規分布データに強い。
このページは ノンパラメトリック手法 を解説する用語ページです。
カテゴリ:統計的手法
ジャストインタイム型データサイエンス教育の一環として、必要な時に参照し、関連概念とともに学べる構成になっています。
基準ページ:correlation.html(149KB、12セクション、SSDSE-B 実値計算)と同等以上の品質を目指しています。
🍰 まずはやさしく
データの「順位」に注目する考え方です。
平均ではなく中央値で差を比べるために使います。
東京のように人口が飛び抜けて多い地域の分析に便利です。
ここでは直感的なイメージと選び方を学びます。
母集団の分布形状を仮定しない統計手法群。正規性に依存しないため外れ値や歪んだ分布に頑健。順位(ランク)に変換するか、リサンプリング(ブートストラップ等)で推論する。
| 場面 | ノンパラ手法の選び方 |
|---|---|
| SSDSE-B-2026 の都道府県人口(東京が外れ値) | 平均ではなく中央値で要約し、 2 群比較は Mann-Whitney U 検定で順位差を見る |
| 所得・物価などの歪んだ分布 | Wilcoxon 符号順位検定で対応のあるデータを正規性に依存せず比較 |
| 3 都市圏×食料消費の比較 | Kruskal-Wallis 検定で 3 群以上の中央値差を検定(ANOVA の代替) |
| 非線形な単調関係(教育費 vs 進学率) | Pearson の代わりに Spearman 順位相関で単調関係を捉える |
ノンパラメトリック検定は「正規性などの分布仮定を置かない」検定群。 ここでは「パラ vs ノンパラ」「順位ベースの考え方」「外れ値耐性」を概念図で押さえる。
🍰 まずはやさしく
数値ではなく順位を使う仕組みです。
外れ値の影響を小さくして分析するために使います。
スマホの利用時間のランキングのようなデータに有効です。
ここでは具体的な計算の仕組みについて読みます。
多くのノンパラ検定は、 値そのものではなく順位(rank)に基づきます。 これにより:
ノンパラメトリック手法 の中心となる数式・定義は次の通りです。
$$ \hat{F}_n(x) = \frac{1}{n}\sum_{i=1}^n \mathbf{1}(X_i \leq x) $$
パラメトリック検定は仮定が正しいときに最大の検出力を持つ。 仮定が崩れるとノンパラの方が頑健で高い検出力。 一般則:
2023 年度・47 都道府県の「年平均気温(列 B4101)」を 8 地方ブロックに分け、 Kruskal-Wallis 検定で分布差を調べます。 併せて一元配置 ANOVA を走らせ、 順位ベース検定とパラメトリック検定の結論を見比べます(気温は北ほど低く南ほど高いので、 地方差がはっきり出る題材)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import pandas as pd from scipy import stats # 2 行目(日本語見出し行)を飛ばし、英字コードを列名として読む df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年度の 47 都道府県だけ抽出 def region(code): # 地域コード R0X000 -> 8 地方ブロック n = int(str(code)[1:3]) if n == 1: return '北海道' if 2 <= n <= 7: return '東北' if 8 <= n <= 14: return '関東' if 15 <= n <= 23: return '中部' if 24 <= n <= 30: return '近畿' if 31 <= n <= 35: return '中国' if 36 <= n <= 39: return '四国' return '九州沖縄' df['region'] = df['Code'].apply(region) # B4101 = 年平均気温(℃)を 8 地方ブロックで比較 groups = [df.loc[df['region'] == r, 'B4101'].values for r in df['region'].unique()] H, p_kw = stats.kruskal(*groups) F, p_aov = stats.f_oneway(*groups) print(f'Kruskal-Wallis : H = {H:.2f}, p = {p_kw:.4f}') print(f'One-way ANOVA : F = {F:.2f}, p = {p_aov:.4f}') |
実行結果(2023 年度の実データ): H ≈ 31.65, p_kw < 0.001、 F ≈ 13.38, p_aov < 0.001。 どちらも 1% 水準で有意で、 「地方ブロックによって年平均気温の分布が異なる」と結論できる(北の北海道・東北が低く、 南の九州沖縄が高い)。 8 群のうち北海道は 1 県だけなど群サイズが小さく正規性も怪しいので、 主結果には順位ベースの Kruskal-Wallis を採るのが無難。
1 2 3 4 5 6 7 8 9 10 11 | from itertools import combinations regions = df['region'].unique() k = len(regions) m = k*(k-1)//2 # 比較数 print(f'比較数 = {m}, Bonferroni 補正後の α = {0.05/m:.4f}') for r1, r2 in combinations(regions, 2): a = df.loc[df.region==r1, 'B4101'] b = df.loc[df.region==r2, 'B4101'] U, p = stats.mannwhitneyu(a, b, alternative='two-sided') mark = '*' if p < 0.05/m else ' ' print(f'{mark} {r1:<5s} vs {r2:<5s} U={U:6.1f} p={p:.4f}') |
1 2 3 4 | import scikit_posthocs as sp pvals = sp.posthoc_dunn(df, val_col='B4101', group_col='region', p_adjust='holm') print(pvals.round(3)) |
政府統計の総合窓口 e-Stat が公開する SSDSE-B-2026.csv(47都道府県×項目)を用いた具体的計算例を示します。
例として 2023 年度の「年平均気温(B4101)」と「消費支出(L3221、 二人以上の世帯)」の Spearman 順位相関を取ると ρ ≈ −0.305(p ≈ 0.037、 Pearson の r ≈ −0.23 よりやや強めに検出)。 気温の低い(寒い)地方ほど消費支出がやや大きい、 という弱い単調傾向が読める。
| 項目 | 値・指標 |
|---|---|
| データ件数 | 47 都道府県 |
| 対象指標 | 年平均気温(B4101)・消費支出(L3221)など |
| 計算結果 | 上記説明参照 |
合成 2 群でランクに基づく U 統計量を計算する。
| 群 | 値 | ランク |
|---|---|---|
| A | 3,5,7 | 2,4,5 |
| B | 2,4,8 | 1,3,6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # ── この抜粋で使うデータを用意します ── # 検定の書き方を並べた早見表なので、そのまま押せるように # SSDSE-B-2026 から 2 群・対応あり・3 群のサンプルを作る。 import numpy as np import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県 temp = df['B4101'].astype(float).values # 年平均気温 group1 = g1 = temp[:24] # 北海道〜静岡 group2 = g2 = temp[24:] # 愛知〜沖縄 group3 = g3 = df['A4103'].astype(float).values # 合計特殊出生率 data = temp # 1 標本検定用 mu0 = float(temp.mean()) # 対応のあるデータ(同じ 47 県の 2012 年と 2023 年) _all = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) before = _all[_all['SSDSE-B-2026'] == 2012]['A1101'].astype(float).values after = _all[_all['SSDSE-B-2026'] == 2023]['A1101'].astype(float).values cond1, cond2, cond3 = before, after, (before + after) / 2 x = df['A1101'].astype(float).values y = df['A4101'].astype(float).values observed = np.array([[20, 15], [12, 18]]) # クロス集計の例 from scipy import stats A = [3, 5, 7] B = [2, 4, 8] U, p = stats.mannwhitneyu(A, B) print(f"U = {U}") print(f"p = {p:.3f}") |
💬 手計算 (Step 2) U=5 と Python 出力が完全一致。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # ── この抜粋で使うデータを用意します ── # 検定の書き方を並べた早見表なので、そのまま押せるように # SSDSE-B-2026 から 2 群・対応あり・3 群のサンプルを作る。 import numpy as np import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県 temp = df['B4101'].astype(float).values # 年平均気温 group1 = g1 = temp[:24] # 北海道〜静岡 group2 = g2 = temp[24:] # 愛知〜沖縄 group3 = g3 = df['A4103'].astype(float).values # 合計特殊出生率 data = temp # 1 標本検定用 mu0 = float(temp.mean()) # 対応のあるデータ(同じ 47 県の 2012 年と 2023 年) _all = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) before = _all[_all['SSDSE-B-2026'] == 2012]['A1101'].astype(float).values after = _all[_all['SSDSE-B-2026'] == 2023]['A1101'].astype(float).values cond1, cond2, cond3 = before, after, (before + after) / 2 x = df['A1101'].astype(float).values y = df['A4101'].astype(float).values observed = np.array([[20, 15], [12, 18]]) # クロス集計の例 from scipy import stats a, b = group1, group2 g4 = df['L3221'].astype(float).values data_per_condition = [cond1, cond2, cond3] diff = after - before # Mann-Whitney U(独立2標本) u, p = stats.mannwhitneyu(group1, group2, alternative='two-sided') # Wilcoxon 符号付き順位(対応のあるデータ) w, p = stats.wilcoxon(before, after) # Kruskal-Wallis(3群以上) h, p = stats.kruskal(group1, group2, group3) # Friedman 検定(反復測定) f, p = stats.friedmanchisquare(cond1, cond2, cond3) # Spearman 相関 rho, p = stats.spearmanr(x, y) # Kendall's tau tau, p = stats.kendalltau(x, y) |
1 2 3 4 5 6 7 8 9 10 11 | from scipy import stats # 2 群独立:Mann-Whitney U U, p = stats.mannwhitneyu(a, b, alternative='two-sided', method='auto') # 2 群対応:Wilcoxon 符号順位 W, p = stats.wilcoxon(x, y, zero_method='wilcox', correction=True) # k 群独立:Kruskal-Wallis H, p = stats.kruskal(g1, g2, g3, g4) # k 群対応:Friedman chi2, p = stats.friedmanchisquare(*data_per_condition) # 符号検定(scipy 1.10+) res = stats.binomtest(np.sum(diff > 0), n=np.sum(diff != 0), p=0.5) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # ── この抜粋で使うデータを用意します ── import numpy as np import pandas as pd import pingouin as pg df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年の 47 都道府県 df = df.copy() _no = df['Code'].str[1:3].astype(int) df['region'] = np.select( [_no <= 7, _no <= 14, _no <= 23, _no <= 30, _no <= 35, _no <= 39], ['北海道東北', '関東', '中部', '近畿', '中国', '四国'], default='九州沖縄') _t = df['B4101'].astype(float).values a, b = _t[:24], _t[24:] x = df['A1101'].astype(float).values y = df['A4101'].astype(float).values # Mann-Whitney + 効果量 r + CI print(pg.mwu(a, b)) # Kruskal-Wallis + η² print(pg.kruskal(data=df, dv='B4101', between='region')) # Wilcoxon + 効果量 print(pg.wilcoxon(x, y)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import pandas as pd import numpy as np import scikit_posthocs as sp # この抜粋だけで動くように、群 g と値 y を持つ長形式データを作る _np = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _latest = _np[_np['SSDSE-B-2026'] == 2023].copy() _latest['g'] = pd.cut(_latest['Code'].str[1:3].astype(int), bins=[0, 13, 23, 35, 47], labels=['東日本', '中部', '西日本', '九州沖縄']) _latest['y'] = _latest['A1303'] / _latest['A1101'] * 100 # 高齢化率(%) df = _latest[['g', 'y']].dropna() # 対応のない k 群の多重比較 print('--- Dunn (holm) ---') print(sp.posthoc_dunn(df, val_col='y', group_col='g', p_adjust='holm').round(3)) print('--- Conover (fdr_bh) ---') print(sp.posthoc_conover(df, val_col='y', group_col='g', p_adjust='fdr_bh').round(3)) # Nemenyi (Friedman 後) は「行=同じ対象 × 列=条件」の行列を渡す。 # ここでは 47 都道府県 × 4 時点(繰り返し測定)で作る _np['y'] = _np['A1303'] / _np['A1101'] * 100 data_matrix = (_np.pivot_table(index='Prefecture', columns='SSDSE-B-2026', values='y') [[2012, 2016, 2020, 2023]].dropna()) print('--- Nemenyi (Friedman 後, 47 県 × 4 時点) ---') print(f'行列の形: {data_matrix.shape}') print(sp.posthoc_nemenyi_friedman(data_matrix.to_numpy()).round(4)) |
1 2 3 4 5 6 7 | from scipy.stats import permutation_test def diff_median(x, y, axis=0): return np.median(x, axis=axis) - np.median(y, axis=axis) res = permutation_test((a, b), diff_median, n_resamples=20000, alternative='two-sided', random_state=0) print(f'observed diff = {res.statistic:.3f}, p = {res.pvalue:.4f}') |
1 2 3 4 5 6 7 8 9 10 | from scipy.stats import bootstrap import numpy as np def cliffs_delta(x, y): n = len(x) * len(y) return (np.sum(x[:,None] > y[None,:]) - np.sum(x[:,None] < y[None,:])) / n res = bootstrap((a, b), cliffs_delta, paired=False, n_resamples=5000, confidence_level=0.95) print('Cliffs δ 95% CI =', res.confidence_interval) |
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd from scipy.stats import spearmanr, mannwhitneyu df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023 年度の 47 都道府県 temp = df['B4101'] # 年平均気温 cons = df['L3221'] # 消費支出(二人以上の世帯) rho, p_s = spearmanr(temp, cons) # 順位相関 ρ ≈ -0.305 u, p_u = mannwhitneyu(temp[:24], temp[24:]) # 前半/後半の県で気温を比較 print(f'Spearman rho={rho:.3f}, p={p_s:.4g}') print(f'Mann-Whitney U={u:.1f}, p={p_u:.4g}') |
上記コードは pandas / numpy / scipy / sklearn / statsmodels の標準的なライブラリを用い、SSDSE-B-2026.csv を直接読み込んで計算します(合成データ不使用)。
下の図は説明用の架空データ(A店・B店の 1 日あたり売上〔万円〕、各 n = 8)です。上の帯が実際の値、下の帯が順位(1〜16 位)で、灰色の対応線が「どの値がどの順位に落ちるか」を示します。B店の赤い点を左右にドラッグして極端な外れ値にしてみてください。平均ベースの t 検定(Welch)の p 値は大きく揺れるのに、順位ベースの Mann-Whitney U の p 値はほとんど動かないことがリアルタイムで確認できます。スライダーまたは再生ボタンで「値 → 順位」への変換過程もアニメーション表示できます。
※ データは説明用の架空値(SSDSE 実測値ではありません)。p 値はページ内 JavaScript で厳密に計算しています:t 検定は Welch 法(自由度は Welch–Satterthwaite 近似、p 値は t 分布の正則化不完全ベータ関数)、Mann-Whitney U はタイ補正+連続性補正つき正規近似。いずれも scipy.stats.ttest_ind(equal_var=False) / mannwhitneyu(method='asymptotic') の出力と一致することを検証済みです。
順位変換のもうひとつの重要な帰結が単調変換不変性だ。データ全体に log や平方根などの単調増加変換をかけても、大小関係は保存されるので順位は 1 ミリも変わらない。したがって Mann-Whitney U や Spearman ρ の値・p 値は対数変換の前後で完全に同一になる。t 検定や Pearson 相関は変換のたびに結果が変わるから、「対数を取るべきか否か」で悩む場面では、順位ベース手法が「変換の選択に依存しない結論」を与えてくれる。上のウィジェットで赤い点をどれだけ右に引っ張っても p 値が変わらないのは、この不変性の特殊ケース(最大値をさらに大きくする変換)を体感していることに他ならない。
ノンパラメトリック=順位検定、ではない。分布形を仮定しない道具は大きく 3 系統ある。①順位系(本ページ:Mann-Whitney・Kruskal-Wallis・Spearman 順位相関)、②リサンプリング系:ブートストラップは再標本化で任意の統計量の信頼区間を、並べ替え検定はラベルのシャッフルで厳密な p 値を、分布仮定なしに構成する。③ノンパラ推定系:カーネル密度推定は「分布そのものの形」をデータから直接推定する(ヒストグラムの滑らか版)。外れ値への対処という文脈では外れ値・ロバスト統計のページ、パラメトリック側との使い分けはt 検定のページの使い分けナビが隣接する。
Mann-Whitney U や Kruskal-Wallis は、 厳密には「中央値の検定」ではなく「分布が確率的に大きいか小さいか(stochastic dominance)」を検定している。 分布の形が大きく違う(一方が右に裾を引く等)と、 中央値が等しくても有意になりうる。 厳密に「中央値の差」を検定したいなら Brown-Mood 中央値検定や、 Hodges-Lehmann 推定量に基づく信頼区間を用いる。 教科書通りに「中央値の比較」と書いて投稿査読で指摘されることが多い。
「外れ値が怖いから何でもノンパラ」というのは過剰な保守。 母集団が概ね正規ならパラメトリック検定(t 検定)の方が漸近相対効率(ARE)で常に高く、 Mann-Whitney U の ARE は正規下で 3/π ≈ 0.955 にしかならない。 つまり同じ検出力を得るのに 5% 多くサンプルが必要。 まず正規性プロット(Q-Q)・Shapiro 検定で確認し、 明らかに正規でない場合のみノンパラに切り替える、 という順序が標準。
順序データやカウントデータでは同値が頻発し、 Mann-Whitney U の正規近似 p 値が不正確になる。 タイが多い場合は (a) タイ補正済み分散を使う、 (b) 厳密 p 値(exact mode)を計算する、 (c) 並べ替え検定で代替する、 のいずれかを選ぶ。 scipy.stats.mannwhitneyu は method='exact' でタイがあると警告を出す。 N が大きく exact が計算困難なら permutation test に切り替える。
Kruskal-Wallis で有意になったあと、 ペアワイズ Mann-Whitney U を 28 ペア(8 群)打って、 補正なしで「ここが有意!」と報告する事故が多い。 これでは family-wise error rate が α = 1 - (1-0.05)^28 ≈ 76% にまで膨らむ。 Bonferroni(保守的)、 Holm(手堅い)、 Benjamini-Hochberg(FDR)のいずれかを必ず適用。 scikit_posthocs.posthoc_dunn は p_adjust 引数で指定可能。
p 値だけ書いて効果量を出さないのは現代統計の悪習。 Mann-Whitney U なら r = Z/√N、 rank-biserial 相関 r_rb、 もしくは Cliff's δ を報告するのが標準。 Wilcoxon 符号順位なら r = Z/√N、 もしくは Hedges' g に変換。 サンプルが少ない時は信頼区間(ブートストラップ)を併記すると説得力が増す。 査読者は p 値より効果量と CI を重視する傾向が強い。
Wilcoxon signed-rank test は「差の分布が中央値ゼロを中心に対称」という仮定を置く。 対称性が崩れる(強く歪んだ差分分布)と、 検定の解釈は「中央値ゼロ」ではなく「分布のシフト」になる。 対称性が怪しい場合は符号検定(sign test、 差の符号だけを見る)の方が頑健だが、 検出力は落ちる。 ヒストグラムと QQ プロットで対称性を必ず確認すること。
ノンパラメトリック検定 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 推測統計 › 検定 › ノンパラメトリック検定
中心に ノンパラメトリック検定 を置き、 そこから t検定・Kruskal-Wallis・中央値・p値・F検定・χ²検定 など 計 11 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「ノンパラメトリック検定」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「ノンパラメトリック検定」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは ノンパラメトリック検定 の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → 検定 → ノンパラメトリック検定 という入れ子の位置を示します。 「検定には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
「ノンパラメトリック検定」は単独で完結せず、 前後の手法と組み合わさって価値が発揮される。 入力データの準備 (上流)・同目的の代替手法との比較 (並列)・結果の活用 (下流) という 3 軸で隣接領域を整理する。
この上流・並列・下流の対応を地図化することで、 「ノンパラメトリック検定」を中核に据えた分析パイプライン (データ準備 → 手法選択 → 結果の検証と展開) の全体像が見えてくる。
「nonparametric」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。
| シナリオ | 重視する観点 | 候補手法 |
|---|---|---|
| データが大規模 (n が多い、 高次元) | 計算コスト / メモリ / 並列化が必要 | ビジネス理解 等 |
| 外れ値が多い / ノイズあり | 頑健性 / 外れ値除去 / 中央値ベース | データ理解 等 |
| 解釈性を重視する | 線形 / 木構造 / ルールベース | データ準備 等 |
| 予測精度を最優先する | アンサンブル / ハイパラ調整 / 交差検証 | モデリング 等 |
| データが少ない | 正則化 / ベイズ / 転移学習 / 簡素なモデル | データアナリスト 等 |
| リアルタイム/オンライン処理 | ストリーミング / 軽量モデル / 逐次更新 | データサイエンティスト 等 |
パラメトリック検定は「母集団は正規分布 N(μ, σ²)」のように分布の形をパラメータ(μ, σ)で完全に指定し、そのパラメータについて推論する。ノンパラメトリック検定はこの一歩を踏まない。「分布の形は分からない・仮定したくない」という前提から出発し、形に依存しない情報=順位(rank)や符号(sign)だけを取り出して推論する。値そのものを捨てて順位に置き換えることは、いわば各国通貨を「順位」という共通通貨に両替する操作にあたる。両替すれば、元が円でもドルでも(正規でも対数正規でも)同じ土俵で比較でき、しかも 1 兆円のような極端値も「最上位という 1 つの順位」に丸め込まれる。
順位検定の核心は、帰無仮説が正しいとき、順位の並びは母集団分布の形と無関係に決まる点にある。たとえば Mann-Whitney U 検定では「2 群は同じ分布から来た」という帰無仮説のもとで、全データを混ぜて順位を振ると、どの順位がどちらの群に来るかは純粋な組合せ(何通りの割り当てがあるか)だけで決まる。母集団が正規でも歪んでいても、この組合せ構造は変わらない。だから帰無分布(p 値を測る物差し)を分布の形を知らなくても計算できる。これが「分布フリー(distribution-free)」の正体であり、正規性という仮定を丸ごと不要にする仕組みである。パラメトリック側の対応表・使い分けは t 検定・ANOVA のページと往復すると理解が深まる。
| 観点 | パラメトリック(例:t 検定) | ノンパラ(例:Mann-Whitney U) |
|---|---|---|
| 何を仮定するか | 分布形(正規性)+独立性+(等分散) | 分布形は仮定せず。独立性・連続性等は残る |
| 何を使うか | 実測値そのもの(間隔情報) | 順位・符号(順序情報のみ) |
| 得意な場面 | 仮定が成り立つ・大標本・高い検出力が欲しい | 小標本・外れ値・歪み・順序尺度 |
要は「仮定を強くして情報を全部使う」か「仮定を弱くして順序だけ使う」かのトレードオフである。どちらが上位というものではなく、データの素性で選ぶ。中央値の直感は 中央値、順位の下地は 四分位・箱ひげ図 のページが補完する。
上の「6 つの典型ミス」に加え、実データで最も誤解されやすい 2 点を SSDSE-B-2026(2023 年度・47 都道府県)の実測で確認する。いずれも合成データではなく、下のコードをそのまま実行すれば再現できる。
2023 年の 高齢化率(65 歳以上人口 A1303 ÷ 総人口 A1101 × 100)と 年平均気温(B4101)の関連を、Pearson・Spearman・Kendall で測ると次のようになる(実測値)。
| 指標 | 係数 | p 値 | 5% で有意? |
|---|---|---|---|
| Pearson r(線形・パラメトリック) | −0.445 | 0.0017 | ✅ 有意 |
| Spearman ρ(順位) | −0.264 | 0.073 | ❌ 非有意 |
| Kendall τ(順位) | −0.185 | 0.069 | ❌ 非有意 |
「寒い地方ほど高齢化が進む」という負の関連はどの指標も向きは同じだが、Pearson は 1% 水準で有意なのに、順位ベースの Spearman・Kendall は 5% でも有意にならない。順位化で間隔情報(沖縄が飛び抜けて暖かい、など)を捨てた結果、検出力が落ちて有意性を取りこぼしている。これは落とし穴②「正規性が成り立つのにノンパラを使い検出力を失う」の実例であり、「ノンパラの方が安全=常に良い」ではないことを示す。順位化はタダではなく、情報損失=検出力の代償を伴う。
ただし A の話には裏がある。上の Pearson の強さは、沖縄(高齢化率 23.8%・年平均気温 23.8℃)という「若くて非常に暖かい」てこ点(leverage point)に支えられている面がある。沖縄 1 県を除くと Pearson r は −0.445 → −0.333(p=0.024)へ大きく縮む一方、Spearman ρ は −0.264 → −0.217(p=0.148)とほとんど動かない。つまり Pearson は 1 点の極端値に敏感、順位ベースは頑健、というお馴染みのトレードオフがここでも成り立つ。「Pearson が強い=本当に強い関連」とは限らず、てこ点が押し上げているだけかもしれない。順位相関との食い違いは、外れ値・非線形を疑うシグナルとして使う(外れ値・ロバスト統計 のページ参照)。
高齢化率を 東日本(都道府県コード 1〜23)と 西日本(24〜47)で Mann-Whitney U 検定にかけると、中央値は東 31.23%・西 32.57% だが U = 231.0, p = 0.344 で有意差なし(Welch の t 検定でも p = 0.426 で一致)。ノンパラ検定で有意にならないのは「差がない証拠」ではなく「差を検出できるだけの情報がなかった」だけ、という点に注意(p 値・検出力分析)。加えて、ノンパラでも独立性の仮定は外せない:47 都道府県を独立標本として扱えるかは別問題で、地理的な空間相関があれば前提が崩れる。「分布フリー=仮定ゼロ」ではないことを、この点は改めて思い出させてくれる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import pandas as pd import numpy as np from scipy import stats df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].copy() # 2023 年度・47 都道府県 df['aging'] = df['A1303'] / df['A1101'] * 100 # 高齢化率(65歳以上人口比率) # A: 高齢化率 vs 年平均気温 — Pearson は有意・順位相関は非有意 print('Pearson :', stats.pearsonr(df['aging'], df['B4101'])) # r=-0.445, p=0.0017 print('Spearman:', stats.spearmanr(df['aging'], df['B4101'])) # rho=-0.264, p=0.073 print('Kendall :', stats.kendalltau(df['aging'], df['B4101'])) # tau=-0.185, p=0.069 # B: 沖縄(てこ点)を除くと Pearson は縮み Spearman は不動 d2 = df[~df['Prefecture'].str.contains('沖縄')] print('w/o沖縄 Pearson :', stats.pearsonr(d2['aging'], d2['B4101'])) # r=-0.333, p=0.024 print('w/o沖縄 Spearman:', stats.spearmanr(d2['aging'], d2['B4101'])) # rho=-0.217, p=0.148 # C: 東日本 vs 西日本の高齢化率 — Mann-Whitney U df['pref_no'] = df['Code'].apply(lambda c: int(str(c)[1:3])) east = df.loc[df['pref_no'] <= 23, 'aging'] west = df.loc[df['pref_no'] >= 24, 'aging'] print('東 median=%.2f, 西 median=%.2f' % (east.median(), west.median())) # 31.23 / 32.57 print(stats.mannwhitneyu(east, west, alternative='two-sided')) # U=231.0, p=0.344 |
※ 数値はいずれも SSDSE-B-2026.csv(2023 年度・47 都道府県)の実測。合成データは使用していません。丸めは小数第 3〜4 位。
Mann-Whitney U・Wilcoxon 符号順位・Kruskal-Wallis は別々の検定に見えるが、いずれも「順位に置き換えてから、群ごとの順位和(または順位平均)が偏っていないか」を見る点で一貫している。
| 検定 | データ構造 | 統計量の骨子 | パラメトリック対応 |
|---|---|---|---|
| Wilcoxon 順位和 = Mann-Whitney U | 独立 2 群 | 一方の群の順位和 R から U=R−n(n+1)/2 | 独立 t 検定 |
| Wilcoxon 符号順位 | 対応 2 群 | 差の絶対値を順位化し、正の差の順位和 W⁺ | 対応 t 検定 |
| Kruskal-Wallis | 独立 k 群 | 各群の順位平均のばらつき H(χ² 近似) | 一元配置 ANOVA |
| Friedman | 対応 k 群 | ブロック内順位の群間ばらつき | 反復測定 ANOVA |
| Spearman ρ | 2 変量の関連 | 順位に変換してから Pearson 相関を計算 | Pearson 相関 |
帰無仮説のもとでは順位和の期待値・分散が組合せだけで閉じた式になる(例:Mann-Whitney U の平均 n₁n₂/2、分散 n₁n₂(N+1)/12)。小標本では全組合せから厳密分布を、大標本では正規(または χ²)近似を使う。同順位があると分散を縮めるタイ補正が入る。
順位検定は「順序」に情報を落とすが、並べ替え検定(permutation test)は値をそのまま使いながら分布仮定を外す。群ラベルを何度もシャッフルして「もし群に差がなければ得られたはずの統計量の分布」を実際に作り、観測値がその裾にあるかで p 値を測る。中央値差でも平均差でも任意の統計量で検定を組めるのが強みで、並べ替え検定 のページが詳しい。もう一方の ブートストラップは、標本から復元抽出を繰り返して効果量(Cliff の δ、Hodges-Lehmann 推定量など)の信頼区間を分布仮定なしに構成する。p 値中心になりがちなノンパラ検定に、効果量と区間推定を補うのが現代的な作法である。
検定だけがノンパラではない。経験分布関数 F̂ₙ(このページ冒頭の数式)は母集団分布を階段関数で近似し、カーネル密度推定(KDE)はそれを滑らかにして「分布の形」を直接描く(ヒストグラムの連続版)。2 標本が同じ分布かを形ごと比べる Kolmogorov-Smirnov 検定は F̂ₙ の最大差を統計量にする。回帰では、外れ値・非線形に強い 分位点回帰や LOWESS がノンパラ推定の代表格である。
分布全体は仮定しないが、関心のあるパラメータ(回帰係数など)だけはパラメトリックに扱うセミパラメトリックな手法群もある。代表は生存時間解析の Cox 比例ハザードモデル:ベースラインハザードの形は自由(ノンパラ)にしつつ、共変量の効果は係数(パラメトリック)で推定する。「分布形の仮定は避けたいが、係数の解釈は欲しい」という実務ニーズに応える中間路線であり、ノンパラ(仮定最小・解釈は弱め)とパラメトリック(仮定強め・解釈は明快)のスペクトル上に位置づけると全体像が掴める。