2019 Q1(3)

確率母関数の不等式を証明する問題をやりました。

 

コード

不等式P(X \leq r) \leq t^{-r} G_X(t)を可視化して確認しました。ここでは二項分布で試しています。

# 2019 Q1(3)  2024.9.11

import numpy as np
import matplotlib.pyplot as plt

# パラメータ設定
n = 10  # 二項分布の試行回数
p = 0.5  # 二項分布の成功確率
t_values = [0.001, 0.2, 0.4, 0.6, 0.8, 1]  # t の値のリスト
sample_size = 10000  # サンプル数
r_values = np.arange(0, n+1, 1)  # r の範囲を設定

# 確率母関数 G_X(t) の定義
def G_X(t, n, p):
    return (p * t + (1 - p))**n

# 1. 二項分布から乱数を生成
samples = np.random.binomial(n, p, sample_size)

# 2. r に対する P(X <= r) の推定(左辺)
P_X_leq_r_values = [np.sum(samples <= r) / sample_size for r in r_values]

# サブプロットの作成
fig, axes = plt.subplots(2, 3, figsize=(15, 8))  # 2行3列のサブプロットを作成

# 3. 各 t に対するグラフを描画
for i, t in enumerate(t_values):
    row = i // 3  # 行番号
    col = i % 3   # 列番号

    # 右辺 t^{-r} G_X(t) の計算
    G_X_value = G_X(t, n, p)  # 確率母関数の t 固定
    right_hand_side_values = [G_X_value if t == 1 else t**(-r) * G_X_value for r in r_values]  # t = 1 の場合はべき乗を回避

    # グラフの描画
    ax = axes[row, col]
    ax.plot(r_values, P_X_leq_r_values, label="P(X <= r) (左辺)", color="blue", linestyle="--")
    ax.plot(r_values, right_hand_side_values, label="t^(-r) G_X(t) (右辺)", color="red")
    ax.set_title(f"t = {t}")
    ax.set_xlabel("r")
    ax.set_ylabel("値 (対数スケール)")
    ax.set_yscale('log')  # 縦軸を対数スケールに設定
    ax.legend()
    ax.grid(True, which="both", ls="--")

# サブプロット間のレイアウト調整
plt.tight_layout()
plt.show()

不等式P(X \leq r) \leq t^{-r} G_X(t)が成り立っていることが確認できました

2019 Q1(2)

二項分布の確率母関数を求め、期待値と分散を算出しました。

 

コード

非負の離散型観測データから確率母関数を構築し、これの微分と2階微分から期待値と分散を求めます。ここでは、観測データとして二項分布の乱数を用いて、その理論的な母関数と期待値と分散の比較を行います。

# 2019 Q1(2)  2024.9.10

import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative

# パラメータ設定
n = 10  # 試行回数
p = 0.5  # 成功確率
sample_size = 10000  # サンプル数

# 1. 二項分布に従う乱数データを生成
samples = np.random.binomial(n, p, sample_size)

# 2. P(X=k) の推定(サンプル度数から確率質量関数の推定)
max_k = np.max(samples)
pmf_estimate = np.zeros(max_k + 1)
for k in range(max_k + 1):
    pmf_estimate[k] = np.sum(samples == k) / sample_size

# 3. G_X(t) の推定
def G_X(t):
    return np.sum([pmf_estimate[k] * t**k for k in range(max_k + 1)])

# 4. 理論的な G_X(t) (二項分布の確率母関数)
def G_X_theoretical(t, n, p):
    return (p * t + (1 - p))**n

# 5. G_X(t) のプロット
t_values = np.linspace(0, 1, 100)
G_X_values = [G_X(t) for t in t_values]
G_X_theoretical_values = [G_X_theoretical(t, n, p) for t in t_values]

plt.plot(t_values, G_X_values, label="推定された G_X(t)", color="blue")
plt.plot(t_values, G_X_theoretical_values, label="理論的な G_X(t)", linestyle='--', color="red")
plt.title("推定された確率母関数と理論的な G_X(t) の比較")
plt.xlabel("t")
plt.ylabel("G_X(t)")
plt.legend()
plt.show()

