2014 Q5(3)
テレビ番組の視聴満足回数の調査で満足と答えた回数のそれぞれ人数の適合度検定のための尤度比検定量と自由度を求めました。
コード
多項確率が、に忠実に基づく場合と、ランダムにノイズを加えた(ズレた)場合についてシミュレーションを行い、尤度比統計量とp-値を計算して比較します。
# 2014 Q5(3) 2025.1.17
import numpy as np
from scipy.stats import chi2
import matplotlib.pyplot as plt
# シミュレーションの設定
n = 100 # 人数
p_true = 0.6 # 真の成功確率
categories = np.arange(5) # カテゴリ (0~4)
n_simulations = 1000 # シミュレーション回数
# 二項分布モデルに基づく q_j の計算 (忠実な設定)
qj_true = [np.math.comb(4, j) * (p_true ** j) * ((1 - p_true) ** (4 - j)) for j in categories]
# 二項分布に従わない (qj_noisy): q_j をランダムに変更してズラす
qj_noisy = np.array(qj_true) + np.random.uniform(-0.1, 0.1, size=len(qj_true))
qj_noisy = np.clip(qj_noisy, 0, None) # 確率が0未満にならないようにする
qj_noisy = qj_noisy / np.sum(qj_noisy) # 確率なので正規化
# 尤度比統計量を記録するリスト
likelihood_ratio_true = []
p_values_true = []
likelihood_ratio_noisy = []
p_values_noisy = []
for _ in range(n_simulations):
# 忠実なモデルの観測データ
obs_true = np.random.multinomial(n, qj_true)
exp_true = n * np.array(qj_true)
likelihood_stat_true = 2 * np.sum(obs_true * np.log(obs_true / exp_true, where=(obs_true > 0)))
p_val_true = 1 - chi2.cdf(likelihood_stat_true, df=3) # 自由度 = カテゴリ数 - 1 - 推定パラメータ数
likelihood_ratio_true.append(likelihood_stat_true)
p_values_true.append(p_val_true)
# ズレたモデルの観測データ
obs_noisy = np.random.multinomial(n, qj_noisy)
exp_noisy = n * np.array(qj_true) # 忠実な期待値を使用
likelihood_stat_noisy = 2 * np.sum(obs_noisy * np.log(obs_noisy / exp_noisy, where=(obs_noisy > 0)))
p_val_noisy = 1 - chi2.cdf(likelihood_stat_noisy, df=3)
likelihood_ratio_noisy.append(likelihood_stat_noisy)
p_values_noisy.append(p_val_noisy)
# 平均尤度比統計量を計算
mean_likelihood_true = np.mean(likelihood_ratio_true)
mean_likelihood_noisy = np.mean(likelihood_ratio_noisy)
# カイ二乗分布のPDFを計算
x = np.linspace(0, 20, 500) # x軸の範囲
pdf = chi2.pdf(x, df=3) # 自由度3のPDF
# 結果の出力
print(f"忠実なモデルの平均尤度比統計量: {mean_likelihood_true:.4f}")
print(f"忠実なモデルの平均p値: {np.mean(p_values_true):.4f}")
print(f"ズレたモデルの平均尤度比統計量: {mean_likelihood_noisy:.4f}")
print(f"ズレたモデルの平均p値: {np.mean(p_values_noisy):.4f}")
# グラフの描画
plt.figure(figsize=(10, 6))
plt.plot(x, pdf, label="自由度3のカイ二乗分布", linewidth=2)
plt.axvline(mean_likelihood_true, color="blue", linestyle="--", label=f"忠実モデルの平均: {mean_likelihood_true:.2f}")
plt.axvline(mean_likelihood_noisy, color="red", linestyle="--", label=f"ズレモデルの平均: {mean_likelihood_noisy:.2f}")
plt.xlabel("$X^2$ 値", fontsize=12)
plt.ylabel("確率密度", fontsize=12)
plt.title("自由度3のカイ二乗分布と平均尤度比統計量", fontsize=14)
plt.legend(fontsize=12)
plt.grid(alpha=0.5)
plt.show()
忠実なモデルの平均尤度比統計量: 3.9418
忠実なモデルの平均p値: 0.3909
ズレたモデルの平均尤度比統計量: 16.7360
ズレたモデルの平均p値: 0.0081
忠実なモデルの平均p-値は大きく、モデルによく適合していることが分かります。一方、ランダムにノイズを加えた(ズレた)モデルではp-値が0.05以下となり、モデルがデータに適合していないことが分かります。
2014 Q5(2)
テレビ番組の視聴満足回数の調査で満足と答えた回数のそれぞれ人数の適合度カイ二乗統計量と自由度を求めました。
コード
多項確率が、に忠実に基づく場合と、ランダムにノイズを加えた(ズレた)場合についてシミュレーションを行い、適合度カイ二乗統計量とp-値を計算して比較します。
# 2014 Q5(2) 2025.1.16
import numpy as np
from scipy.stats import chi2
import matplotlib.pyplot as plt
# シミュレーションの設定
n = 100 # 人数
p_true = 0.6 # 真の成功確率
categories = np.arange(5) # カテゴリ (0~4)
n_simulations = 1000 # シミュレーション回数
# 二項分布モデルに基づく q_j の計算 (忠実な設定)
qj_true = [np.math.comb(4, j) * (p_true ** j) * ((1 - p_true) ** (4 - j)) for j in categories]
# 二項分布に従わない (qj_noisy): q_j をランダムに変更してズラす
qj_noisy = np.array(qj_true) + np.random.uniform(-0.1, 0.1, size=len(qj_true))
qj_noisy = np.clip(qj_noisy, 0, None) # 確率が0未満にならないようにする
qj_noisy = qj_noisy / np.sum(qj_noisy) # 確率なので正規化
# カイ二乗統計量と p 値を記録するリスト
chi_squared_true = []
p_values_true = []
chi_squared_noisy = []
p_values_noisy = []
for _ in range(n_simulations):
# 忠実なモデルの観測データ
obs_true = np.random.multinomial(n, qj_true)
exp_true = n * np.array(qj_true)
chi2_stat_true = np.sum((obs_true - exp_true) ** 2 / exp_true)
p_val_true = 1 - chi2.cdf(chi2_stat_true, df=3) # 自由度 = カテゴリ数 - 1 - 推定パラメータ数
chi_squared_true.append(chi2_stat_true)
p_values_true.append(p_val_true)
# ズレたモデルの観測データ
obs_noisy = np.random.multinomial(n, qj_noisy)
exp_noisy = n * np.array(qj_true) # 忠実な期待値を使用
chi2_stat_noisy = np.sum((obs_noisy - exp_noisy) ** 2 / exp_noisy)
p_val_noisy = 1 - chi2.cdf(chi2_stat_noisy, df=3)
chi_squared_noisy.append(chi2_stat_noisy)
p_values_noisy.append(p_val_noisy)
# 平均カイ二乗統計量を計算
mean_chi2_true = np.mean(chi_squared_true)
mean_chi2_noisy = np.mean(chi_squared_noisy)
# カイ二乗分布のPDFを計算
x = np.linspace(0, 20, 500) # x軸の範囲
pdf = chi2.pdf(x, df=3) # 自由度3のPDF
# 結果の出力
print(f"忠実なモデルの平均カイ二乗統計量: {mean_chi2_true:.4f}")
print(f"忠実なモデルの平均p値: {np.mean(p_values_true):.4f}")
print(f"ズレたモデルの平均カイ二乗統計量: {mean_chi2_noisy:.4f}")
print(f"ズレたモデルの平均p値: {np.mean(p_values_noisy):.4f}")
# グラフの描画
plt.figure(figsize=(10, 6))
plt.plot(x, pdf, label="自由度3のカイ二乗分布", linewidth=2)
plt.axvline(mean_chi2_true, color="blue", linestyle="--", label=f"忠実モデルの平均: {mean_chi2_true:.2f}")
plt.axvline(mean_chi2_noisy, color="red", linestyle="--", label=f"ズレモデルの平均: {mean_chi2_noisy:.2f}")
plt.xlabel("$X^2$ 値", fontsize=12)
plt.ylabel("確率密度", fontsize=12)
plt.title("自由度3のカイ二乗分布と平均カイ二乗統計量", fontsize=14)
plt.legend(fontsize=12)
plt.grid(alpha=0.5)
plt.show()
忠実なモデルの平均カイ二乗統計量: 3.8112
忠実なモデルの平均p値: 0.4026
ズレたモデルの平均カイ二乗統計量: 13.4317
ズレたモデルの平均p値: 0.0236
忠実なモデルの平均p-値は大きく、モデルによく適合していることが分かります。一方、ランダムにノイズを加えた(ズレた)モデルではp-値が0.05以下となり、モデルがデータに適合していないことが分かります。
2014 Q5(1)
テレビ番組の視聴満足回数の調査で満足と答えた回数のそれぞれ人数との組みが多項分布に従うのを利用し多項確率を構成する二項分布の確率pの最尤推定量を求めました。
コード
真の確率pに基づいてシミュレーションを行い、最尤推定値を計算し、真の確率pと比較します。
# 2014 Q5(1) 2025.1.15
import numpy as np
import matplotlib.pyplot as plt
# シミュレーションのパラメータ
n_simulations = 10000 # シミュレーション回数
n = 100 # 調査対象の人数
p_true = 0.6 # 真の満足確率
# nj のシミュレーション (j = 0, 1, 2, 3, 4)
data = np.random.binomial(4, p_true, size=n_simulations * n).reshape(n_simulations, n)
# 各シミュレーションでの最尤推定値を計算
p_estimates = np.sum(data, axis=1) / (4 * n)
# 平均値(推定されたp^の期待値)を計算
mean_p_estimate = np.mean(p_estimates)
# 推定されたp^の平均値と真の値を出力
print(f"推定された最尤推定値の平均: {mean_p_estimate:.4f}")
print(f"真の値: {p_true:.4f}")
# グラフの描画
plt.hist(p_estimates, bins=30, density=True, alpha=0.75, label="推定された $\\hat{p}$")
plt.axvline(p_true, color='red', linestyle='dashed', label=f"真の値 $p = {p_true}$")
plt.xlabel("推定された $\\hat{p}$")
plt.ylabel("密度")
plt.title("最尤推定値 $\\hat{p}$ の分布")
plt.legend()
plt.grid(alpha=0.5)
plt.show()
推定された最尤推定値の平均: 0.5997
真の値: 0.6000
シミュレーションの結果、最尤推定値は、真の確率pに近い値を示しました。
2014 Q4(5)
5個の物体の重さを、1つずつ2回量る場合と、2つずつ10通り量る場合で、物体の重さが全て同じか、そうでないかF検定するとき、どちらの場合が効率的かを示しました。
コード
(1)の計画行列X1と、(2)の計画行列X2を、それぞれ0と1を反転させた計画行列X3,X4を加え、それぞれの分散と非心度λを計算して比較してみます。
# 2014 Q4(5) 2025.1.14
import numpy as np
# 設計行列 (1)~(4)
X1 = np.array([
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1]
])
X2 = np.array([
[1, 1, 0, 0, 0],
[1, 0, 1, 0, 0],
[1, 0, 0, 1, 0],
[1, 0, 0, 0, 1],
[0, 1, 1, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 0, 0, 1],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 1],
[0, 0, 0, 1, 1]
])
X3 = 1 - X2 # (2) の反転
X4 = 1 - X1 # (1) の反転
# 設計行列リスト
design_matrices = [X1, X2, X3, X4]
# 真の値 θ
true_theta = np.array([10, 20, 30, 40, 50])
# 結果を格納するリスト
results = []
for i, X in enumerate(design_matrices, start=1):
# 分散行列を計算
variance_matrix = np.linalg.inv(X.T @ X)
# 平均分散を計算
mean_variance = np.trace(variance_matrix) / len(variance_matrix)
# 非心度 λ を計算
theta_mean = np.mean(true_theta)
ones_vector = np.ones((X.shape[0], 1)) # X の行数に応じた列ベクトル
theta_centered = true_theta - theta_mean # θ から平均を引いたベクトル
numerator = theta_centered.T @ X.T @ X @ theta_centered
denominator = ones_vector.T @ X @ X.T @ ones_vector
non_centrality_lambda = numerator.item() # スカラーに変換
# 結果を保存
results.append((i, mean_variance, non_centrality_lambda))
# 結果の出力
for i, mean_variance, non_centrality_lambda in results:
print(f"(X{i}) の平均分散: {mean_variance:.6f}, 非心度 λ: {non_centrality_lambda:.6f}")
(X1) の平均分散: 0.500000, 非心度 λ: 2000.000000
(X2) の平均分散: 0.291667, 非心度 λ: 3000.000000
(X3) の平均分散: 0.277778, 非心度 λ: 3000.000000
(X4) の平均分散: 0.406250, 非心度 λ: 2000.000000
(2)の計画行列X2は、(1)の計画行列X1に比べ、平均分散が小さく、非心度 λが大きいため、より優れた計画行列と言えます。また、X2の0と1を反転したX3は、X2よりも分散がさらに小さく、非心度 λが変化しないことから、この中で最も優れた計画行列と考えられます。
X3 = np.array([
[0, 0, 1, 1, 1],
[0, 1, 0, 1, 1],
[0, 1, 1, 0, 1],
[0, 1, 1, 1, 0],
[1, 0, 0, 1, 1],
[1, 0, 1, 0, 1],
[1, 0, 1, 1, 0],
[1, 1, 0, 0, 1],
[1, 1, 0, 1, 0],
[1, 1, 1, 0, 0]
])
2014 Q4(4)
5個の物体の重さを2つずつ10通り量る場合で、誤差の分散を未知とし、全ての物体の重さが等しいとはいえないとする対立仮説のF検定量の非心度を求めました。
コード
真の値からへ徐々に変化させて、非心度λを計算し、その変化をグラフにプロットしてみます。測定法(1)と測定法(2)を同時に表示し、分散の違いを確認してみます。
# 2014 Q4(4) 2025.1.13
import numpy as np
import matplotlib.pyplot as plt
# 初期設定
theta_initial = np.array([10, 10, 10, 10, 10]) # 初期の真の値
theta_final = np.array([10, 20, 30, 40, 50]) # 最終的な真の値
steps = 50 # 変化のステップ数
# θを徐々に変化させる
theta_values = [theta_initial + (theta_final - theta_initial) * t / steps for t in range(steps + 1)]
# 非心度 λ を計算
# 測定法(1): 係数は2
lambdas_1 = [2 * np.sum((theta - np.mean(theta)) ** 2) for theta in theta_values]
# 測定法(2): 係数は3
lambdas_2 = [3 * np.sum((theta - np.mean(theta)) ** 2) for theta in theta_values]
# サンプルのインデックス(途中でいくつかの点を表示)
sample_indices = [0, 10, 20, 30, 40, 50]
# 真の値と対応する λ を取得 (測定法(1) と測定法(2))
sample_theta_values = [theta_values[i] for i in sample_indices]
sample_lambdas_1 = [lambdas_1[i] for i in sample_indices]
sample_lambdas_2 = [lambdas_2[i] for i in sample_indices]
# 視覚化
plt.figure(figsize=(12, 8))
# 測定法(1) のプロット
plt.plot(range(steps + 1), lambdas_1, label="測定法(1): λ", color="blue")
plt.scatter(sample_indices, sample_lambdas_1, color="blue", label="測定法(1) サンプル点")
for i, (theta, lam) in enumerate(zip(sample_theta_values, sample_lambdas_1)):
plt.text(sample_indices[i], lam, f"{np.round(theta, 1)}\nλ={lam:.1f}",
fontsize=10, ha="center", color="blue")
# 測定法(2) のプロット
plt.plot(range(steps + 1), lambdas_2, label="測定法(2): λ", color="red")
plt.scatter(sample_indices, sample_lambdas_2, color="red", label="測定法(2) サンプル点")
for i, (theta, lam) in enumerate(zip(sample_theta_values, sample_lambdas_2)):
plt.text(sample_indices[i], lam, f"{np.round(theta, 1)}\nλ={lam:.1f}",
fontsize=10, ha="center", color="red")
# グラフの設定
plt.xlabel("変化のステップ数")
plt.ylabel("非心度 λ")
plt.title("真の値の変化による非心度 λ の変化 (測定法(1) と 測定法(2))")
plt.legend()
plt.grid()
plt.show()
真の値のばらつきが大きくなるにつれて、非心度λも非線形的に増加することが確認できました。また測定法(1)のほうが測定法(2)より分散が大きいことが確認できました。