統計的仮説検定を正しく使うには、有意水準(significance level) と p値(p-value) の2つの概念を正確に理解する必要があります。しかし、これらは最も誤解されやすい統計概念でもあり、2016年にはアメリカ統計学会(ASA)がp値の誤用に関する声明を発表するほどの問題になりました。
本記事では、有意水準とp値の定義を数学的に厳密に述べ、よくある誤解を正したうえで、Pythonによる実演を通じて直感的な理解を深めます。
本記事の内容
- 有意水準 $\alpha$ の定義と意味
- p値の正確な数学的定義
- p値のよくある誤解
- 検定の完全な手順
- Pythonでのp値計算と可視化
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
有意水準とは
定義
有意水準(significance level) $\alpha$ とは、帰無仮説 $H_0$ が正しいときに、$H_0$ を誤って棄却する確率の上限です。
$$ \alpha = P(\text{$H_0$ を棄却} \mid H_0 \text{ が真}) $$
これは第1種の過誤の確率そのものです。研究者が 検定を行う前に 設定する閾値であり、「どの程度の偽陽性リスクを許容するか」を表しています。
なぜ事前に設定するのか
有意水準を事前に設定する理由は、データを見てから基準を変えてしまう恣意的な判断を防ぐためです。たとえばp値が 0.06 だったときに「$\alpha = 0.10$ にしよう」と後から変更するのは不適切です。
一般的な有意水準
| 有意水準 | 使われる場面 |
|---|---|
| $\alpha = 0.05$ | 最も標準的。多くの分野で慣例 |
| $\alpha = 0.01$ | より厳しい基準。物理学の一部 |
| $\alpha = 0.001$ | 非常に厳しい基準 |
| $\alpha = 5 \times 10^{-7}$ | 素粒子物理学の「5シグマ」基準 |
$\alpha = 0.05$ が広く使われていますが、これは絶対的な基準ではなく、分野や問題の性質に応じて適切な値を選ぶべきです。
p値とは
数学的定義
p値とは、帰無仮説 $H_0$ が正しいという前提のもとで、観測されたデータと同等以上に極端な検定統計量が得られる確率です。
検定統計量の観測値を $T_{\text{obs}}$ とすると、
両側検定の場合:
$$ p = P(|T| \geq |T_{\text{obs}}| \mid H_0) $$
右片側検定の場合:
$$ p = P(T \geq T_{\text{obs}} \mid H_0) $$
左片側検定の場合:
$$ p = P(T \leq T_{\text{obs}} \mid H_0) $$
正規分布に基づくp値の計算
z検定を例に、p値を具体的に計算します。検定統計量 $Z = \frac{\bar{X} – \mu_0}{\sigma / \sqrt{n}}$ とし、$H_0$ のもとで $Z \sim N(0, 1)$ です。
観測された検定統計量の値を $z_{\text{obs}}$ とすると、両側検定のp値は次のようになります。
$$ \begin{align} p &= P(|Z| \geq |z_{\text{obs}}| \mid H_0) \\ &= P(Z \geq |z_{\text{obs}}|) + P(Z \leq -|z_{\text{obs}}|) \\ &= 2P(Z \geq |z_{\text{obs}}|) \quad (\because \text{標準正規分布の対称性}) \\ &= 2(1 – \Phi(|z_{\text{obs}}|)) \end{align} $$
ここで $\Phi(\cdot)$ は標準正規分布の累積分布関数です。
p値の直感的な解釈
p値は「帰無仮説が正しいと仮定したとき、今回のデータがどれだけ珍しいか」を表す指標です。
- p値が小さい → データが帰無仮説のもとで珍しい → $H_0$ に反する証拠が強い
- p値が大きい → データが帰無仮説のもとで珍しくない → $H_0$ に反する証拠が弱い
判定基準
$$ \begin{cases} p \leq \alpha & \Rightarrow H_0 \text{ を棄却する} \\ p > \alpha & \Rightarrow H_0 \text{ を棄却しない} \end{cases} $$
p値のよくある誤解
誤解1: 「p値は $H_0$ が正しい確率」
誤り: $p = 0.03$ のとき「帰無仮説が正しい確率は3%」
正しい理解: p値は「$H_0$ が正しいと仮定したとき、このデータ以上に極端な結果が得られる確率」です。$H_0$ の真偽の確率ではありません。
数式で書くと、p値は $P(\text{データ} \mid H_0)$ に関連する量であり、$P(H_0 \mid \text{データ})$ ではありません。後者はベイズの定理を通じてしか求められません。
誤解2: 「p値が小さいほど効果が大きい」
誤り: $p = 0.001$ なら大きな効果がある
正しい理解: p値は効果の大きさ(効果量)を直接反映しません。標本サイズが非常に大きければ、ごく小さな効果でもp値は極めて小さくなります。
z検定の検定統計量 $Z = \frac{\bar{X} – \mu_0}{\sigma / \sqrt{n}}$ を見ると、$n$ が大きくなれば $Z$ が大きくなり、p値は小さくなります。効果の実質的な大きさは 効果量(effect size) で評価すべきです。
誤解3: 「p > 0.05 なら効果がない」
誤り: $p = 0.08$ だから効果がない
正しい理解: 帰無仮説を棄却できないことは、帰無仮説が正しいことの証明ではありません(「証拠がない」と「ないことの証拠」は異なります)。検出力が不足している可能性もあります。
誤解4: 「$1 – p$ は $H_1$ が正しい確率」
誤り: $p = 0.03$ だから対立仮説が正しい確率は97%
正しい理解: $1 – p$ に確率的な意味はありません。p値はあくまで $H_0$ のもとでの確率計算です。
検定の完全な手順
以上を踏まえて、仮説検定の正しい手順を整理します。
ステップ1: 仮説の設定
$$ H_0: \mu = \mu_0, \quad H_1: \mu \neq \mu_0 $$
ステップ2: 有意水準 $\alpha$ の設定
$\alpha = 0.05$ など、事前に決める。
ステップ3: 検定統計量の計算
$$ Z = \frac{\bar{X} – \mu_0}{\sigma / \sqrt{n}} $$
ステップ4: p値の計算
$$ p = 2(1 – \Phi(|z_{\text{obs}}|)) $$
ステップ5: 判定
$p \leq \alpha$ なら $H_0$ を棄却。$p > \alpha$ なら $H_0$ を棄却しない。
ステップ6: 結論の記述
効果量や信頼区間とあわせて報告する。
Pythonでの実演
p値の計算と可視化
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 具体例: ある工場の製品の長さ
mu_0 = 50.0 # 帰無仮説の母平均 (mm)
sigma = 2.0 # 母標準偏差 (既知)
n = 25 # 標本サイズ
# 標本データ(母平均50.8から生成)
np.random.seed(42)
data = np.random.normal(50.8, sigma, n)
x_bar = np.mean(data)
# 検定統計量
se = sigma / np.sqrt(n)
z_obs = (x_bar - mu_0) / se
# p値(両側検定)
p_value = 2 * (1 - stats.norm.cdf(np.abs(z_obs)))
print(f"標本平均: {x_bar:.4f}")
print(f"検定統計量: Z = {z_obs:.4f}")
print(f"p値: {p_value:.4f}")
print(f"α = 0.05 での判定: {'棄却' if p_value < 0.05 else '棄却しない'}")
# 可視化
x = np.linspace(-4, 4, 1000)
pdf = stats.norm.pdf(x)
fig, ax = plt.subplots(figsize=(10, 6))
# 標準正規分布
ax.plot(x, pdf, 'k-', linewidth=2, label='$N(0, 1)$')
# p値の領域を塗りつぶし(両側)
x_right = x[x >= np.abs(z_obs)]
ax.fill_between(x_right, stats.norm.pdf(x_right),
color='red', alpha=0.4, label=f'p-value = {p_value:.4f}')
x_left = x[x <= -np.abs(z_obs)]
ax.fill_between(x_left, stats.norm.pdf(x_left),
color='red', alpha=0.4)
# 棄却域(α = 0.05)
z_crit = stats.norm.ppf(1 - 0.05 / 2)
ax.axvline(z_crit, color='blue', linestyle='--', linewidth=1.5,
label=f'$z_{{\\alpha/2}}$ = $\\pm${z_crit:.3f}')
ax.axvline(-z_crit, color='blue', linestyle='--', linewidth=1.5)
# 観測された検定統計量
ax.axvline(z_obs, color='darkred', linewidth=2.5,
label=f'$z_{{obs}}$ = {z_obs:.3f}')
ax.set_xlabel('$z$', fontsize=13)
ax.set_ylabel('Probability Density', fontsize=13)
ax.set_title('p-value Visualization (Two-sided Z-test)', fontsize=14)
ax.legend(fontsize=10)
ax.set_ylim(bottom=0)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
標本サイズとp値の関係
p値が標本サイズに強く依存することを示します。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 固定パラメータ
mu_0 = 50.0
mu_true = 50.5 # 真の母平均(わずかな差)
sigma = 2.0
# 標本サイズの範囲
sample_sizes = np.arange(10, 2001, 10)
np.random.seed(42)
p_values = []
for n in sample_sizes:
# 理論的なp値(期待値ベースで計算)
se = sigma / np.sqrt(n)
z = (mu_true - mu_0) / se
p = 2 * (1 - stats.norm.cdf(np.abs(z)))
p_values.append(p)
p_values = np.array(p_values)
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(sample_sizes, p_values, 'b-', linewidth=2)
ax.axhline(y=0.05, color='red', linestyle='--', linewidth=1.5,
label='$\\alpha$ = 0.05')
ax.axhline(y=0.01, color='orange', linestyle='--', linewidth=1.5,
label='$\\alpha$ = 0.01')
# p < 0.05 となるnを探す
n_sig = sample_sizes[np.argmax(p_values < 0.05)]
ax.axvline(x=n_sig, color='gray', linestyle=':', alpha=0.7,
label=f'p < 0.05 at n = {n_sig}')
ax.set_xlabel('Sample Size $n$', fontsize=13)
ax.set_ylabel('p-value', fontsize=13)
ax.set_title(f'p-value vs Sample Size ($\\mu_0$={mu_0}, $\\mu_{{true}}$={mu_true}, $\\sigma$={sigma})',
fontsize=13)
ax.set_yscale('log')
ax.legend(fontsize=11)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(f"真の効果量: d = {(mu_true - mu_0) / sigma:.3f}")
print(f"p < 0.05 となる最小の標本サイズ: n = {n_sig}")
このグラフから、効果量がわずか $d = 0.25$ でも標本サイズを増やせばp値はいくらでも小さくなることがわかります。p値の大きさと効果の実質的な意味は別のものです。
p値のシミュレーション: 帰無仮説が真のときのp値の分布
帰無仮説が正しいとき、p値は一様分布 $U(0, 1)$ に従います。これをシミュレーションで確認します。
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
np.random.seed(42)
mu_0 = 0
sigma = 1
n = 30
n_sim = 10000
# H0が真のもとでp値を繰り返し計算
p_values_h0 = []
for _ in range(n_sim):
sample = np.random.normal(mu_0, sigma, n)
z = (np.mean(sample) - mu_0) / (sigma / np.sqrt(n))
p = 2 * (1 - stats.norm.cdf(np.abs(z)))
p_values_h0.append(p)
p_values_h0 = np.array(p_values_h0)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 左: p値のヒストグラム
axes[0].hist(p_values_h0, bins=50, density=True, alpha=0.7, color='steelblue',
edgecolor='white')
axes[0].axhline(y=1.0, color='red', linestyle='--', linewidth=2,
label='Uniform(0, 1)')
axes[0].set_xlabel('p-value', fontsize=12)
axes[0].set_ylabel('Density', fontsize=12)
axes[0].set_title('Distribution of p-values under $H_0$', fontsize=13)
axes[0].legend(fontsize=11)
# 右: 偽陽性率
alpha_levels = np.linspace(0, 1, 200)
false_positive_rates = [np.mean(p_values_h0 <= a) for a in alpha_levels]
axes[1].plot(alpha_levels, false_positive_rates, 'b-', linewidth=2,
label='Observed')
axes[1].plot([0, 1], [0, 1], 'r--', linewidth=1.5, label='Theoretical')
axes[1].set_xlabel('$\\alpha$', fontsize=12)
axes[1].set_ylabel('$P(p \\leq \\alpha)$', fontsize=12)
axes[1].set_title('False Positive Rate vs $\\alpha$', fontsize=13)
axes[1].legend(fontsize=11)
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print(f"α = 0.05 での偽陽性率: {np.mean(p_values_h0 <= 0.05):.4f}")
print(f"α = 0.01 での偽陽性率: {np.mean(p_values_h0 <= 0.01):.4f}")
$H_0$ が真のときp値は一様分布に従うため、$P(p \leq \alpha) = \alpha$ が成り立ちます。これが「有意水準 $\alpha$ で第1種の過誤の確率が $\alpha$ になる」ことの直接的な帰結です。
まとめ
本記事では、有意水準とp値の正しい理解について解説しました。
- 有意水準 $\alpha$: 第1種の過誤の確率の上限。検定前に事前に設定する
- p値: $H_0$ のもとで、観測データ以上に極端な結果が得られる確率
- p値の誤解: 「$H_0$ が正しい確率」ではない。効果の大きさも反映しない
- 判定基準: $p \leq \alpha$ なら $H_0$ を棄却、$p > \alpha$ なら棄却しない
- 標本サイズ依存性: 大標本ではわずかな差でもp値が小さくなるため、効果量とあわせて解釈すべき
次のステップとして、以下の記事も参考にしてください。