統計的検定とは?帰無仮説・対立仮説・p値をわかりやすく解説

はじめに

「新しい薬は本当に効果があるのか?」「このコインは本当に公平なのか?」「A/Bテストでコンバージョン率に差があるのか?」

こうした疑問に対して、データに基づいて客観的に判断する方法が 統計的仮説検定(statistical hypothesis testing) です。統計的検定は、科学研究、医学、品質管理、マーケティングなど、あらゆる分野でデータに基づく意思決定の基盤となっています。

本記事では、統計的検定の基本概念を、具体例と Python コードを交えてわかりやすく解説します。

前提知識

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

統計的検定とは何か

統計的検定とは、観測データから仮説の妥当性を確率的に判断する方法 です。

私たちが何かを主張したいとき(たとえば「この薬には効果がある」)、直接それを証明するのではなく、「効果がない」という仮説を立て、それがデータと矛盾するかどうかを調べる というアプローチを取ります。

データと矛盾するならば「効果がない」という仮説を棄却し、結果として「効果がある」と結論づけます。これは背理法に似た論理構造です。

帰無仮説と対立仮説

統計的検定では、2つの仮説を設定します。

帰無仮説 $H_0$(null hypothesis)

棄却したい方の仮説 です。「差がない」「効果がない」「変化がない」など、現状維持や無効果を主張する仮説を設定します。

$$ H_0: \text{「差がない」「効果がない」「パラメータは基準値に等しい」} $$

たとえば、コインの公平性を検証する場合は

$$ H_0: p = 0.5 $$

と設定します。ここで $p$ はコインの表が出る確率です。

対立仮説 $H_1$(alternative hypothesis)

主張したい方の仮説 です。帰無仮説が棄却されたときに採択される仮説です。

$$ H_1: \text{「差がある」「効果がある」「パラメータは基準値と異なる」} $$

コインの例では

$$ H_1: p \neq 0.5 $$

です。この場合、$p > 0.5$ と $p < 0.5$ の両方を考えるので 両側検定 と呼びます。$H_1: p > 0.5$ のように片方だけを考える場合は 片側検定 と呼びます。

検定の手順

統計的検定は、次の4つのステップで行います。

ステップ1: 仮説の設定

帰無仮説 $H_0$ と対立仮説 $H_1$ を明確に設定します。

ステップ2: 検定統計量の計算

観測データから 検定統計量(test statistic) を計算します。検定統計量とは、帰無仮説が正しいと仮定したときに、データがどの程度「極端」であるかを定量化した値です。

ステップ3: 棄却域の決定またはp値の計算

事前に定めた 有意水準 に基づいて棄却域を設定するか、検定統計量から p値 を計算します。

ステップ4: 判定

検定統計量が棄却域に入れば(またはp値が有意水準以下であれば)$H_0$ を棄却し、$H_1$ を採択します。そうでなければ $H_0$ を棄却しません。

重要な注意点として、「$H_0$ を棄却しない」ことは「$H_0$ が正しい」ことの証明ではありません。あくまで「$H_0$ を棄却するだけの十分な証拠がデータから得られなかった」という意味です。

有意水準 $\alpha$

有意水準(significance level) $\alpha$ は、帰無仮説が実際には正しいにもかかわらず、誤って棄却してしまう確率の上限を表します。

$$ \alpha = P(\text{$H_0$ を棄却} \mid \text{$H_0$ が真}) $$

慣例的に $\alpha = 0.05$(5%)が最もよく使われます。これは「帰無仮説が正しい場合でも、100回検定を行えば約5回は誤って棄却してしまう」ことを許容する、という意味です。

分野によっては $\alpha = 0.01$(1%)や $\alpha = 0.001$(0.1%)を用いることもあります。素粒子物理学では「$5\sigma$」($\alpha \approx 2.87 \times 10^{-7}$)という極めて厳しい基準が使われます。

p値の定義と解釈

p値の定義

p値(p-value) とは、帰無仮説 $H_0$ が正しいと仮定したとき、観測されたデータ以上に極端な結果が得られる確率 です。

$$ p\text{値} = P(\text{検定統計量が観測値以上に極端} \mid H_0 \text{が真}) $$

p値の解釈

  • $p$ 値が 小さい → 帰無仮説のもとでは観測データが非常にまれな事象 → $H_0$ を棄却する根拠が強い
  • $p$ 値が 大きい → 帰無仮説のもとでも観測データはそれほど珍しくない → $H_0$ を棄却する根拠が弱い