# 6. G_X(t) の微分と2階微分
def G_X_diff_1(t):
    return derivative(G_X, t, dx=1e-6)

def G_X_diff_2(t):
    return derivative(G_X_diff_1, t, dx=1e-6)

# 7. t = 1 における期待値と分散の推定
E_X_estimated = G_X_diff_1(1)  # 期待値
Var_X_estimated = G_X_diff_2(1) + E_X_estimated - E_X_estimated**2  # 分散

# 結果の出力
print(f"推定された期待値 E[X]: {E_X_estimated}")
print(f"推定された分散 Var(X): {Var_X_estimated}")

# 真の期待値と分散を計算
E_X_true = n * p
Var_X_true = n * p * (1 - p)

# 真の期待値と分散を出力
print(f"真の期待値 E[X]: {E_X_true}")
print(f"真の分散 Var(X): {Var_X_true}")
推定された期待値 E[X]: 4.9988999998862305
推定された分散 Var(X): 2.4964947096596752
真の期待値 E[X]: 5.0
真の分散 Var(X): 2.5

観測値から推定された確率母関数は理論的な二項分布の確率母関数と一致しました。また、推定された確率母関数から計算された期待値と分散も、真の値に非常に近い結果となりました。

次に、二項分布の確率母関数$G_X(t)$、その1階微分 $G'_X(t)$、および2階微分 $G''_X(t)$ を視覚的に比較してみます。

# 2019 Q1(2)  2024.9.10

import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative

# パラメータ設定
n = 10  # 試行回数
p = 0.5  # 成功確率

# 確率母関数 G_X(t)
def G_X(t, n, p):
    return (p * t + (1 - p))**n

# 1階微分 G'_X(t)
def G_X_diff_1(t, n, p):
    return derivative(lambda t: G_X(t, n, p), t, dx=1e-6)

# 2階微分 G''_X(t)
def G_X_diff_2(t, n, p):
    return derivative(lambda t: G_X_diff_1(t, n, p), t, dx=1e-6)

# t の範囲を定義
t_values = np.linspace(0, 1, 100)

# G_X(t), G'_X(t), G''_X(t) の値を計算
G_X_values = [G_X(t, n, p) for t in t_values]
G_X_diff_1_values = [G_X_diff_1(t, n, p) for t in t_values]
G_X_diff_2_values = [G_X_diff_2(t, n, p) for t in t_values]

# グラフの描画
plt.plot(t_values, G_X_values, label="G_X(t) (確率母関数)", color="blue")
plt.plot(t_values, G_X_diff_1_values, label="G'_X(t) (1階微分)", color="green")
plt.plot(t_values, G_X_diff_2_values, label="G''_X(t) (2階微分)", color="red")
plt.title(f"G_X(t), G'_X(t), G''_X(t) の比較 (n={n}, p={p})")
plt.xlabel("t")
plt.ylabel("値")
plt.legend()
plt.grid(True)
plt.show()

微分を重ねるごとにt=1付近での傾きが急になり大きな値を取っています。期待値や分散などの高次統計量に関連しているため、その値が大きくなっていると思います。

2019 Q1(1)

非負の整数を取る離散確率変数の確率母関数の定義式から期待値と分散を求める式を導出しました。

 

コード

非負の離散型観測データから確率母関数を構築し、これの微分と2階微分から期待値と分散を求めます。ここでは、観測データとしてポアソン分布の乱数を用いて、その理論的な母関数と期待値と分散の比較を行います。

# 2019 Q1(1)  2024.9.9

import numpy as np
import matplotlib.pyplot as plt
from scipy.misc import derivative

# パラメータ設定
lambda_val = 3  # ポアソン分布のパラメータ λ
sample_size = 10000  # サンプル数

# 1. ポアソン分布に従う乱数データを生成
samples = np.random.poisson(lambda_val, sample_size)

