適合度検定の体系 — χ²・KS・Anderson-Darlingを比較して理解する

統計モデルを使う際、「データが仮定した分布に本当に従っているか」を確認することは極めて重要です。正規分布を仮定して $t$ 検定を行ったのに、実際のデータが正規分布から大きくずれていたら、検定の結論は信頼できません。ポアソン回帰を行うなら、カウントデータが本当にポアソン分布に従うかを確認すべきです。

このような「データと理論分布の適合性」を統計的に評価する手法を総称して適合度検定(goodness-of-fit test)と呼びます。適合度検定には複数の手法があり、それぞれ異なる「不適合の測り方」をします。

適合度検定を体系的に理解すると、以下のような応用が可能です。

  • モデル診断: 回帰モデルの残差が正規分布に従うかの確認に使われます
  • 品質管理: 製品の特性値が仕様の分布に従っているかの検査に利用されます
  • 乱数検証: シミュレーションの乱数生成器が正しい分布を出力しているかを検証します
  • 保険数理: 損害額の分布が仮定した分布(ワイブル分布、対数正規分布など)に適合するかの検定に使われます

本記事の内容

  • 3大適合度検定($\chi^2$検定・KS検定・Anderson-Darling検定)の理論的な比較
  • 各検定の検定統計量の意味と導出
  • 検出力の違いと使い分けの指針
  • Pythonによる実装と比較シミュレーション

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

適合度検定とは何か — 3つのアプローチ

問題の設定

適合度検定の一般的な設定は次の通りです。

$$ H_0: F = F_0 \quad \text{vs.} \quad H_1: F \neq F_0 $$

手元のデータ $X_1, X_2, \dots, X_n$ が帰無仮説の分布 $F_0$ に従うかどうかを検定します。

「データと分布のずれ」を測る方法は一通りではありません。3つの主要な適合度検定は、このずれを異なる方法で定量化します。

3つのアプローチの概要

アプローチ1: ビン分割 → 度数比較($\chi^2$ 適合度検定)

データをいくつかのビン(区間)に分割し、各ビンの観測度数と期待度数を比較します。度数のカウントに基づくため、離散データにも連続データにも適用できますが、ビンの取り方に結果が依存するという問題があります。

アプローチ2: 最大乖離(KS検定)

経験分布関数(EDF)と理論的なCDFの間の最大乖離を見ます。ビン分割が不要で分布自由性を持ちますが、CDFの中央付近の乖離に敏感で裾の乖離には鈍感です。

アプローチ3: 重み付き二乗乖離(Anderson-Darling検定)

EDFとCDFの二乗乖離を、裾に重みを付けて積分します。KS検定の弱点(裾への鈍感さ)を克服し、正規性の検定など裾の振る舞いが重要な場面で高い検出力を発揮します。

これら3つの手法を順番に詳しく見ていきましょう。

$\chi^2$ 適合度検定

ピアソンの $\chi^2$ 統計量

$\chi^2$ 適合度検定は、カール・ピアソン(Karl Pearson)が1900年に提案した最も古典的な適合度検定です。

データの範囲を $k$ 個のビン(区間)$B_1, B_2, \dots, B_k$ に分割します。各ビンについて、観測度数 $O_i$(ビン $B_i$ に入るデータの数)と期待度数 $E_i$(帰無仮説のもとでビン $B_i$ に入るべきデータの期待数)を比較します。

$$ E_i = n \cdot P(X \in B_i | H_0) = n \cdot \int_{B_i} f_0(x)\,dx $$

ピアソンの $\chi^2$ 統計量は、各ビンの観測度数と期待度数のずれの二乗和として定義されます。

$$ \begin{equation} \chi^2 = \sum_{i=1}^{k} \frac{(O_i – E_i)^2}{E_i} \end{equation} $$

直感的には、各ビンで「予想からのずれ」を「予想の大きさ」で割って標準化し、それらを足し合わせたものです。$E_i$ で割ることで、期待度数の大きいビンと小さいビンを公平に扱います。

帰無分布

帰無仮説のもとで、$n$ が十分大きいとき、$\chi^2$ 統計量は漸近的にカイ二乗分布に従います。

$$ \chi^2 \xrightarrow{d} \chi^2(k – 1 – m) $$

自由度は $k – 1 – m$ です。$k$ はビンの数、$m$ はデータから推定したパラメータの数です。パラメータを推定しない場合($F_0$ が完全に指定されている場合)は $m = 0$ で自由度は $k – 1$ です。

