105 lines
3.2 KiB
Python
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()
|
|
|
|
|