# 2. P(X=k) の推定(サンプル度数から確率質量関数の推定)
max_k = np.max(samples)
pmf_estimate = np.zeros(max_k + 1)
for k in range(max_k + 1):
    pmf_estimate[k] = np.sum(samples == k) / sample_size

# 3. G_X(t) の推定
def G_X(t):
    return np.sum([pmf_estimate[k] * t**k for k in range(max_k + 1)])

# 4. 理論的な G_X(t) (ポアソン分布の確率母関数)
def G_X_theoretical(t, lam):
    return np.exp(lam * (t - 1))

# 5. G_X(t) のプロット
t_values = np.linspace(0, 1, 100)
G_X_values = [G_X(t) for t in t_values]
G_X_theoretical_values = [G_X_theoretical(t, lambda_val) for t in t_values]

plt.plot(t_values, G_X_values, label="推定された G_X(t)", color="blue")
plt.plot(t_values, G_X_theoretical_values, label="理論的な G_X(t)", linestyle='--', color="red")
plt.title("推定された確率母関数と理論的な G_X(t) の比較")
plt.xlabel("t")
plt.ylabel("G_X(t)")
plt.legend()
plt.show()

# 6. G_X(t) の微分と2階微分
def G_X_diff_1(t):
    return derivative(G_X, t, dx=1e-6)

def G_X_diff_2(t):
    return derivative(G_X_diff_1, t, dx=1e-6)

# 7. t = 1 における期待値と分散の推定
E_X_estimated = G_X_diff_1(1)  # 期待値
Var_X_estimated = G_X_diff_2(1) + E_X_estimated - E_X_estimated**2  # 分散

# 結果の出力
print(f"推定された期待値 E[X]: {E_X_estimated}")
print(f"推定された分散 Var(X): {Var_X_estimated}")

# 真の λ と比較
print(f"真の期待値 E[X]: {lambda_val}")
print(f"真の分散 Var(X): {lambda_val}")
推定された期待値 E[X]: 3.0239000000098493
推定された分散 Var(X): 3.0824841743413582
真の期待値 E[X]: 3
真の分散 Var(X): 3

観測値から推定された確率母関数は理論的なポアソン分布の確率母関数と一致しました。また、推定された確率母関数から計算された期待値と分散も、真の値に非常に近い結果となりました。

2021 Q3(1)

ポアソン分布のモーメント母関数を求めました。

コード

数式を使った計算

# 2021 Q3(1)  2024.8.25

import sympy as sp

# 変数の定義
s, x, lambda_ = sp.symbols('s x lambda_', real=True, positive=True)

# ポアソン分布の確率質量関数 (PMF)
poisson_pmf = (lambda_**x * sp.exp(-lambda_)) / sp.factorial(x)

# モーメント母関数 M_X(s) の定義
M_X = sp.summation(sp.exp(s*x) * poisson_pmf, (x, 0, sp.oo))

# 結果を簡略化
M_X_simplified = sp.simplify(M_X)

# 結果を表示
M_X_simplified

無限級数がe^xの形に変換されないようです。

exp(s) を t に置き換えて、最後に戻してみます。

# 2021 Q3(1)  2024.8.25

import sympy as sp

# 変数の定義
s, x, lambda_, t = sp.symbols('s x lambda_ t', real=True, positive=True)

# exp(s) を t に置き換え
summand = (lambda_ * t)**x / sp.factorial(x)

# モーメント母関数 M_X(s) の定義
M_X = sp.exp(-lambda_) * sp.summation(summand, (x, 0, sp.oo))

# 簡略化
M_X_simplified = sp.simplify(M_X)

# 最後に t を exp(s) に戻す
M_X_final = M_X_simplified.subs(t, sp.exp(s))

# 結果を表示
M_X_final

手計算と同じ形になりました。

モーメント母関数を使って期待値と分散を求めます。

import sympy as sp