$k – 1$ であって $k$ でない理由は、全ビンの度数の合計が $n$ に固定されるという1つの制約があるためです。

$\chi^2$ 検定の利点と欠点

利点: – 離散分布にも連続分布にも適用可能 – 計算が非常にシンプル – パラメータ推定の補正が明快(自由度を減らすだけ) – 多変量への拡張が容易

欠点: – ビンの選び方に結果が依存する – 情報の損失がある(連続データをビン分割するため) – 期待度数が小さいビンでは $\chi^2$ 近似が悪くなる(一般に各ビンの $E_i \geq 5$ が推奨される) – 連続分布に対する検出力はEDF検定(KS、AD)より一般に低い

ビンの選び方

$\chi^2$ 検定の結果はビンの選び方に依存するため、適切なビン分割が重要です。よく使われる方法は次の通りです。

  1. 等確率ビン: 各ビンの期待度数が等しくなるようにビンの幅を調整する。$E_i = n/k$ となるため、$\chi^2$ 近似の精度が最も良くなります
  2. 等幅ビン: データの範囲を等間隔に分割する。直感的ですが、裾のビンで期待度数が小さくなりがちです
  3. ビン数の選択: 一般的な目安として $k \approx 2n^{2/5}$ が推奨されます。$n = 100$ なら $k \approx 13$、$n = 1000$ なら $k \approx 32$ 程度です

$\chi^2$ 検定はビン分割に依存するという限界がありました。次に、ビン分割を必要としないEDF検定について見ましょう。

KS検定の復習と位置づけ

KS統計量の再確認

KS検定の記事で詳しく導出した通り、KS統計量はEDFと帰無仮説のCDFの最大乖離です。

$$ D_n = \sup_x |F_n(x) – F_0(x)| $$

KS検定はビン分割が不要で、連続分布に対しては分布自由性を持つという優れた性質があります。

KS検定の弱点 — 裾への感度の低さ

KS検定は $\sup$ 統計量(最大値統計量)であるため、EDF全体ではなく「最も乖離が大きい一点」だけで判定を行います。この性質から、CDFの中央付近での乖離には敏感ですが、裾の部分での乖離には鈍感になります。

なぜ裾で感度が低いのかを直感的に説明しましょう。CDFの裾($F_0(x)$ が0に近い領域や1に近い領域)では、EDFの値もほぼ0や1に固定されるため、EDFとCDFの乖離が構造的に小さくなります。分布の中央付近では、EDFが大きく変動する余地があるため、乖離も大きくなりやすいのです。

正規性の検定のように、裾の振る舞いが重要な場面ではKS検定は最適ではありません。この弱点を克服するのが次に説明するAnderson-Darling検定です。

Anderson-Darling検定

重み付き二乗乖離のアイデア

Anderson-Darling(AD)検定は、KS検定の改良版として1952年にT. W. AndersonとD. A. Darlingによって提案されました。KS検定が「最大乖離」を見るのに対し、AD検定は「重み付きの二乗乖離の積分」を見ます。

$$ \begin{equation} A^2 = n \int_{-\infty}^{\infty} \frac{[F_n(x) – F_0(x)]^2}{F_0(x)[1 – F_0(x)]}\,dF_0(x) \end{equation} $$

分母の $F_0(x)[1 – F_0(x)]$ は重み関数の逆数です。$F_0(x)$ が0に近い(左裾)や1に近い(右裾)で値が小さくなるため、重み $\frac{1}{F_0(x)[1 – F_0(x)]}$ は裾で大きくなります。つまり、AD検定は裾の乖離に大きな重みを付けて評価します。

この重み付けの効果により、AD検定は分布の裾の違いに対してKS検定よりもはるかに高い感度を持ちます。

計算式の導出

確率積分変換 $U_i = F_0(X_{(i)})$($X_{(i)}$ は $i$ 番目の順序統計量)を適用すると、$A^2$ は次のように計算可能な形になります。

$$ \begin{equation} A^2 = -n – \sum_{i=1}^{n} \frac{2i – 1}{n}\left[\ln U_i + \ln(1 – U_{n+1-i})\right] \end{equation} $$

ここで $U_i = F_0(X_{(i)})$ です。この式は閉じた形なので、数値積分は不要です。計算手順は次の通りです。

  1. データを昇順にソートする: $X_{(1)} \leq X_{(2)} \leq \cdots \leq X_{(n)}$
  2. $U_i = F_0(X_{(i)})$ を計算する
  3. 上の式に代入して $A^2$ を求める