判定規則は単純です。

$$ p \text{値} \leq \alpha \implies H_0 \text{を棄却(統計的に有意)} $$

$$ p \text{値} > \alpha \implies H_0 \text{を棄却しない(有意でない)} $$

p値に関する注意

p値はしばしば誤解されます。以下の点に注意してください。

  • p値は $H_0$ が正しい確率ではありません。$H_0$ が正しいと仮定した条件つき確率です。
  • p値が小さいことは、効果が大きいことを意味しません。サンプルサイズが十分に大きければ、実質的に無意味な小さな差でも統計的に有意になり得ます。
  • p値は 効果の大きさ(effect size) とは別の概念です。実務的な判断には効果量や信頼区間も合わせて検討すべきです。

第1種の過誤と第2種の過誤

統計的検定では、2種類の誤りが生じ得ます。

$H_0$ が真 $H_0$ が偽
$H_0$ を棄却 第1種の過誤(偽陽性) 正しい判定
$H_0$ を棄却しない 正しい判定 第2種の過誤(偽陰性)

第1種の過誤(Type I error)

帰無仮説が実際には正しいのに、誤って棄却してしまう誤りです。その確率は有意水準 $\alpha$ で制御されます。

$$ P(\text{第1種の過誤}) = P(\text{$H_0$ を棄却} \mid \text{$H_0$ が真}) = \alpha $$

たとえば、実際には効果のない薬を「効果あり」と判定してしまうケースです。

第2種の過誤(Type II error)

帰無仮説が実際には誤っているのに、棄却できない誤りです。その確率を $\beta$ で表します。

$$ P(\text{第2種の過誤}) = P(\text{$H_0$ を棄却しない} \mid \text{$H_0$ が偽}) = \beta $$

たとえば、実際には効果のある薬を「効果なし」と判定してしまうケースです。

$\alpha$ と $\beta$ のトレードオフ

サンプルサイズが固定されている場合、$\alpha$ を小さくすると $\beta$ は大きくなる傾向があります。つまり、偽陽性を減らそうとすると偽陰性が増えます。両方を同時に小さくするには、サンプルサイズを大きくする ことが有効です。

検出力(1 – $\beta$)

検出力(power) は、帰無仮説が実際に誤っているときに、正しくそれを棄却できる確率です。

$$ \text{検出力} = 1 – \beta = P(\text{$H_0$ を棄却} \mid \text{$H_0$ が偽}) $$

検出力が高いほど、実際に存在する効果を見逃しにくい検定だといえます。一般的に、検出力が 0.8(80%)以上であることが望ましいとされています。

検出力に影響を与える要因は以下のとおりです。

  • 効果量: 真の効果が大きいほど検出しやすい
  • サンプルサイズ: 大きいほど検出力が上がる
  • 有意水準 $\alpha$: 大きいほど検出力が上がる(ただし偽陽性も増える)
  • データのばらつき: ばらつきが小さいほど検出力が上がる

具体例: コインの公平性の検定(二項検定)

ここでは、具体的な数値を使って検定の流れを一通り体験してみましょう。

問題設定

あるコインを100回投げたところ、65回表が出ました。このコインは公平(表と裏が同じ確率)と言えるでしょうか?有意水準 $\alpha = 0.05$ で両側検定を行います。

ステップ1: 仮説の設定

$$ H_0: p = 0.5 \quad \text{(コインは公平)} $$

$$ H_1: p \neq 0.5 \quad \text{(コインは公平でない)} $$

ステップ2: 検定統計量の計算

表が出る回数 $X$ は、帰無仮説のもとで二項分布 $B(n, p_0)$ に従います。

$$ X \sim B(100,\, 0.5) \quad \text{($H_0$ のもとで)} $$

二項分布の正規近似を用いると、検定統計量 $Z$ は次のように計算されます。

$$ Z = \frac{X – np_0}{\sqrt{np_0(1 – p_0)}} $$

具体的な値を代入します。

$$ Z = \frac{65 – 100 \times 0.5}{\sqrt{100 \times 0.5 \times 0.5}} $$

分子を計算します。

$$ 65 – 50 = 15 $$

分母を計算します。

$$ \sqrt{100 \times 0.25} = \sqrt{25} = 5 $$

したがって

$$ Z = \frac{15}{5} = 3.0 $$

ステップ3: p値の計算

両側検定なので、$|Z| \geq 3.0$ となる確率を求めます。標準正規分布の性質から

