Files
Baysian_Canonical_Identific…/demo.py
T
2025-10-20 09:53:02 +08:00

105 lines
3.2 KiB
Python

## 实现一下重要抽样
import numpy as np
import matplotlib.pyplot as plt
import scipy as stats
import seaborn as sns
np.random.seed(42)
def baysian_linear_regression_inportance_sampling():
"""
使用贝叶斯线性回归方法进行重要抽样
本例需要估计一个简单的线性回归模型的后验分布
y = β0 + β1*x + ε, ε ~ N(0, σ²)
= [1 x] * [β0 β1]' + ε
"""
# 1. 定义关键数据
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
y = np.array([2.1, 3.9, 6.2, 8.1, 9.8, 12.3, 13.9, 16.2, 17.8, 20.1])
n = len(x)
print(f"数据点数量:{n}")
print(f"x: {x}")
print(f"y: {y}")
# 2. 定义先验分布
# β0 ~ N(0, 10)
beta0_prior_mean = 0
beta0_prior_var = 10
# β1 ~ N(1, 5)
beta1_prior_mean = 1
beta1_prior_var = 5
# σ² ~ Inverse-Gamma(2, 1)
sigma2_prior_a = 2
sigma2_prior_b = 1
# 3. 定义重要抽样分布
# 使用最小二乘进行估计
X = np.column_stack([np.ones(n), x])
beta_estimate = np.linalg.inv(X.T @ X) @ X.T @ y
y_pred = X @ beta_estimate
residuals = y - y_pred
RSS = residuals.T @ residuals
sigma2_estimate = RSS / (n - 2)
print(f"最小二乘结果:β0 = {beta_estimate[0]}, β1 = {beta_estimate[1]}, σ² = {sigma2_estimate}")
print(f"残差平方和 RSS = {RSS}")
# 4. 定义联合后验分布(未归一化)
def unnormalized_log_posterior(param):
"""
计算后验概率密度的未归一化值
param: [β0, β1, log_sigma2)]
"""
beta0, beta1, log_sigma2 = param
sigma2 = np.exp(log_sigma2)
# 计算似然函数值
y_pred = beta0 + beta1 * x
residuals = y - y_pred
log_likelihood = -0.5 * n * np.log(2 * np.pi * sigma2) * -0.5 * np.sum(residuals**2) / sigma2
# 计算先验概率
log_prior_beta0 = stats.norm.logpdf(beta0, loc = beta0_prior_mean, scale = np.sqrt(beta0_prior_var))
log_prior_beta1 = stats.norm.logpdf(beta1, loc = beta1_prior_mean, scale = np.sqrt(beta1_prior_var))
log_prior_sigma2 = stats.invgamma.logpdf(sigma2, a = sigma2_prior_a, scale = sigma2_prior_b) + log_sigma2
return log_likelihood + log_prior_beta0 + log_prior_beta1 + log_prior_sigma2
# 5. 定义重要抽样分布
proposal_mean = np.array([beta_estimate[0], beta_estimate[1], np.log(sigma2_estimate)])
proposal_cov = np.diag([1.0, 1.0, 1.0])
def log_proposal_density(param):
return stats.multivariable_normal.logpdf(param, mean = proposal_mean, cov = proposal_cov)
# 6. 进行重要抽样
num_samples = 10000
samples = np.zeros((num_samples, 3))
weights = np.zeros(num_samples)
log_weights = np.zeros(num_samples)
for i in range(num_samples):
samples[i] = np.random.multivariate_normal(proposal_mean, proposal_cov)
unnormalized_log_posterior = unnormalized_log_posterior(samples[i])
log_proposal = log_proposal_density(samples[i])
log_weights[i] = unnormalized_log_posterior - log_proposal
weights = np.exp(log_weights)
if __name__ == "__main__":
baysian_linear_regression_inportance_sampling()