帰無分布

KS検定と同様に、AD統計量も帰無仮説のもとで分布自由性を持ちます($F_0$ が完全に指定されている場合)。ただし、漸近分布はカイ二乗分布ではなく、KS検定のコルモゴロフ分布とも異なる固有の分布に従います。

$F_0$ のパラメータをデータから推定する場合は、帰無分布が変わります。正規分布に対する検定の場合のAD統計量の修正版は、リリフォース検定の代替として広く使われています。

EDF検定族の一般的な形

KS検定とAD検定は、より一般的なEDF検定の枠組みの中に位置づけられます。EDF検定の一般形は次のように書けます。

$$ \begin{equation} Q_n = n \int_{-\infty}^{\infty} [F_n(x) – F_0(x)]^2 \psi(F_0(x))\,dF_0(x) \end{equation} $$

重み関数 $\psi$ の選び方によって異なる検定が得られます。

検定 重み関数 $\psi(u)$ 特徴
クラメール・フォン・ミーゼス $\psi(u) = 1$ 一様な重み
Anderson-Darling $\psi(u) = \frac{1}{u(1-u)}$ 裾に大きな重み
ワトソン 修正版(循環データ用) 方向統計学

KS検定は $\sup$ 型なのでこの積分型の枠組みには直接入りませんが、概念的には同じEDF検定族の一員です。

3つの適合度検定の理論を一通り見ました。次に、Pythonで実装して性能を比較しましょう。

Pythonによる実装と比較

3つの適合度検定の実装

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

def chi2_goodness_of_fit(data, cdf_func, k=None):
    """χ²適合度検定"""
    n = len(data)
    if k is None:
        k = max(int(2 * n**(2/5)), 5)

    # 等確率ビン
    quantiles = np.linspace(0, 1, k + 1)
    bin_edges = [cdf_func(q) for q in quantiles]
    # 逆CDFが使えない場合は経験的に
    bin_edges = np.quantile(data, quantiles)
    bin_edges[0] = -np.inf
    bin_edges[-1] = np.inf

    O, _ = np.histogram(data, bins=bin_edges)
    E = np.full(k, n / k)

    chi2_stat = np.sum((O - E)**2 / E)
    p_value = 1 - stats.chi2.cdf(chi2_stat, df=k - 1)

    return chi2_stat, p_value

def anderson_darling_statistic(data, cdf_func):
    """Anderson-Darling統計量の計算"""
    n = len(data)
    x_sorted = np.sort(data)
    U = cdf_func(x_sorted)
    U = np.clip(U, 1e-10, 1 - 1e-10)  # 数値安定性

    i = np.arange(1, n + 1)
    A2 = -n - np.sum((2 * i - 1) / n * (np.log(U) + np.log(1 - U[::-1])))

    return A2

# --- テスト: 正規データに対する3検定 ---
np.random.seed(42)
n = 100

# 帰無仮説が正しい場合
data_null = np.random.randn(n)
# 対立仮説(t分布、裾が重い)
data_alt = np.random.standard_t(df=3, size=n)

print("=" * 60)
print("適合度検定の比較 (H0: N(0,1))")
print("=" * 60)

for label, data in [("正規データ (H0正しい)", data_null),
                     ("t(3)データ (H0正しくない)", data_alt)]:
    print(f"\n--- {label} ---")

    # KS検定
    D, p_ks = stats.kstest(data, "norm")
    print(f"KS検定:    D = {D:.4f}, p = {p_ks:.4f}")

    # AD統計量
    A2 = anderson_darling_statistic(data, stats.norm.cdf)
    # SciPyのAD検定
    ad_result = stats.anderson(data, dist="norm")
    print(f"AD検定:    A² = {A2:.4f} (SciPy: {ad_result.statistic:.4f})")
    print(f"  臨界値 (5%): {ad_result.critical_values[2]:.4f}")

    # χ²検定
    chi2, p_chi2 = chi2_goodness_of_fit(data, stats.norm.cdf)
    print(f"χ²検定:   χ² = {chi2:.4f}, p = {p_chi2:.4f}")

この結果から、3つの検定が同じデータに対して異なる感度を示すことがわかります。正規データに対してはいずれの検定もp値が大きく帰無仮説を棄却しませんが、t分布データに対してはAD検定が特に敏感に差を検出する傾向があります。

