サンプルサイズの決め方3章 1つの母平均の検定-母分散が既知の場合
はじめに
このブログ記事では、永田靖著『サンプルサイズの決め方』(朝倉書店)の3章を参考に、母平均の検定、検出力の計算方法、適切なサンプルサイズの設計方法について解説します。これらの概念は、実験計画やデータ分析において非常に重要です。これら統計学の基本的な概念をPythonを用いて実装しながら確認していきます。
母分散が既知の場合の母平均の検定
サンプルサイズの決め方3章では母分散が既知の時の母平均の検定の手順は以下のように紹介されています。
-
手順1:仮説の設定
- 帰無仮説
(H₀:μ = μ₀ は指定された値)μ₀ - 対立仮説 (1)
H₁:μ ≠ μ₀ - 対立仮説 (2)
H₁:μ > μ₀ - 対立仮説 (3)
H₁:μ < μ₀
- 帰無仮説
-
手順2:有意水準
の設定(通常はα とする)α = 0.05 -
手順3:棄却域
の設定R - 対立仮説 (1) の場合
R:|u₀| ≥ z_{α/2} - 対立仮説 (2) の場合
R:u₀ ≥ z_{α} - 対立仮説 (3) の場合
R:u₀ ≤ z_{₁-α}(= -z_{α})
- 対立仮説 (1) の場合
-
手順4:データ
をとり、検定統計量x₁, x₂, ···, xₙ の値を計算する。u_₀
(u₀ = \frac{(x̄ - μ₀)}{\sqrt{(σ₀²/n)}} は既知の母分散の値)σ_₀^² -
手順5:
が手順3で設定した棄却域u₀ にあれば有意と判定し、R を棄却する。H_₀
この検定では、
pythonで実装すると以下のようになります。
import numpy as np
from scipy import stats
def hypothesis_test(data, mu0, sigma0, alpha=0.05, test_type='two-sided'):
n = len(data)
x_bar = np.mean(data)
u0 = (x_bar - mu0) / (sigma0 / np.sqrt(n))
if test_type == 'two-sided':
critical_value = stats.norm.ppf(1 - alpha/2)
reject = abs(u0) >= critical_value
elif test_type == 'greater':
critical_value = stats.norm.ppf(1 - alpha)
reject = u0 >= critical_value
elif test_type == 'less':
critical_value = stats.norm.ppf(alpha)
reject = u0 <= critical_value
else:
raise ValueError("Invalid test_type. Choose 'two-sided', 'greater', or 'less'.")
return {
'test_statistic': u0,
'critical_value': critical_value,
'reject_null': reject
}
そこで、実際にこの関数を用いて練習問題を解いていきたいと思います。
print("問題3.1の結果:")
data_3_1 = [6.2, 4.8, 7.3, 5.5, 6.5, 4.9, 6.8, 7.9, 6.6, 7.3]
mu0_3_1 = 5.0
sigma0_3_1 = 1.0
result_3_1 = hypothesis_test(data_3_1, mu0_3_1, sigma0_3_1, alpha=0.05, test_type='two-sided')
print(f"検定統計量 u0: {result_3_1['test_statistic']:.4f}")
print(f"棄却域の境界: ±{result_3_1['critical_value']:.4f}")
print(f"帰無仮説を棄却するか: {'はい' if result_3_1['reject_null'] else 'いいえ'}")
問題3.1の結果:
検定統計量 u0: 4.3639
棄却域の境界: ±1.9600
帰無仮説を棄却するか: はい
この問題は対立仮説が
次に、練習問題3-2を同様に解いていきます。
print("問題3.2の結果:")
data_3_2 = [10.8, 11.2, 9.7, 9.9, 12.0, 9.6, 10.5, 10.7, 10.1]
mu0_3_2 = 10.0
sigma0_3_2 = 0.7
result_3_2 = hypothesis_test(data_3_2, mu0_3_2, sigma0_3_2, alpha=0.05, test_type='greater')
print(f"検定統計量 u0: {result_3_2['test_statistic']:.4f}")
print(f"棄却域の境界: {result_3_2['critical_value']:.4f}")
print(f"帰無仮説を棄却するか: {'はい' if result_3_2['reject_null'] else 'いいえ'}")
問題3.2の結果:
検定統計量 u0: 2.1429
棄却域の境界: 1.6449
帰無仮説を棄却するか: はい
この問題は対立仮説が
3-3も同様に解くと以下のようになります。
print("問題3.3の結果:")
data_3_3 = [21, 19, 16, 19, 22, 18, 20, 21]
mu0_3_3 = 20.0
sigma0_3_3 = 2.0
result_3_3 = hypothesis_test(data_3_3, mu0_3_3, sigma0_3_3, alpha=0.05, test_type='less')
print(f"検定統計量 u0: {result_3_3['test_statistic']:.4f}")
print(f"棄却域の境界: {result_3_3['critical_value']:.4f}")
print(f"帰無仮説を棄却するか: {'はい' if result_3_3['reject_null'] else 'いいえ'}")
問題3.3の結果:
検定統計量 u0: -0.7071
棄却域の境界: -1.6449
帰無仮説を棄却するか: いいえ
この問題は対立仮説が
検出力の計算
次に、検出力の計算について解説します。検出力(1 - β)は対立仮説
ただし、
これらのことを踏まえて、実際に例題をpythonを用いて解いていきたいと思います。
検出力を計算するプログラムは以下のようになります。
import numpy as np
from scipy import stats
def calculate_power(n, alpha, delta, test_type='two-sided'):
"""
検出力を計算する関数
n: サンプルサイズ
alpha: 有意水準
delta: Δ
test_type: 検定の種類 ('two-sided', 'greater', 'less')
return: 検出力 (1 - β)
"""
if test_type == 'two-sided':
z_alpha = stats.norm.ppf(1 - alpha / 2)
power = (1 - stats.norm.cdf(z_alpha - np.sqrt(n) * delta) +
stats.norm.cdf(-z_alpha - np.sqrt(n) * delta))
elif test_type == 'greater':
z_alpha = stats.norm.ppf(1 - alpha)
power = 1 - stats.norm.cdf(z_alpha - np.sqrt(n) * delta)
elif test_type == 'less':
z_alpha = stats.norm.ppf(1 - alpha)
power = stats.norm.cdf(-z_alpha - np.sqrt(n) * delta)
else:
raise ValueError("Invalid test_type. Choose 'two-sided', 'greater', or 'less'.")
return power
そこで、上で定義した関数を用いて、練習問題3-5から問いていきたいと思います。
print("問題3.5の結果:")
alpha_3_5 = 0.05
delta_3_5 = 0.5
# (1) n = 10
n_3_5_1 = 10
power_3_5_1 = calculate_power(n_3_5_1, alpha_3_5, delta_3_5, 'two-sided')
print(f"(1) n = 10 の場合の検出力: {power_3_5_1:.4f}")
# (2) n = 20
n_3_5_2 = 20
power_3_5_2 = calculate_power(n_3_5_2, alpha_3_5, delta_3_5, 'two-sided')
print(f"(2) n = 20 の場合の検出力: {power_3_5_2:.4f}")
問題3.5の結果:
(1) n = 10 の場合の検出力: 0.3526
(2) n = 20 の場合の検出力: 0.6088
この問題ではサンプルサイズを増やすことで検出力が向上することが確認できました。
# 問題3.6
print("問題3.6の結果:")
alpha_3_6 = 0.05
n_3_6 = 9
# (1) Δ = 1.0
delta_3_6_1 = 1.0
power_3_6_1 = calculate_power(n_3_6, alpha_3_6, delta_3_6_1, 'greater')
print(f"(1) Δ = 1.0 の場合の検出力: {power_3_6_1:.4f}")
# (2) Δ = 1.5
delta_3_6_2 = 1.5
power_3_6_2 = calculate_power(n_3_6, alpha_3_6, delta_3_6_2, 'greater')
print(f"(2) Δ = 1.5 の場合の検出力: {power_3_6_2:.4f}")
問題3.6の結果:
(1) Δ = 1.0 の場合の検出力: 0.9123
(2) Δ = 1.5 の場合の検出力: 0.9978
Δが大きくなると検出力が上がることがわかります。
# 問題3.7
print("問題3.7の結果:")
alpha_3_7 = 0.05
delta_3_7 = -1.0
# (1) n = 8
n_3_7_1 = 8
power_3_7_1 = calculate_power(n_3_7_1, alpha_3_7, delta_3_7, 'less')
print(f"(1) n = 8 の場合の検出力: {power_3_7_1:.4f}")
# (2) n = 16
n_3_7_2 = 16
power_3_7_2 = calculate_power(n_3_7_2, alpha_3_7, delta_3_7, 'less')
print(f"(2) n = 16 の場合の検出力: {power_3_7_2:.4f}")
問題3.7の結果:
(1) n = 8 の場合の検出力: 0.8817
(2) n = 16 の場合の検出力: 0.9907
サンプルサイズを2倍にすることで、検出力が大幅に向上しています。
サンプルサイズの設計方法
書籍ではサンプルサイズの設計方法は以下のように紹介されています。
これをpythonで実装したプログラムは以下の通りです。
import math
from scipy import stats
def calculate_sample_size(alpha, beta, delta, test_type):
z_alpha = stats.norm.ppf(1 - alpha)
z_beta = stats.norm.ppf(1 - beta)
if test_type == "two_sided":
z_alpha = stats.norm.ppf(1 - alpha/2)
# 初期値の設定
n_min, n_max = 2, 1000
while n_min <= n_max:
n = (n_min + n_max) // 2
if test_type == "two_sided":
power = 1 - stats.norm.cdf(z_alpha - math.sqrt(n) * delta) + stats.norm.cdf(-z_alpha - math.sqrt(n) * delta)
else:
power = 1 - stats.norm.cdf(z_alpha - math.sqrt(n) * delta)
if abs(power - (1 - beta)) < 0.0001:
return n
elif power < (1 - beta):
n_min = n + 1
else:
n_max = n - 1
return n_min
この関数を用いて以下の練習問題を解いていきます。
print("問題 3.8:")
alpha = 0.05
delta = 0.8
# (1) Power = 0.90
n1 = calculate_sample_size(alpha, 0.10, delta, "two_sided")
print(f"(1) 検出力0.90のサンプルサイズ: {n1}")
# (2) Power = 0.95
n2 = calculate_sample_size(alpha, 0.05, delta, "two_sided")
print(f"(2) 検出力0.95のサンプルサイズ: {n2}")
問題 3.8:
(1) 検出力0.90のサンプルサイズ: 17
(2) 検出力0.95のサンプルサイズ: 21
この結果は、検出力を高めるためにはサンプルサイズを増やす必要があることを示しています。
print("問題 3.9:")
alpha = 0.05
beta = 0.10 # Power = 1 - beta = 0.90
# (1) Delta = 1.0
n1 = calculate_sample_size(alpha, beta, 1.0, "one_sided")
print(f"(1) Δ >= 1.0 かつ検出力 0.90 の場合のサンプルサイズ: {n1}")
# (2) Delta = 0.5
n2 = calculate_sample_size(alpha, beta, 0.5, "one_sided")
print(f"(2) Δ >= 0.5 かつ検出力 0.90 の場合のサンプルサイズ: {n2}")
問題 3.9:
(1) Δ >= 1.0 かつ検出力 0.90 の場合のサンプルサイズ: 9
(2) Δ >= 0.5 かつ検出力 0.90 の場合のサンプルサイズ: 35
Δが小さい場合、十分な検出力を得るためにはサンプルサイズを大幅に増やす必要があることがわかります。
print("問題 3.10:")
alpha = 0.05
# (1) Delta = -1.2, Power = 0.90
n1 = calculate_sample_size(alpha, 0.10, 1.2, "one_sided")
print(f"(1) Δ ≤ -1.2 かつ検出力 0.90 の場合のサンプルサイズ: {n1}")
# (2) Delta = -1.5, Power = 0.95
n2 = calculate_sample_size(alpha, 0.05, 1.5, "one_sided")
print(f"(2) Δ ≤ -1.5 かつ検出力 0.95 の場合のサンプルサイズ: {n2}")
問題 3.10:
(1) Δ ≤ -1.2 かつ検出力 0.90 の場合のサンプルサイズ: 6
(2) Δ ≤ -1.5 かつ検出力 0.95 の場合のサンプルサイズ: 5
最後に
本ブログでは、永田靖著『サンプルサイズの決め方』の第3章「一つの母平均の検定-母分散が既知の場合」の内容を、Pythonを用いて実践的に解説しました。ここで学んだ主要なポイントは以下の通りです:
- 母平均の検定の基本概念と手順
- 検出力の計算方法とその重要性
- 適切なサンプルサイズの設計方法
次回のブログでは、『サンプルサイズの決め方』の第4章の内容を取り上げる予定です。このブログを通して少しでもサンプルサイズの設計方法について理解が進めば幸いです。
Discussion