$$ p\text{値} = 2 \times P(Z \geq 3.0) = 2 \times (1 – \Phi(3.0)) $$

ここで $\Phi$ は標準正規分布の累積分布関数です。

$$ \Phi(3.0) \approx 0.99865 $$

$$ p\text{値} = 2 \times (1 – 0.99865) = 2 \times 0.00135 = 0.0027 $$

ステップ4: 判定

$$ p\text{値} = 0.0027 < \alpha = 0.05 $$

p値が有意水準を下回るため、帰無仮説 $H_0$ を棄却します。すなわち、このコインは公平でない(表が出る確率が0.5ではない)と結論づけられます。

Python での実装

二項検定と正規近似による検定

import numpy as np
from scipy import stats

# --- 問題設定 ---
n = 100       # 試行回数
x = 65        # 表が出た回数
p0 = 0.5      # 帰無仮説のもとでの表の確率
alpha = 0.05  # 有意水準

# --- 方法1: 正規近似による検定 ---
z_stat = (x - n * p0) / np.sqrt(n * p0 * (1 - p0))
p_value_normal = 2 * (1 - stats.norm.cdf(abs(z_stat)))

print("=" * 50)
print("方法1: 正規近似による Z 検定")
print("=" * 50)
print(f"観測値: {x} / {n} 回 (観測比率 = {x/n:.2f})")
print(f"検定統計量 Z = {z_stat:.4f}")
print(f"p値 = {p_value_normal:.6f}")
print(f"有意水準 α = {alpha}")
if p_value_normal < alpha:
    print(f"判定: p値 ({p_value_normal:.6f}) < α ({alpha}) → H₀を棄却")
else:
    print(f"判定: p値 ({p_value_normal:.6f}) ≥ α ({alpha}) → H₀を棄却しない")

# --- 方法2: scipy.stats.binom_test の後継 binomtest ---
result = stats.binomtest(x, n, p0, alternative="two-sided")

print()
print("=" * 50)
print("方法2: 正確二項検定 (scipy.stats.binomtest)")
print("=" * 50)
print(f"観測値: {x} / {n} 回 (観測比率 = {x/n:.2f})")
print(f"p値 = {result.pvalue:.6f}")
print(f"有意水準 α = {alpha}")
if result.pvalue < alpha:
    print(f"判定: p値 ({result.pvalue:.6f}) < α ({alpha}) → H₀を棄却")
else:
    print(f"判定: p値 ({result.pvalue:.6f}) ≥ α ({alpha}) → H₀を棄却しない")

# 信頼区間も確認
ci = result.proportion_ci(confidence_level=0.95)
print(f"95%信頼区間: [{ci.low:.4f}, {ci.high:.4f}]")

棄却域の可視化

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

# --- パラメータ ---
alpha = 0.05
z_critical = stats.norm.ppf(1 - alpha / 2)  # 両側検定の臨界値
z_observed = 3.0  # 観測された検定統計量

# --- 標準正規分布の描画 ---
x = np.linspace(-4, 4, 1000)
y = stats.norm.pdf(x)

fig, ax = plt.subplots(figsize=(10, 5))

# 分布全体
ax.plot(x, y, "k-", linewidth=2, label="標準正規分布 $N(0, 1)$")

# 棄却域(左側)を塗りつぶす
x_left = x[x <= -z_critical]
ax.fill_between(x_left, stats.norm.pdf(x_left), color="red", alpha=0.4,
                label=f"棄却域 ($|Z| > {z_critical:.3f}$)")

# 棄却域(右側)を塗りつぶす
x_right = x[x >= z_critical]
ax.fill_between(x_right, stats.norm.pdf(x_right), color="red", alpha=0.4)

# 採択域を塗りつぶす
x_accept = x[(x >= -z_critical) & (x <= z_critical)]
ax.fill_between(x_accept, stats.norm.pdf(x_accept), color="blue", alpha=0.1,
                label="採択域")

# 臨界値の線
ax.axvline(-z_critical, color="red", linestyle="--", linewidth=1.5,
           label=f"臨界値 $\\pm {z_critical:.3f}$")
ax.axvline(z_critical, color="red", linestyle="--", linewidth=1.5)

# 観測された検定統計量
ax.axvline(z_observed, color="green", linestyle="-", linewidth=2.5,
           label=f"観測値 $Z = {z_observed:.1f}$")