# 変数の定義
s, lambda_ = sp.symbols('s lambda_', real=True, positive=True)

# モーメント母関数 M_X(s) の定義
M_X = sp.exp(lambda_ * (sp.exp(s) - 1))

# 1次モーメント(期待値)の計算
M_X_prime = sp.diff(M_X, s)
expectation = M_X_prime.subs(s, 0)

# 2次モーメントの計算
M_X_double_prime = sp.diff(M_X_prime, s)
second_moment = M_X_double_prime.subs(s, 0)

# 分散の計算
variance = second_moment - expectation**2

# 結果を表示
display(expectation, variance)

2021 Q2(4)

事前分布と尤度から事後確率が最大となるパラメータの推定値を求めました。

コード

数式を使った計算

# 2021 Q2(4)  2024.8.24

import numpy as np
from scipy.special import comb

# 事前分布 P(N_A)
def prior(NA):
    return NA + 1

# 尤度関数 P(X = 4 | N_A)
def likelihood(NA):
    return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)

# 事後分布 P(N_A | X = 4) (正規化定数は省略)
def posterior(NA):
    return prior(NA) * likelihood(NA)

# N_A の範囲
NA_values = np.arange(4, 90)

# 事後分布の計算
posterior_values = [posterior(NA) for NA in NA_values]

# 最大値を取る N_A (事後モード) を探索
NA_mode = NA_values[np.argmax(posterior_values)]

NA_mode
30

プロット

# 2021 Q2(4)  2024.8.24

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb

# 事前分布 P(N_A)
def prior(NA):
    return NA + 1

# 正規化定数
C = 1 / 5151

# 尤度関数 P(X = 4 | N_A)
def likelihood(NA):
    return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)

# 事後分布 P(N_A | X = 4)
def posterior(NA):
    return prior(NA) * likelihood(NA)

# N_A の範囲を0から100まで(事前分布用)
NA_values_full = np.arange(0, 101)

# 事前分布を計算(0から100まで)
prior_values_full = [C * prior(NA) for NA in NA_values_full]

# N_A の範囲を4から89まで(事後分布用)
NA_values = np.arange(4, 90)

# 事後分布の計算
posterior_values = [posterior(NA) for NA in NA_values]

# 事後分布の正規化
posterior_sum = sum(posterior_values)
posterior_values_normalized = [value / posterior_sum for value in posterior_values]

# 事前分布が存在しない場合の事後分布(尤度のみを正規化)
likelihood_values = [likelihood(NA) for NA in NA_values]
likelihood_sum = sum(likelihood_values)
likelihood_values_normalized = [value / likelihood_sum for value in likelihood_values]

# 3つの分布を重ねて表示
plt.figure(figsize=(10, 6))

# 事前分布のプロット(0から100まで)
plt.plot(NA_values_full, prior_values_full, 'g-', label=r'事前分布 $P(N_A)$', markersize=5)

# 事後分布のプロット(4から89まで)
plt.plot(NA_values, posterior_values_normalized, 'bo-', label=r'事後分布 $P(N_A | X = 4)$', markersize=5)

# 事前分布が存在しない場合の事後分布(尤度のみ)
plt.plot(NA_values, likelihood_values_normalized, 'r-', label=r'事前分布なし $P(N_A | X = 4)$', markersize=5)

# 事後モードのプロット
NA_mode = NA_values[np.argmax(posterior_values_normalized)]
plt.axvline(NA_mode, color='blue', linestyle='--', label=f'事後モード: {NA_mode}')

# 事前分布なしの場合の最尤推定値のプロット
NA_mode_likelihood = NA_values[np.argmax(likelihood_values_normalized)]
plt.axvline(NA_mode_likelihood, color='red', linestyle=':', label=f'最尤推定値 (事前分布なし): {NA_mode_likelihood}')

# グラフの設定
plt.xlabel(r'$N_A$')
plt.ylabel(r'確率')
plt.title(r'事前分布ありとなしの比較')
plt.grid(True)
plt.legend()
plt.show()