「サイコロの出目は本当に均等か?」「アンケート結果は想定した割合と一致しているか?」「観測データはポアソン分布に従っているか?」――このように、データが理論的に予想される分布と合っているかを確かめたい場面は実務・研究を問わず頻繁に現れる。
こうした問題に答える手法が適合度検定(goodness of fit test)である。1900年にイギリスの統計学者カール・ピアソン(Karl Pearson, 1857–1936)が発表したこの検定は、観測度数と理論的に期待される度数のずれをカイ二乗分布を用いて評価する。母比率の検定や独立性の検定など、多くの検定手法の基礎となる重要な手法である。
適合度検定とは
カテゴリの個数を I とし、それぞれの生起確率を p_i(1 \leq i \leq I)とおく。総度数を n、カテゴリ i の観測度数を x_i、帰無仮説のもとでの p_i の推定量を \hat{p}_i とする。
ピアソンのカイ二乗統計量
ピアソンのカイ二乗適合度検定統計量は次のように定義される。
ここで n\hat{p}_i は期待度数(expected frequency)と呼ばれる。この統計量は、観測度数と期待度数のずれが大きいほど大きな値をとる。
各カテゴリについて「(観測度数 − 期待度数)²÷ 期待度数」を計算し、すべて足し合わせる。観測データが帰無仮説の分布に完全に一致すれば T = 0 となり、ずれが大きいほど T は大きくなる。
帰無仮説下の分布と自由度
帰無仮説のもとで n \to \infty のとき、T は漸近的に自由度 d のカイ二乗分布に従う。自由度は
で与えられる。ここで I - 1 は制約のないフルモデル(飽和モデル)で自由に動けるパラメータの個数であり、k は帰無仮説のもとでデータから推定するパラメータの個数である。
帰無仮説が生起確率のすべてを具体的に指定している場合(単純帰無仮説)は k = 0 であるから、自由度は d = I - 1 となる。一方、帰無仮説が「ポアソン分布に従う」のような形で分布の形だけを指定し、パラメータ \lambda をデータから推定する場合は k = 1 となり、自由度は d = I - 2 である。
有意水準 \alpha の検定は、T \geq \chi^2_{\alpha}(d) のとき帰無仮説を棄却する(右片側検定)。
カイ二乗近似が十分に正確であるためには、すべてのカテゴリで期待度数が5以上であることが目安とされる。期待度数が小さいカテゴリがある場合は、隣接するカテゴリと統合して期待度数を確保する。
計算例:サイコロの一様性検定
あるサイコロを120回振ったところ、各目の出現回数は以下の通りだった。このサイコロの出目は均等(各目の確率が \dfrac{1}{6})と言えるか、有意水準5%で検定せよ。
| 目 | 1 | 2 | 3 | 4 | 5 | 6 | 合計 |
|---|---|---|---|---|---|---|---|
| 観測度数 | 25 | 17 | 15 | 23 | 24 | 16 | 120 |
| 期待度数 | 20 | 20 | 20 | 20 | 20 | 20 | 120 |
解答
ステップ1:仮説の設定
すべての確率を具体的に指定しているので単純帰無仮説であり、推定するパラメータは k = 0 である。
ステップ2:カイ二乗統計量の計算
ステップ3:棄却域との比較
自由度 d = 6 - 1 = 5 のカイ二乗分布の上側5%点は \chi^2_{0.05}(5) = 11.07 である。
ステップ4:結論
T = 5.000 は棄却域に入らないので、帰無仮説を棄却しない。有意水準5%では「サイコロの出目は均等でない」とは言えない(P値 = 0.416)。
イエーツの補正
期待度数が十分大きくない場合には、イエーツの補正(Yates' correction)が用いられることがある。これはカイ二乗統計量の分子にある (x_i - n\hat{p}_i)^2 を
に置き換える補正法である。離散的な分布(観測度数は整数値)を連続的なカイ二乗分布で近似する際の誤差を軽減するもので、中心極限定理における連続修正に対応している。主にカテゴリ数が2の場合(2×2分割表)に用いられる。
自由度の求め方
自由度の計算は「フルモデルの自由パラメータ数 − 帰無仮説下の自由パラメータ数」として理解できる。
| 場面 | カテゴリ数 | 推定パラメータ数 k | 自由度 d |
|---|---|---|---|
| 一様性の検定(確率が全て指定) | I | 0 | I - 1 |
| ポアソン適合度(λを推定) | I | 1 | I - 2 |
| 正規分布適合度(μ, σ²を推定) | I | 2 | I - 3 |
| 独立性の検定(I×J分割表) | IJ | I+J-2 | (I-1)(J-1) |
計算例:曜日ごとの来客数
あるカフェで150日間の来客数を曜日別に集計したところ、以下の結果を得た。「来客数は曜日によらず均等である」と言えるか、有意水準5%で検定せよ。
| 曜日 | 月 | 火 | 水 | 木 | 金 | 土 | 日 | 合計 |
|---|---|---|---|---|---|---|---|---|
| 観測度数 | 15 | 12 | 18 | 14 | 22 | 35 | 34 | 150 |
| 期待度数 | 21.43 | 21.43 | 21.43 | 21.43 | 21.43 | 21.43 | 21.43 | 150 |
解答
帰無仮説 H_0: p_1 = \cdots = p_7 = \dfrac{1}{7}、自由度 d = 7 - 1 = 6。期待度数は各曜日 \dfrac{150}{7} = 21.43 である。
自由度6のカイ二乗分布の上側5%点は \chi^2_{0.05}(6) = 12.59 であり、T = 25.19 > 12.59 なので帰無仮説を棄却する。有意水準5%で「来客数は曜日によって異なる」と結論できる(P値 < 0.001)。土日の来客が特に多いことが統計量を大きくしている要因である。
他の検定との関係
母比率の検定は適合度検定の特殊ケース
母比率の検定は、カテゴリ数 I = 2(「成功」と「失敗」)の適合度検定と見なせる。帰無仮説 \theta = \theta_0 のもとで p_1 = \theta_0、p_2 = 1 - \theta_0 とすると、カイ二乗統計量は
となり、これは母比率の検定における検定統計量 Z^2 に等しい。すなわち、母比率の検定のZ統計量の2乗はカイ二乗統計量に一致する。
ポアソン分布の検定
ポアソン分布のパラメータに関する検定統計量 \dfrac{(\hat{\lambda} - \lambda_0)^2}{\lambda_0} も、カテゴリ数2(X = \lambda_0 か否か)の適合度検定の特別な場合と解釈できる。
練習問題
帰無仮説:p_1 = 0.25, \ p_2 = 0.50, \ p_3 = 0.25
期待度数:AA = 400 \times 0.25 = 100、Aa = 400 \times 0.50 = 200、aa = 400 \times 0.25 = 100
自由度 d = 3 - 1 = 2(すべての確率を指定しているので k = 0)
T = 4.50 < 5.991 = \chi^2_{0.05}(2) より、帰無仮説を棄却しない。
結論:有意水準5%では「理論比1:2:1に適合しない」とは言えない。
帰無仮説:p_A = 0.4, \ p_O = 0.3, \ p_B = 0.2, \ p_{AB} = 0.1
期待度数:A = 200 \times 0.4 = 80、O = 200 \times 0.3 = 60、B = 200 \times 0.2 = 40、AB = 200 \times 0.1 = 20
自由度 d = 4 - 1 = 3(すべての確率を指定しているので k = 0)
T = 2.292 < 7.815 = \chi^2_{0.05}(3) より、帰無仮説を棄却しない。
結論:有意水準5%では「理論比率4:3:2:1に適合しない」とは言えない。
まとめ
| 項目 | 内容 |
|---|---|
| 目的 | データが理論的な分布に適合しているか |
| 検定統計量 | T = \sum \dfrac{(\text{観測度数} - \text{期待度数})^2}{\text{期待度数}} |
| 帰無仮説下の分布 | カイ二乗分布 \chi^2(d)(近似) |
| 自由度 | d = I - 1 - k(I: カテゴリ数、k: 推定パラメータ数) |
| 棄却域 | T \geq \chi^2_{\alpha}(d)(右片側のみ) |
| 適用条件 | すべての期待度数が5以上 |
Python実装
SciPyの scipy.stats.chisquare で適合度検定を実行できる。期待度数が一様でない場合は f_exp 引数で指定する。
import numpy as np
from scipy import stats
# ========== 例題1: サイコロの一様性検定 ==========
print("【サイコロの一様性検定】")
observed = np.array([25, 17, 15, 23, 24, 16])
n = observed.sum()
expected = np.array([n / 6] * 6)
# scipy.stats.chisquare(一様分布がデフォルト)
chi2, p_value = stats.chisquare(observed)
print(f"観測度数: {observed}")
print(f"期待度数: {expected}")
print(f"カイ二乗統計量 T = {chi2:.4f}")
print(f"自由度 = {len(observed) - 1}")
print(f"P値 = {p_value:.4f}")
print(f"結論: 帰無仮説を棄却しない")
print()
print("=" * 50)
print()
# ========== 例題2: 曜日ごとの来客数 ==========
print("【曜日ごとの来客数の一様性検定】")
observed2 = np.array([15, 12, 18, 14, 22, 35, 34])
chi2_2, p_2 = stats.chisquare(observed2)
print(f"観測度数: {observed2}")
print(f"カイ二乗統計量 T = {chi2_2:.4f}")
print(f"自由度 = {len(observed2) - 1}")
print(f"P値 = {p_2:.6f}")
print(f"結論: 帰無仮説を棄却(有意差あり)")
print()
print("=" * 50)
print()
# ========== ポアソン適合度検定 ==========
print("【ポアソン適合度検定】")
obs_poi = np.array([10, 25, 30, 20, 10, 5])
vals = np.array([0, 1, 2, 3, 4, 5.5])
n_poi = obs_poi.sum()
lam_hat = np.sum(obs_poi * vals) / n_poi
print(f"推定 λ = {lam_hat:.4f}")
# 期待度数の計算
exp_poi = []
for k in range(5):
exp_poi.append(n_poi * stats.poisson.pmf(k, lam_hat))
exp_poi.append(n_poi * (1 - stats.poisson.cdf(4, lam_hat)))
exp_poi = np.array(exp_poi)
print(f"期待度数: {np.round(exp_poi, 2)}")
# 手動でカイ二乗統計量を計算(λを推定→自由度調整が必要)
chi2_poi = np.sum((obs_poi - exp_poi)**2 / exp_poi)
df_poi = len(obs_poi) - 1 - 1 # λを推定したので k=1
p_poi = 1 - stats.chi2.cdf(chi2_poi, df_poi)
print(f"カイ二乗統計量 T = {chi2_poi:.4f}")
print(f"自由度 = {df_poi}(カテゴリ{len(obs_poi)} - 1 - 1)")
print(f"P値 = {p_poi:.4f}")
print(f"結論: 帰無仮説を棄却しない")
scipy.stats.chisquare は自由度を自動的に「カテゴリ数 − 1」として計算する。パラメータをデータから推定した場合(ポアソン適合度など)は自由度の調整が必要なので、上のコードのようにP値を手動で計算する。