ホーム » 分布 (ページ 9)
「分布」カテゴリーアーカイブ
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()
2021 Q2(2)
超幾何分布の当たりの数の推定値を尤度比を使って求めました。
コード
シミュレーションによる計算
# 2021 Q2(2) 2024.8.22
import numpy as np
from scipy.special import comb
# 尤度関数 L(N_A) を定義
def L(NA):
return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)
# L(N_A + 1) / L(N_A) を計算し、条件を満たす最小の N_A を探索
# max(0, N_A - 85) ≤ 4 ≤ min(15, N_A) の式に基づき、取り出した豆Aが4粒の場合の N_A の範囲を設定 (4 ≤ N_A ≤ 89)
NA_values = np.arange(4, 90)
ratios = [(L(NA + 1) / L(NA)) for NA in NA_values]
NA_optimal = NA_values[np.where(np.array(ratios) < 1)[0][0]]
print(f"L(N_A + 1) / L(N_A) < 1 となる最小の N_A は {NA_optimal} です。")
L(N_A + 1) / L(N_A) < 1 となる最小の N_A は 26 です。
プロット
# 2021 Q2(2) 2024.8.22
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb
# 尤度関数 L(N_A) を定義
def L(NA):
return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)
# N_A の範囲を設定
NA_values = np.arange(4, 90)
ratios = [(L(NA + 1) / L(NA)) for NA in NA_values]
# グラフの描画
plt.figure(figsize=(10, 6))
plt.plot(NA_values, ratios, 'bo-', label=r'$\frac{L(N_A + 1)}{L(N_A)}$', markersize=8)
plt.axhline(y=1, color='red', linestyle='--', label=r'$1$')
plt.xlabel(r'$N_A$')
plt.ylabel(r'$\frac{L(N_A + 1)}{L(N_A)}$')
plt.title(r'$N_A$ の尤度比 $\frac{L(N_A + 1)}{L(N_A)}$')
plt.legend()
plt.grid(True)
plt.show()
プロット(NA=26付近をズーム)
# 2021 Q2(2) 2024.8.22
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb
# 尤度関数 L(N_A) を定義
def L(NA):
return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)
# N_A の範囲を設定
NA_values = np.arange(4, 90)
ratios = [(L(NA + 1) / L(NA)) for NA in NA_values]
# 26付近のズームしたグラフを描画
plt.figure(figsize=(10, 6))
plt.plot(NA_values, ratios, 'bo-', label=r'$\frac{L(N_A + 1)}{L(N_A)}$', markersize=8)
plt.axhline(y=1, color='red', linestyle='--', label=r'$1$')
plt.xlabel(r'$N_A$')
plt.ylabel(r'$\frac{L(N_A + 1)}{L(N_A)}$')
plt.title(r'$N_A$ の尤度比 $\frac{L(N_A + 1)}{L(N_A)}$ (25 < $N_A$ < 30)')
plt.xlim(25, 30) # N_A = 26 付近をズーム
plt.ylim(0.95, 1.05) # y軸もズームして見やすく
plt.legend()
plt.grid(True)
plt.show()
2021 Q2(1)
超幾何分布の問題をやりました。
コード
シミュレーションによる計算
# 2021 Q2(1) 2024.8.21
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import hypergeom
# パラメータの設定
M = 100 # 全体の豆の数
N_A = 30 # 豆Aの数
n = 15 # 抽出する豆の数
x_values = np.arange(0, n+1) # 可能な豆Aの数
# 理論的な超幾何分布のPMFを計算
rv = hypergeom(M, N_A, n)
pmf_theoretical = rv.pmf(x_values)
# 数値シミュレーションの設定
n_simulations = 10000 # シミュレーション回数
simulated_counts = []
# シミュレーションの実行
for _ in range(n_simulations):
# 袋の中の豆を表すリスト(1が豆A、0が豆B)
bag = np.array([1]*N_A + [0]*(M - N_A))
# 無作為に15個抽出
sample = np.random.choice(bag, size=n, replace=False)
# 抽出した中の豆Aの数をカウント
count_A = np.sum(sample)
simulated_counts.append(count_A)
# シミュレーションから得られたPMFを計算
pmf_simulated, bins = np.histogram(simulated_counts, bins=np.arange(-0.5, n+1.5, 1), density=True)
# グラフの描画
plt.figure(figsize=(10, 6))
# 理論的なPMFの描画
plt.plot(x_values, pmf_theoretical, 'bo-', label='理論的PMF', markersize=8)
# シミュレーション結果をヒストグラムとして描画
plt.hist(simulated_counts, bins=np.arange(-0.5, n+1.5, 1), density=True, alpha=0.5, color='red', label='シミュレーション結果')
# グラフの設定
plt.xlabel('豆Aの数')
plt.ylabel('確率')
plt.title('超幾何分布のPMF: 理論とシミュレーションの比較')
plt.legend()
plt.grid(True)
plt.show()
2021 Q1(4)
独立ではない2つの確率変数の積の期待値を求めました。
コード
数式を使った計算
# 2021 Q1(4) 2024.8.20
import sympy as sp
# シンボリック変数の定義
x, y = sp.symbols('x y')
# h(x) の導出
h_x = sp.integrate(sp.exp(-x), (x, 0, x))
# XY の期待値の計算
# h(x) = 1 - exp(-x) を使って E[X * h(X)] を計算する
integral_part1 = sp.integrate(x * h_x * sp.exp(-x), (x, 0, sp.oo))
E_XY_simplified = sp.simplify(integral_part1)
# 結果の表示
display(sp.Eq(sp.Symbol('h(x)'), h_x))
display(sp.Eq(sp.Symbol('E[XY]'), E_XY_simplified))
指数分布に従う乱数Xを生成し、Y=h(X)Yが一様分布に従うか確認
import numpy as np
import matplotlib.pyplot as plt
# シミュレーションの設定
num_samples = 100000 # サンプル数
# 指数分布に従う乱数 X を生成
X_samples = np.random.exponential(scale=1.0, size=num_samples)
# 関数 Y = h(X) = 1 - exp(-X) を適用して Y を計算
Y_samples = 1 - np.exp(-X_samples)
# ヒストグラムのプロット
plt.figure(figsize=(8, 5))
plt.hist(Y_samples, bins=50, density=True, alpha=0.6, color='g', label='シミュレーションされた Y=h(X)')
plt.xlabel('y')
plt.ylabel('密度')
plt.title('Y = h(X) の分布 (シミュレーション結果)')
plt.legend()
plt.grid(True)
plt.show()
シミュレーションによるE[XY]の計算
import numpy as np
# シミュレーションの設定
num_samples = 100000 # サンプル数
# 指数分布に従う乱数 X を生成
X_samples = np.random.exponential(scale=1.0, size=num_samples)
# 関数 Y = h(X) = 1 - exp(-X) を適用して Y を計算
Y_samples = 1 - np.exp(-X_samples)
# XY の期待値を計算
XY_samples = X_samples * Y_samples
E_XY_simulation = np.mean(XY_samples)
# 結果の表示
print(f"シミュレーションによる E[XY] = {E_XY_simulation}")
print(f"理論値 E[XY] = 3/4 = {3/4}")
シミュレーションによる E[XY] = 0.7473462073557277
理論値 E[XY] = 3/4 = 0.75
2021 Q1(3)
変数変換を用いて二つの分布の和の確率密度関数を求めました。
コード
数式を使った計算
# 2024 Q1(3) 2024.8.19
import sympy as sp
# シンボリック変数の定義
x, z = sp.symbols('x z')
# 確率密度関数の定義
f_X = sp.exp(-x) # f_X(x) = e^(-x)
f_Y = sp.Piecewise((1, (z - x >= 0) & (z - x <= 1)), (0, True)) # f_Y(z - x) for 0 < z - x < 1
# 一般的な積分の設定
f_Z_integral = sp.integrate(f_X * f_Y, (x, 0, z))
# 結果の簡略化
f_Z_general = sp.simplify(f_Z_integral)
# 結果の表示
display(f_Z_general)
簡単のため、zの範囲を指定して再度計算
# 2024 Q1(3) 2024.8.19
import sympy as sp
# シンボリック変数の定義
x, z = sp.symbols('x z')
# 確率密度関数の定義
f_X = sp.exp(-x) # f_X(x) = e^(-x)
f_Y = 1 # f_Y(y) = 1 (0 < y < 1)
# 各範囲での計算
# 1. z <= 0 の場合
f_Z_1 = 0 # z <= 0 の場合は f_Z(z) = 0
# 2. 0 < z <= 1 の場合
f_Z_2_integral = sp.integrate(f_X * f_Y, (x, 0, z))
f_Z_2 = sp.simplify(f_Z_2_integral)
# 3. z > 1 の場合
f_Z_3_integral = sp.integrate(f_X * f_Y, (x, z-1, z))
f_Z_3 = sp.simplify(f_Z_3_integral)
# 結果の表示
print(f"f_Z(z) for z <= 0:")
display(f_Z_1)
print(f"f_Z(z) for 0 < z <= 1:")
display(f_Z_2)
print(f"f_Z(z) for z > 1:")
display(f_Z_3)
プロット
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import quad
# 確率密度関数 f_X(x) と f_Y(y)
def f_X(x):
return np.exp(-x) if x > 0 else 0
def f_Y(y):
return 1 if 0 < y < 1 else 0
# Z = X + Y の確率密度関数 f_Z(z) の計算
def f_Z(z):
integrand = lambda x: f_X(x) * f_Y(z - x)
return quad(integrand, max(0, z-1), z)[0] #積分範囲を限定する場合
#return quad(integrand, 0, z, epsabs=1e-8, epsrel=1e-8)[0] #積分範囲を広くする場合
# z の範囲を設定し、f_Z(z) を計算
z_values = np.linspace(0, 5, 1000) # 増加させたサンプル数
f_Z_values = np.array([f_Z(z) for z in z_values])
# グラフの描画
plt.plot(z_values, f_Z_values, label='f_Z(z) = X + Y')
plt.xlabel('z')
plt.ylabel('確率密度')
plt.title('X + Y の確率密度関数')
plt.legend()
plt.grid(True)
plt.show()
2021 Q1(1)(2)
指数分布と一様分布の期待値と、それらが独立な場合の積の期待値を求めました。
コード
数式を使った計算
# 2021 Q1(1)(2) 2024.8.18
import numpy as np
from scipy.integrate import quad
# Xの期待値の計算
def fx(x):
return x * np.exp(-x)
E_X, _ = quad(fx, 0, np.inf)
# Yの期待値の計算
def fy(y):
return y
E_Y, _ = quad(fy, 0, 1)
# XYの期待値の計算(独立の場合)
E_XY = E_X * E_Y
print(f"E[X] = {E_X}")
print(f"E[Y] = {E_Y}")
print(f"E[XY] (独立の場合) = {E_XY}")
E[X] = 0.9999999999999998
E[Y] = 0.5
E[XY] (独立の場合) = 0.4999999999999999
シミュレーションによる計算
# 2021 Q1(1)(2) 2024.8.18
import numpy as np
# シミュレーションの設定
num_samples = 1000000 # サンプル数
# Xの乱数生成(指数分布)
X_samples = np.random.exponential(scale=1.0, size=num_samples)
# Yの乱数生成(一様分布)
Y_samples = np.random.uniform(0, 1, size=num_samples)
# (1) XとYの期待値の計算
E_X_simulation = np.mean(X_samples)
E_Y_simulation = np.mean(Y_samples)
# (2) XYの期待値の計算(独立な場合)
E_XY_simulation = np.mean(X_samples * Y_samples)
print(f"E[X] = {E_X_simulation}")
print(f"E[Y] = {E_Y_simulation}")
print(f"E[XY] = {E_XY_simulation}")
E[X] = 1.0001064255963075
E[Y] = 0.4998284579940602
E[XY] = 0.4998038319582688
2022 Q5(1)
正規分布の差の分布を求める問題をやりました。
コード
シミュレーションによる計算
# 2022 Q4(5) 2024.8.13
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
# パラメータの設定
mu_i = 5.0 # 平均値 mu_i
theta = 3.0 # シフトパラメータ θ
sigma = 1.0 # 標準偏差 σ
n = 1000 # サンプル数
# X_i と Y_i のサンプル生成
X_i = np.random.normal(mu_i, sigma, n)
Y_i = np.random.normal(mu_i + theta, sigma, n)
# D_i の計算
D_i = Y_i - X_i
# シミュレーション結果の平均と分散を計算
mean_simulation = np.mean(D_i)
variance_simulation = np.var(D_i)
# 理論上の平均と分散
mean_theoretical = theta
variance_theoretical = 2 * sigma**2
# 結果の表示
print(f"シミュレーション結果: 平均 = {mean_simulation}, 分散 = {variance_simulation}")
print(f"理論値: 平均 = {mean_theoretical}, 分散 = {variance_theoretical}")
# サンプルのヒストグラムを作成
plt.hist(D_i, bins=30, density=True, alpha=0.6, color='g', label='サンプルデータ')
# 理論上の分布を重ねる
x = np.linspace(min(D_i), max(D_i), 1000)
plt.plot(x, stats.norm.pdf(x, mean_theoretical, np.sqrt(variance_theoretical)), 'r', label='理論的な確率密度関数')
plt.title("差 $D_i = Y_i - X_i$ の分布")
plt.xlabel("$D_i$")
plt.ylabel("密度")
plt.legend()
plt.show()
シミュレーション結果: 平均 = 2.975536685240219, 分散 = 2.005575154363111
理論値: 平均 = 3.0, 分散 = 2.0
2022 Q4(4)
対数で変数変換した場合の分布を求めました。
コード
数式を使った計算
# 2022 Q4(4) 2024.8.11
import sympy as sp
# シンボリック変数の定義
t, gamma = sp.symbols('t gamma', positive=True)
x = sp.symbols('x', real=True, positive=True)
# 累積分布関数 F_X(x) の定義
F_X = sp.Piecewise((0, x <= 1), (1 - x**(-1/gamma), x > 1))
# F_T(t) の計算
F_T = F_X.subs(x, sp.exp(gamma * t))
# f_T(t) の計算(F_T(t) を t で微分)
f_T = sp.diff(F_T, t)
# 結果の表示
display(F_T, f_T)
# LaTeXで表示できなときは、こちら
#sp.pprint(F_T, use_unicode=True)
#sp.pprint(f_T, use_unicode=True)
シミュレーションによる計算
# 2022 Q4(4) 2024.8.11
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
# パラメータ設定
gamma = 1.0 # γの値(例えば1)
num_samples = 10000 # サンプルサイズ
# 累積分布関数 F(x) に従う乱数を生成
X = (np.random.uniform(size=num_samples))**(-gamma)
# T = (1/γ) * log(X) の計算
T = (1/gamma) * np.log(X)
# ヒストグラムをプロット
plt.hist(T, bins=50, density=True, alpha=0.6, color='g', label="シミュレーションによる T")
# 理論的な指数分布の密度関数をプロット
x = np.linspace(0, 8, 100)
pdf = stats.expon.pdf(x) # 指数分布(λ=1)の密度関数
plt.plot(x, pdf, 'r-', lw=2, label='指数分布の理論値')
# グラフの設定(日本語でキャプションとラベルを設定)
plt.xlabel('Tの値')
plt.ylabel('確率密度')
plt.title(r'$T = \frac{1}{\gamma} \log X$ のヒストグラムと指数分布の比較')
plt.legend()
plt.show()
2022 Q3(5)
モーメント法によりガンマポアソン分布のパラメータの推定量を求めました。
コード
数式を使った計算
# 2022 Q3(5) 2024.8.6
from sympy import init_printing
from sympy import symbols, Eq, solve
# これでTexの表示ができる
init_printing()
# 変数の定義
r, p, X_bar, S_squared = symbols('r p X_bar S_squared')
alpha, beta = symbols('alpha beta')
# モーメント法の方程式を定義
# 期待値 E[X] にサンプル平均を一致させる
eq1_correct = Eq(X_bar, alpha / beta)
# 分散 V[X] にサンプル分散を一致させる
eq2_correct = Eq(S_squared, alpha / beta**2 + alpha / beta)
# 方程式を解いて α と β を求める
solutions_correct = solve((eq1_correct, eq2_correct), (alpha, beta))
solutions_correct
シミュレーションによる計算
# 2022 Q3(5) 2024.8.6
import numpy as np
from scipy.stats import nbinom
# 1. パラメータの設定
alpha_true = 3.0
beta_true = 2.0
# 2. 負の二項分布のパラメータ計算
r = alpha_true
p = beta_true / (beta_true + 1)
# 3. 負の二項分布から乱数を生成
sample_size = 10000
nbinom_samples = nbinom.rvs(r, p, size=sample_size)
# 4. サンプル統計量の計算
X_bar = np.mean(nbinom_samples)
S_squared = np.var(nbinom_samples, ddof=1)
# 5. モーメント法によるパラメータ推定
alpha_estimated = X_bar**2 / (S_squared - X_bar)
beta_estimated = X_bar / (S_squared - X_bar)
# 6. 推定結果の表示
print(f"推定された α: {alpha_estimated}")
print(f"推定された β: {beta_estimated}")
print(f"理論値 α: {alpha_true}")
print(f"理論値 β: {beta_true}")
推定された α: 2.93536458612626
推定された β: 1.95157541794180
理論値 α: 3.0
理論値 β: 2.0
アルゴリズム
シミュレーションによる計算
パラメータの設定:
- 真のパラメータ と を設定する。
負の二項分布のパラメータ計算:
- パラメータ
- パラメータ
負の二項分布から乱数を生成:
- サンプルサイズ を設定し、負の二項分布から乱数を生成する。
サンプル統計量の計算:
- サンプル平均 と分散 を計算する。
モーメント法によるパラメータ推定:
- 推定された を で計算する。
- 推定された を で計算する。
推定結果の表示:
- 推定された と を表示する。
- 真の と を表示する。
2022 Q3(4)
条件付き期待値の公式と条件付き分散の公式を使ってガンマポアソン分布の期待値と分散を求めました。
コード
数式を使った計算
# 2022 Q3(4) 2024.8.7
import sympy as sp
# 定義
k, lambda_var = sp.symbols('k lambda')
alpha, beta = sp.symbols('alpha beta', positive=True)
# ポアソン分布の確率質量関数
poisson_pmf = (lambda_var**k * sp.exp(-lambda_var)) / sp.factorial(k)
# ガンマ分布の確率密度関数
gamma_pdf = (beta**alpha / sp.gamma(alpha)) * lambda_var**(alpha - 1) * sp.exp(-beta * lambda_var)
# 周辺分布の計算
marginal_distribution = sp.integrate(poisson_pmf * gamma_pdf, (lambda_var, 0, sp.oo)).simplify()
# 期待値 E[X] の計算
expected_value = sp.summation(k * marginal_distribution, (k, 0, sp.oo)).simplify()
# 分散 V[X] の計算
expected_value_of_square = sp.summation(k**2 * marginal_distribution, (k, 0, sp.oo)).simplify()
variance = (expected_value_of_square - expected_value**2).simplify()
# 結果を表示
results = {
"期待値 E[X]": expected_value,
"分散 V[X]": variance
}
results
{'期待値 E[X]': alpha/beta, '分散 V[X]': alpha*(beta + 1)/beta**2}
シミュレーションによる計算
import numpy as np
# パラメータの設定
alpha = 3.0
beta = 2.0
sample_size = 10000
# ガンマ分布から λ を生成
lambda_samples = np.random.gamma(alpha, 1/beta, sample_size)
# 生成された λ を使ってポアソン分布から X を生成
poisson_samples = [np.random.poisson(lam) for lam in lambda_samples]
# サンプルの期待値と分散を計算
sample_mean = np.mean(poisson_samples)
sample_variance = np.var(poisson_samples)
# 理論値を計算
theoretical_mean = alpha / beta
theoretical_variance = alpha * (beta + 1) / beta**2
# 結果を表示
results_with_caption = {
"シミュレーションによる期待値": sample_mean,
"理論値による期待値": theoretical_mean,
"シミュレーションによる分散": sample_variance,
"理論値による分散": theoretical_variance
}
results_with_caption
{'シミュレーションによる期待値': 1.5027,
'理論値による期待値': 1.5,
'シミュレーションによる分散': 2.31159271,
'理論値による分散': 2.25}