検出力の比較シミュレーション

3つの適合度検定の検出力を、異なるタイプの対立仮説で比較します。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(42)
n = 50
n_sim = 2000
alpha = 0.05

# 対立仮説のタイプ
# (1) 位置ずれ: N(delta, 1)
# (2) 裾の重さ: t(df) 分布
# (3) 歪み: 歪正規分布の近似

# --- (1) 位置ずれ ---
shifts = np.linspace(0, 1.0, 10)
power_ks_loc = []
power_ad_loc = []
power_chi2_loc = []

for delta in shifts:
    rej_ks, rej_ad, rej_chi2 = 0, 0, 0
    for _ in range(n_sim):
        data = np.random.normal(delta, 1, n)
        _, p = stats.kstest(data, "norm")
        if p < alpha: rej_ks += 1
        ad_res = stats.anderson(data, dist="norm")
        if ad_res.statistic > ad_res.critical_values[2]: rej_ad += 1
        # χ²検定(等確率ビン)
        k = 10
        edges = stats.norm.ppf(np.linspace(0, 1, k + 1)[1:-1])
        edges = np.concatenate([[-np.inf], edges, [np.inf]])
        O, _ = np.histogram(data, bins=edges)
        E = np.full(k, n / k)
        chi2_stat = np.sum((O - E)**2 / E)
        if chi2_stat > stats.chi2.ppf(1 - alpha, k - 1): rej_chi2 += 1

    power_ks_loc.append(rej_ks / n_sim)
    power_ad_loc.append(rej_ad / n_sim)
    power_chi2_loc.append(rej_chi2 / n_sim)

# --- (2) 裾の重さ ---
dfs = [100, 30, 15, 10, 7, 5, 4, 3]
power_ks_tail = []
power_ad_tail = []
power_chi2_tail = []

for df in dfs:
    rej_ks, rej_ad, rej_chi2 = 0, 0, 0
    for _ in range(n_sim):
        data = np.random.standard_t(df, n)
        _, p = stats.kstest(data, "norm")
        if p < alpha: rej_ks += 1
        ad_res = stats.anderson(data, dist="norm")
        if ad_res.statistic > ad_res.critical_values[2]: rej_ad += 1
        k = 10
        edges = stats.norm.ppf(np.linspace(0, 1, k + 1)[1:-1])
        edges = np.concatenate([[-np.inf], edges, [np.inf]])
        O, _ = np.histogram(data, bins=edges)
        E = np.full(k, n / k)
        chi2_stat = np.sum((O - E)**2 / E)
        if chi2_stat > stats.chi2.ppf(1 - alpha, k - 1): rej_chi2 += 1

    power_ks_tail.append(rej_ks / n_sim)
    power_ad_tail.append(rej_ad / n_sim)
    power_chi2_tail.append(rej_chi2 / n_sim)

fig, axes = plt.subplots(1, 2, figsize=(13, 5.5))

