towardsdatascience.com/bayesian-linear-regression-a-complete-beginners-guide-3a49bb252fdc?source=collection_archive---------1-----------------------#2024-09-14
使用
STAN
创建贝叶斯回归模型的工作流程和代码展示
https://medium.com/@samvardhanvishnoi2026?source=post_page---byline--3a49bb252fdc--------------------------------
https://towardsdatascience.com/?source=post_page---byline--3a49bb252fdc--------------------------------
Samvardhan Vishnoi
·发布于
Towards Data Science
·阅读时间 9 分钟·2024 年 9 月 14 日
–
注意:查看我之前的文章,深入探讨贝叶斯建模可能为何是你的任务的合适选择。
本教程将重点讲解如何通过工作流程和代码展示,使用概率编程语言
STAN
构建贝叶斯回归模型。STAN 广泛应用,并能与你选择的编程语言(如 R、Python、shell、MATLAB、Julia、Stata 等)接口。请参阅安装指南和文档。
本教程将使用 Pystan,因为我用 Python 编程。即使你使用其他语言,我讨论的贝叶斯实践和 STAN 语言语法也不会有很大不同。
对于更注重实践的读者,以下是本教程的笔记本链接,来自我在西北大学(2024 年 4 月)举办的贝叶斯建模工作坊的一部分。
让我们开始吧!
贝叶斯线性回归
让我们学习如何用贝叶斯方法构建一个简单的线性回归模型,这是任何统计学家日常使用的基础模型。假设有一个因变量 Y 和协变量 X,我提出以下简单模型:
Y = α + β * X + ε
其中ε是截距,β是斜率,ε是一些随机误差。假设:
ε ~ 正态分布(0, σ)
我们可以证明 Y ~ 正态分布(α + β * X, σ)
我们将学习如何在 STAN 中编写这个模型形式的代码。
生成数据
首先,让我们生成一些虚拟数据。
# 模型参数
alpha = 4.0 # 截距
beta = 0.5 # 斜率
sigma = 1.0 # 误差尺度
# 生成模拟数据
x = 8 * np.random.rand(100)
y = alpha + beta * x
y = np.random.normal(y, scale=sigma) # 噪声
# 可视化生成的数据
plt.scatter(x, y, alpha=0.8)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/6164a06655df22cfc765b4dc8df23e5e.png
线性回归生成的数据(图片来自作者代码)
模型字符串
现在我们有了一些数据来建模,让我们深入了解如何构建数据并将其与建模指令一起传递给 STAN。这是通过 model 字符串完成的,它通常包含 4 个(偶尔更多)块——data、parameters、model 和 generated quantities。让我们详细讨论这些块的每一个。
DATA 块
data { // 将数据输入到 STAN 中
int尽管先前的知识不必与最终解决方案完全一致,但它们必须允许我们从中抽取样本。
在我们的示例中,我们使用均值为 0、方差各异的正态先验,这取决于我们对提供均值的确信程度:α的方差为 10(非常不确定),β的方差为 1(较为确定)。在这里,我表达了普遍的看法,即虽然α可以取广泛的不同值,但斜率通常会更加受限,并且不会有很大的波动。
因此,在上述示例中,α的先验比β更“弱”。随着模型逐渐变得复杂,采样解决方案空间扩展,提供信念变得更加重要。否则,如果没有强烈的直觉,一个好方法是向模型提供较少的信息性假设,即使用较弱的信息性先验,并保持对数据的灵活性。
y 的形式,你可能已经识别出,是标准的线性回归方程。
生成的数量
最后,我们得到了“生成的数量”的代码块。在这里,我们告知 STAN 我们希望计算并作为输出接收哪些量。
generated quantities { //get quantities of interest from fitted model
vector[N] yhat;
vector[N] log_lik;
for (n in 1:N){
yhat[n] = normal_rng(alpha + x[n] * beta, sigma);
//generate samples from model
log_lik[n] = normal_lpdf( y[n] | alpha + x[n] * beta, sigma);
//probability of data given the model and parameters
}
}
注意:STAN 支持将向量直接传入方程中,或者作为每个元素 n 的迭代 1:N。在实践中,我发现这种支持会随着 STAN 不同版本而变化,因此,如果向量化版本无法编译,最好尝试使用迭代声明。
在上面的例子中——
yhat: 根据拟合参数值生成 y 的样本。
log_lik: 生成数据在给定模型和拟合参数值情况下的概率。
这些量的用途将在我们讨论模型评估时更加明了。
将所有内容整合在一起
总体而言,我们现在已完全指定了我们的第一个简单贝叶斯回归模型:
model = """
data { //input the data to STAN
int<lower=0> N;
vector[N] x;
vector[N] y;
}
parameters {
real alpha;
real beta;
real<lower=0> sigma;
}model {
alpha ~ normal(0,10);
beta ~ normal(0,1);
y ~ normal(alpha + beta * x, sigma);
}generated quantities {
vector[N] yhat;
vector[N] log_lik;
for (n in 1:N){ yhat[n] = normal_rng(alpha + x[n] * beta, sigma);
log_lik[n] = normal_lpdf(y[n] | alpha + x[n] * beta, sigma); }
}
"""
剩下的工作就是编译模型并运行采样。
#STAN takes data as a dict
data = {'N': len(x), 'x': x, 'y': y}
#parameters for STAN fitting
chains = 2
samples = 1000
warmup = 10
# set seed
# Compile the model
posterior = stan.build(model, data=data, random_seed = 42)
# Train the model and generate samples
fit = posterior.sample(num_chains=chains, num_samples=samples)The .sample() method parameters control the Hamiltonian Monte Carlo (HMC) sampling process, where —
num_chains:
是我们重复采样过程的次数。
num_samples:
是每条链中要抽取的样本数。
warmup:
是我们丢弃的初始样本数量(因为在达到解空间的一般范围之前需要一些时间)。
了解这些参数的正确值取决于我们模型的复杂程度及可用资源。
更大的样本规模当然是理想的,但对于一个不稳定的模型,它们只是浪费时间和计算资源。从经验来看,我曾经需要等待一周才能完成的大型数据模型,最终发现模型并没有收敛。重要的是在运行完整的采样之前,先慢慢开始并对模型进行合理性检查。
模型评估
生成的数量用于
评估拟合的质量,即收敛性,
预测
模型比较
收敛性
评估模型的第一步,在贝叶斯框架下,是可视化的。我们观察哈密顿蒙特卡洛(HMC)采样过程的采样结果。

简单来说,STAN 会迭代地抽取参数值的样本并对其进行评估(HMC 做的工作要复杂得多,但那超出了我们当前的范围)。对于一个良好的拟合,样本抽取必须收敛到某个共同的区域,这个区域理想情况下应该是全局最优解。
上图展示了我们模型在两个独立链(红色和蓝色)上的采样结果。
在左侧,我们绘制了拟合的参数值的整体分布,即后验分布。如果模型及其参数设定得当,我们期望看到一个正态分布。(为什么会有这样的分布?好吧,正态分布意味着对于参数存在一个最佳拟合值的特定范围,这支持了我们选择的模型形式)。此外,如果模型收敛到最优解,我们还应当期望不同链之间有显著的重叠。
在右侧,我们绘制了每次迭代中实际抽取的样本(仅仅是为了额外确认)。在这里,我们希望看到不仅是一个狭窄的范围,同时也希望看到抽取样本之间有很大的重叠。
并非所有评估指标都是可视化的。Gelman 等人[1]还提出了 Rhat 诊断,它本质上是一个数学度量,用于评估不同链之间样本的相似性。通过 Rhat,可以定义一个临界值,超过该值时,两个链被认为过于不同,无法收敛。然而,由于过程的迭代性质和变化的预热期,临界值很难确定。
因此,视觉比较是一个至关重要的组成部分,无论是诊断测试与否。
你可能会有一个频率主义的想法:“那么,如果我们只有链和分布,实际的参数值是什么呢?”这正是关键所在。贝叶斯的公式只处理分布,而非带有难以解释的测试统计量的点估计。
话虽如此,后验分布仍然可以通过可信区间来总结,比如高密度区间(HDI),它包括所有 x% 的最高概率密度点。

对比贝叶斯可信区间和频率主义置信区间是很重要的。
可信区间为参数的可能值提供了一个概率分布,即给定数据时,参数在某个区间内取每个值的概率。
置信区间将参数值视为固定的,而是估计反复随机抽样数据时,结果会有多大可能性匹配。
因此,贝叶斯方法允许参数值是流动的,并且直接根据数据的表面意义来进行推断,而频率主义方法则要求存在唯一的真实参数值……如果我们能接触到所有历史数据的话。
呼,稍微消化一下,再读一遍,直到完全理解。
使用可信区间的另一个重要含义,换句话说,允许参数是可变的,就是我们所做的预测能够捕捉到这种不确定性,并且具有透明性,有一定的 HDI 百分比指示最佳拟合线。

模型比较
在贝叶斯框架中,渡边-赤池信息量度(WAIC)得分是进行模型比较的广泛接受的选择。WAIC 得分的简单解释是,它估计模型的似然,同时对模型参数的数量进行正则化。简单来说,它可以帮助解决过拟合问题。这也是贝叶斯框架的一个主要优势——并不一定需要持有一个模型验证数据集。因此,当数据稀缺时,贝叶斯建模提供了一个重要的优势。
WAIC 得分是一个比较性指标,即只有在跨不同模型进行比较时,它才具有意义,这些模型试图解释相同的基础数据。因此,在实践中,只要 WAIC 增加,就可以继续增加模型的复杂性。如果在这个增加复杂性的过程中,WAIC 开始下降,那么可以停止——任何更多的复杂性在描述基础数据分布时将不会提供信息上的优势。
结论
总结来说,STAN 模型块只是一个字符串。它向 STAN 解释你将提供给它什么(模型)、需要找出什么(参数)、你认为发生了什么(模型),以及它应该返回什么(生成的量)。
当开启时,STAN 简单地转动机器并给出其输出。
实际的挑战在于定义一个适当的模型(参考先验分布),合理构建数据,准确地向 STAN 提出需求,并评估其输出的有效性。
一旦我们掌握了这一部分,就可以进一步探讨 STAN 的核心优势。在这里,指定越来越复杂的模型变成了一项简单的语法任务。事实上,在我们的下一篇教程中,我们将正是这样做。我们将在这个简单的回归示例基础上,探索贝叶斯层次模型:行业标准、最先进的技术、事实上的标准…你可以自行定义。我们将看到如何在模型中加入组级的随机效应或固定效应,并惊叹于在贝叶斯框架中增加复杂性同时保持可比性的简便。
如果这篇文章对你有帮助,请订阅,并继续关注更多内容!
参考文献
- Andrew Gelman, John B. Carlin, Hal S. Stern, David B. Dunson, Aki Vehtari 和 Donald B. Rubin (2013). 贝叶斯数据分析,第三版。Chapman and Hall/CRC。
towardsdatascience.com/bayesian-linear-regression-a-complete-beginners-guide-3a49bb252fdc?source=collection_archive---------1-----------------------#2024-09-14

雷达卡


京公网安备 11010802022788号







