母平均の検定で「$z$ 検定」と「$t$ 検定」を使い分ける必要があるのはなぜでしょうか?母分散 $\sigma^2$ がわかっていれば $z$ 検定(正規分布に基づく)が使えますが、現実には $\sigma^2$ は未知であることがほとんどです。$\sigma^2$ を標本分散 $s^2$ で置き換えると、検定統計量の分布は正規分布からずれます。このずれを正確に記述するのがt分布(Student’s t-distribution)です。
t分布は1908年にギネスビール醸造所で品質管理に携わっていたウィリアム・シーリー・ゴセットが発見しました。ギネスの社員規定で実名での論文発表が禁じられていたため、「Student」というペンネームで発表したことから「Student の t 分布」と呼ばれます。
t分布は、以下のような場面で不可欠です。
- t検定: 母平均の検定(1標本、2標本、対応のある検定)
- 信頼区間: 母分散が未知の場合の母平均の信頼区間
- 回帰分析: 回帰係数の有意性検定
- ベイズ統計: 正規分布の周辺分布として現れる
本記事の内容
- t分布の導出(正規分布とカイ二乗分布から)
- 自由度のパラメータの意味
- 期待値・分散の計算
- 正規分布との比較(裾の重さ)
- t検定への応用
- Pythonでの実装と可視化
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
t分布の導出
問題の設定
$X_1, \ldots, X_n \sim N(\mu, \sigma^2)$(独立)のとき、$\bar{X} = \sum X_i / n$ として
$$ Z = \frac{\bar{X} – \mu}{\sigma / \sqrt{n}} \sim N(0, 1) $$
$\sigma$ が既知ならこの統計量で検定ができます。しかし $\sigma$ が未知のとき、標本標準偏差 $S = \sqrt{\sum(X_i – \bar{X})^2/(n-1)}$ で置き換えた
$$ T = \frac{\bar{X} – \mu}{S / \sqrt{n}} $$
はもはや $N(0, 1)$ に従いません。$T$ の正確な分布がt分布です。
正式な定義と導出
$Z \sim N(0, 1)$ と $V \sim \chi^2(\nu)$ が独立のとき
$$ \begin{equation} T = \frac{Z}{\sqrt{V / \nu}} \sim t(\nu) \end{equation} $$
$\bar{X}$ の統計量との対応は、$Z = (\bar{X} – \mu)/(\sigma/\sqrt{n})$ と $V = (n-1)S^2/\sigma^2 \sim \chi^2(n-1)$ が独立であることから
$$ T = \frac{Z}{\sqrt{V/(n-1)}} = \frac{(\bar{X}-\mu)/(\sigma/\sqrt{n})}{\sqrt{(n-1)S^2/(\sigma^2(n-1))}} = \frac{\bar{X}-\mu}{S/\sqrt{n}} $$
密度関数
自由度 $\nu$ のt分布の密度関数は
$$ \begin{equation} f(t) = \frac{\Gamma\left(\frac{\nu+1}{2}\right)}{\sqrt{\nu\pi}\,\Gamma\left(\frac{\nu}{2}\right)} \left(1 + \frac{t^2}{\nu}\right)^{-(\nu+1)/2} \end{equation} $$
性質
期待値と分散
$$ E[T] = 0 \quad (\nu > 1) $$
$$ \text{Var}(T) = \frac{\nu}{\nu – 2} \quad (\nu > 2) $$
$\nu = 1$ では期待値が存在せず(コーシー分布)、$\nu = 2$ では分散が無限大です。
正規分布との関係
$\nu \to \infty$ のとき $t(\nu) \to N(0, 1)$。実用的には $\nu \geq 30$ で正規近似が良好です。
$\nu$ が有限のとき、t分布は正規分布より裾が重い(heavy-tailed)。これは $\sigma$ を $S$ で推定することによる追加の不確実性を反映しています。
Pythonでの実装と可視化
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# (a) 異なる自由度でのPDF
ax = axes[0, 0]
x = np.linspace(-5, 5, 500)
dfs = [1, 2, 5, 10, 30]
for df in dfs:
pdf = stats.t.pdf(x, df)
ax.plot(x, pdf, linewidth=2, label=f'$\\nu$ = {df}')
ax.plot(x, stats.norm.pdf(x), 'k--', linewidth=2.5, label='N(0,1)')
ax.set_xlabel('t', fontsize=12)
ax.set_ylabel('f(t)', fontsize=12)
ax.set_title("Student's t-Distribution PDF", fontsize=13)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3)
# (b) 裾の重さの比較(対数スケール)
ax = axes[0, 1]
for df in [1, 5, 30]:
pdf = stats.t.pdf(x, df)
ax.plot(x, pdf, linewidth=2, label=f't($\\nu$={df})')
ax.plot(x, stats.norm.pdf(x), 'k--', linewidth=2.5, label='N(0,1)')
ax.set_xlabel('t', fontsize=12)
ax.set_ylabel('f(t) [log scale]', fontsize=12)
ax.set_title('Heavy Tails of t-Distribution', fontsize=12)
ax.set_yscale('log')
ax.set_ylim(1e-5, 1)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
# (c) t検定のシミュレーション
ax = axes[1, 0]
np.random.seed(42)
n_sim = 10000
n_sample = 5
mu_true = 0
sigma_true = 1
t_stats = []
z_stats = []
for _ in range(n_sim):
sample = np.random.normal(mu_true, sigma_true, n_sample)
x_bar = np.mean(sample)
s = np.std(sample, ddof=1)
t_stats.append(x_bar / (s / np.sqrt(n_sample)))
z_stats.append(x_bar / (sigma_true / np.sqrt(n_sample)))
ax.hist(z_stats, bins=80, density=True, alpha=0.5, color='steelblue',
label='Z-statistic (σ known)')
ax.hist(t_stats, bins=80, density=True, alpha=0.5, color='coral',
label='T-statistic (σ unknown)')
x_range = np.linspace(-6, 6, 300)
ax.plot(x_range, stats.norm.pdf(x_range), 'b-', linewidth=2)
ax.plot(x_range, stats.t.pdf(x_range, n_sample-1), 'r-', linewidth=2)
ax.set_xlabel('Statistic value', fontsize=12)
ax.set_ylabel('Density', fontsize=12)
ax.set_title(f't vs z Statistic (n={n_sample})', fontsize=12)
ax.legend(fontsize=9)
ax.grid(True, alpha=0.3)
# (d) 自由度と分散の関係
ax = axes[1, 1]
nu_range = np.arange(3, 101)
var_t = nu_range / (nu_range - 2)
ax.plot(nu_range, var_t, 'b-', linewidth=2.5,
label=r'$\mathrm{Var}(T) = \nu/(\nu-2)$')
ax.axhline(1, color='red', linestyle='--', linewidth=1.5,
label='N(0,1) variance = 1')
ax.set_xlabel('$\\nu$ (degrees of freedom)', fontsize=12)
ax.set_ylabel('Variance', fontsize=12)
ax.set_title('t-Distribution Variance vs $\\nu$', fontsize=13)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
ax.set_ylim(0.9, 4)
plt.tight_layout()
plt.savefig('student_t_distribution.png', dpi=150, bbox_inches='tight')
plt.show()
この可視化から、t分布の特徴が明確に読み取れます。
-
左上(PDF): 自由度が小さいほど裾が重く、正規分布(黒い破線)から離れています。$\nu = 30$ ではほぼ正規分布と区別がつきません。
-
右上(対数スケール): 裾の重さが対数スケールで明確に見えます。$t(\nu=1)$(コーシー分布)は $|t| = 5$ でも正規分布の100倍以上の密度を持ちます。
-
左下(t検定vs z検定): $n = 5$ の小標本では、t統計量(赤)が z統計量(青)よりばらつきが大きいことが確認できます。$\sigma$ を $S$ で推定する不確実性がt分布の広がりに反映されています。
-
右下(分散の収束): t分布の分散 $\nu/(\nu-2)$ は $\nu \to \infty$ で1(正規分布の分散)に収束しますが、$\nu$ が小さいと急激に増大します。
まとめ
本記事では、t分布の導出から性質、t検定への応用まで解説しました。
- t分布は $Z/\sqrt{V/\nu}$(標準正規÷カイ二乗の平方根)として導出される
- 自由度 $\nu$ は標本サイズに関連し、$\nu$ が大きいほど正規分布に近づく
- 裾が重い: 分散未知の不確実性が裾の重さに反映される
- t検定は母分散が未知の場合の母平均の検定に不可欠
- $\nu \geq 30$ で正規近似が良好
次のステップとして、以下の記事も参考にしてください。