# 位置ずれ
ax = axes[0]
ax.plot(shifts, power_ks_loc, "b-o", markersize=5, label="KS test")
ax.plot(shifts, power_ad_loc, "r-s", markersize=5, label="Anderson-Darling")
ax.plot(shifts, power_chi2_loc, "g-^", markersize=5, label=r"$\chi^2$ test")
ax.axhline(alpha, color="gray", linestyle="--", linewidth=0.8)
ax.set_xlabel("Location shift", fontsize=12)
ax.set_ylabel("Power", fontsize=12)
ax.set_title("(a) Location shift: N(δ, 1) vs N(0, 1)", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
ax.set_ylim(0, 1.05)

# 裾の重さ
ax = axes[1]
ax.plot(dfs, power_ks_tail, "b-o", markersize=5, label="KS test")
ax.plot(dfs, power_ad_tail, "r-s", markersize=5, label="Anderson-Darling")
ax.plot(dfs, power_chi2_tail, "g-^", markersize=5, label=r"$\chi^2$ test")
ax.axhline(alpha, color="gray", linestyle="--", linewidth=0.8)
ax.set_xlabel("Degrees of freedom (t distribution)", fontsize=12)
ax.set_ylabel("Power", fontsize=12)
ax.set_title("(b) Heavy tails: t(df) vs N(0, 1)", fontsize=12)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
ax.set_ylim(0, 1.05)
ax.invert_xaxis()  # df小→裾重い を右に

plt.tight_layout()
plt.savefig("goodness_of_fit_power.png", dpi=150, bbox_inches="tight")
plt.show()

この検出力比較から、以下の重要な結果が読み取れます。

  1. 位置ずれ(左図): 3つの検定の中でAD検定が最も高い検出力を示し、次にKS検定、$\chi^2$ 検定の順です。位置ずれはCDFの形状を大きく変えるため、EDF検定(KS、AD)は$\chi^2$検定よりも効率的です。$\chi^2$検定はビン分割による情報損失のため検出力が低下しています

  2. 裾の重さ(右図): 裾の重い$t$分布と正規分布の違いを検出する場面で、AD検定がKS検定を大幅に上回っています。自由度が小さい(裾が重い)ほど差が顕著です。これはAD検定が裾に大きな重みを付けている効果の直接的な確認です。$\chi^2$検定は裾のビンで差を捉えることができるため、KS検定よりも良い場合があります

  3. 自由度が大きいt分布は正規分布に近いため、$\text{df} = 100$ では3検定とも棄却率が名目水準 $0.05$ に近くなっています。これは帰無仮説がほぼ正しい場合のサイズの確認にもなっています

EDF検定の可視化

3つの検定統計量の幾何学的な意味を可視化します。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

np.random.seed(123)
n = 20
data = np.sort(np.random.standard_t(df=4, size=n))

U = stats.norm.cdf(data)
F_n = np.arange(1, n + 1) / n
F_n_minus = np.arange(0, n) / n

fig, axes = plt.subplots(1, 3, figsize=(16, 5))

# --- KS検定: 最大乖離 ---
ax = axes[0]
# EDF
for i in range(n):
    x_l = data[i - 1] if i > 0 else data[0] - 2
    ax.plot([x_l, data[i]], [F_n_minus[i], F_n_minus[i]], "b-", linewidth=1.5)
    ax.plot([data[i], data[i]], [F_n_minus[i], F_n[i]], "b-", linewidth=1.5)
ax.plot([data[-1], data[-1] + 2], [1, 1], "b-", linewidth=1.5, label="EDF")

x_theo = np.linspace(data[0] - 2, data[-1] + 2, 300)
ax.plot(x_theo, stats.norm.cdf(x_theo), "r-", linewidth=2, label="N(0,1) CDF")

# 最大乖離
diff_plus = F_n - U
diff_minus = U - F_n_minus
idx_max = np.argmax(np.maximum(diff_plus, diff_minus))
D = max(diff_plus[idx_max], diff_minus[idx_max])
x_max = data[idx_max]
ax.fill_between([x_max - 0.1, x_max + 0.1],
                [min(F_n[idx_max], U[idx_max])],
                [max(F_n[idx_max], U[idx_max])],
                color="green", alpha=0.4)
ax.annotate(f"D = {D:.3f}", xy=(x_max, (F_n[idx_max] + U[idx_max]) / 2),
            fontsize=11, color="green", fontweight="bold",
            xytext=(x_max + 0.8, (F_n[idx_max] + U[idx_max]) / 2 + 0.1),
            arrowprops=dict(arrowstyle="->", color="green"))

ax.set_title("KS test: max deviation", fontsize=12)
ax.set_xlabel("x", fontsize=11)
ax.set_ylabel("CDF", fontsize=11)
ax.legend(fontsize=9, loc="upper left")
ax.grid(True, alpha=0.3)

# --- AD検定: 重み付き二乗乖離 ---
ax = axes[1]
for i in range(n):
    x_l = data[i - 1] if i > 0 else data[0] - 2
    ax.plot([x_l, data[i]], [F_n_minus[i], F_n_minus[i]], "b-", linewidth=1.5)
    ax.plot([data[i], data[i]], [F_n_minus[i], F_n[i]], "b-", linewidth=1.5)
ax.plot([data[-1], data[-1] + 2], [1, 1], "b-", linewidth=1.5, label="EDF")
ax.plot(x_theo, stats.norm.cdf(x_theo), "r-", linewidth=2, label="N(0,1) CDF")

# 全点での乖離を表示(重み付き)
for i in range(n):
    weight = 1 / max(U[i] * (1 - U[i]), 0.01)
    alpha_val = min(weight / 50, 0.8)
    ax.plot([data[i], data[i]], [U[i], F_n[i]], color="purple",
            alpha=alpha_val, linewidth=2)

ax.set_title("AD test: weighted squared deviation", fontsize=12)
ax.set_xlabel("x", fontsize=11)
ax.set_ylabel("CDF", fontsize=11)
ax.legend(fontsize=9, loc="upper left")
ax.grid(True, alpha=0.3)

# --- χ² 検定: ビン別度数 ---
ax = axes[2]
k = 6
edges = stats.norm.ppf(np.linspace(0, 1, k + 1)[1:-1])
edges = np.concatenate([[-4], edges, [4]])
O, _ = np.histogram(data, bins=edges)
E = np.full(k, n / k)
x_positions = np.arange(k)
width = 0.35
ax.bar(x_positions - width/2, O, width, color="steelblue", alpha=0.7,
       edgecolor="white", label="Observed")
ax.bar(x_positions + width/2, E, width, color="red", alpha=0.4,
       edgecolor="white", label="Expected")

for i in range(k):
    chi2_contrib = (O[i] - E[i])**2 / E[i]
    ax.text(i, max(O[i], E[i]) + 0.3, f"{chi2_contrib:.2f}",
            ha="center", fontsize=9, color="purple")

bin_labels = [f"({edges[i]:.1f},{edges[i+1]:.1f}]" for i in range(k)]
ax.set_xticks(x_positions)
ax.set_xticklabels(bin_labels, fontsize=7, rotation=30)
ax.set_title(r"$\chi^2$ test: observed vs expected counts", fontsize=12)
ax.set_ylabel("Count", fontsize=11)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3, axis="y")