# 装飾
ax.set_xlabel("$Z$", fontsize=14)
ax.set_ylabel("確率密度", fontsize=14)
ax.set_title("コインの公平性の検定(両側検定, $\\alpha = 0.05$)", fontsize=15)
ax.legend(fontsize=11, loc="upper left")
ax.grid(True, alpha=0.3)

# 注釈
ax.annotate(
    f"$Z = {z_observed:.1f}$\n棄却域に入る\n→ $H_0$ を棄却",
    xy=(z_observed, 0.01),
    xytext=(z_observed + 0.3, 0.15),
    fontsize=11,
    arrowprops=dict(arrowstyle="->", color="green", linewidth=1.5),
    bbox=dict(boxstyle="round,pad=0.3", facecolor="lightyellow", edgecolor="gray"),
)

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

p値の可視化

p値が分布のどの領域に対応するかを視覚的に示します。

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

# --- パラメータ ---
z_observed = 3.0
p_value = 2 * (1 - stats.norm.cdf(z_observed))

# --- 描画 ---
x = np.linspace(-4, 4, 1000)
y = stats.norm.pdf(x)

fig, ax = plt.subplots(figsize=(10, 5))

# 分布全体
ax.plot(x, y, "k-", linewidth=2, label="標準正規分布 $N(0, 1)$")

# p値に対応する領域(左側)
x_p_left = x[x <= -z_observed]
ax.fill_between(x_p_left, stats.norm.pdf(x_p_left), color="orange", alpha=0.6,
                label=f"p値の領域 (p = {p_value:.4f})")

# p値に対応する領域(右側)
x_p_right = x[x >= z_observed]
ax.fill_between(x_p_right, stats.norm.pdf(x_p_right), color="orange", alpha=0.6)

# 観測値の線
ax.axvline(z_observed, color="green", linestyle="-", linewidth=2.5,
           label=f"観測値 $Z = {z_observed:.1f}$")
ax.axvline(-z_observed, color="green", linestyle="-", linewidth=2.5)

# 装飾
ax.set_xlabel("$Z$", fontsize=14)
ax.set_ylabel("確率密度", fontsize=14)
ax.set_title("p値の図示: $|Z| \\geq 3.0$ となる確率", fontsize=15)
ax.legend(fontsize=11, loc="upper left")
ax.grid(True, alpha=0.3)

# 注釈
ax.annotate(
    f"p値 = {p_value:.4f}\nα = 0.05 より小さい\n→ 統計的に有意",
    xy=(z_observed, stats.norm.pdf(z_observed)),
    xytext=(1.5, 0.25),
    fontsize=11,
    arrowprops=dict(arrowstyle="->", color="orange", linewidth=1.5),
    bbox=dict(boxstyle="round,pad=0.3", facecolor="lightyellow", edgecolor="gray"),
)

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

上記の3つのコードを実行すると、以下の結果が得られます。

  1. 正規近似による Z 検定: $Z = 3.0$、$p = 0.0027$ で帰無仮説を棄却
  2. 正確二項検定: scipy の binomtest による厳密な計算でも同様に棄却
  3. 棄却域の図: 観測値 $Z = 3.0$ が棄却域(赤い領域)に入っていることを視覚的に確認
  4. p値の図: オレンジ色の領域がp値に対応し、非常に小さい面積であることを確認

まとめ

本記事では、統計的仮説検定の基本概念を体系的に解説しました。

  • 統計的検定 は、データから仮説の妥当性を確率的に判断する方法です。
  • 帰無仮説 $H_0$ は「差がない」「効果がない」という仮説、対立仮説 $H_1$ は主張したい仮説です。
  • 検定は「仮説設定 → 検定統計量の計算 → 棄却域またはp値 → 判定」の4ステップで行います。
  • 有意水準 $\alpha$ は第1種の過誤の確率の上限であり、通常 0.05 を用います。
  • p値 は帰無仮説のもとで観測データ以上に極端な結果が得られる確率であり、$\alpha$ と比較して判定します。
  • 第1種の過誤(偽陽性)と 第2種の過誤(偽陰性)の2種類の誤りがあり、トレードオフの関係にあります。
  • 検出力($1 – \beta$)は実際の効果を正しく検出できる確率であり、サンプルサイズを大きくすることで改善できます。
  • コインの公平性を例に、二項検定の全手順を数式と Python コードで実演しました。

次の記事では、連続データに対する検定手法として t検定(1標本、2標本、対応ありの3種類)と、カテゴリデータに対する $\chi^2$(カイ二乗)検定 を解説します。