plt.tight_layout()
plt.savefig("goodness_of_fit_geometry.png", dpi=150, bbox_inches="tight")
plt.show()

この3つの検定の幾何学的な比較から、以下の違いが視覚的に確認できます。

  1. KS検定(左図): EDFとCDFの間の最大の垂直距離(緑色の領域)だけを測定します。1つの点での乖離情報しか使わないため、分布全体の適合度を評価する上では情報量が限定的です

  2. AD検定(中央図): 全データ点での乖離(紫色の線分)を加重して合計します。裾の近くの線分がより濃い色(重みが大きい)で表示されています。分布の裾での乖離を重視するため、裾の重い分布の検出に優れています

  3. $\chi^2$ 検定(右図): データをビンに分割し、各ビンの観測度数と期待度数の差を見ます。各ビンの上に表示されている数値は $\chi^2$ 統計量への各ビンの寄与です。連続的な情報をカテゴリカルに変換するため情報損失が生じますが、離散データにも適用できる汎用性があります

3つの検定の使い分け

実用的なガイドライン

状況 推奨する検定 理由
連続データ、正規性の検定 Anderson-Darling 裾の感度が高く、正規性検定で最高の検出力
連続データ、一般的な適合度 KS検定 分布自由性、実装の簡便さ
離散データ $\chi^2$ 検定 KS/AD検定は連続分布専用
多変量データ $\chi^2$ 検定 多次元のビン分割が可能
パラメータを推定する場合 $\chi^2$ 検定 or リリフォース 自由度の補正が明快
小標本 KS検定(正確検定) 漸近近似に頼らない

複数の検定を併用する

実際の分析では、1つの検定だけでなく複数の検定を併用することが推奨されます。3つの検定が異なる側面を評価するため、すべてが帰無仮説を棄却しないことで、分布の仮定への信頼度が高まります。

ただし、複数の検定を行う場合は多重検定の問題に注意が必要です。3つの検定のうち1つでも有意になったら帰無仮説を棄却する、という基準を使うと第1種の過誤率が膨らみます。

まとめ

本記事では、3大適合度検定の理論と特徴を体系的に比較しました。

  • $\chi^2$ 適合度検定はビン分割に基づく最も古典的な手法で、離散データにも適用できますが、ビンの選び方に結果が依存し、連続データに対する検出力は他の2手法に劣ります
  • KS検定はEDFとCDFの最大乖離を見る分布自由検定で、ビン分割が不要ですが、裾の乖離への感度が低いという弱点があります
  • Anderson-Darling検定は裾に重みを付けた二乗乖離の積分で、正規性の検定など裾の振る舞いが重要な場面で最高の検出力を発揮します
  • シミュレーションにより、位置ずれの検出ではAD > KS > $\chi^2$ の順で検出力が高く、裾の重さの検出ではAD検定がKS検定を大幅に上回ることを確認しました

次のステップとして、以下の記事も参考にしてください。