数以千计的用户依靠stan在社会,生物和物理科学,工程和商业进行统计建模,数据分析和预测的工作。
用户在Stan概率编程语言中可以基于对数概率密度函数,得到:
完整的贝叶斯统计推理与MCMC抽样(NUTS,HMC)
近似贝叶斯推理与变分推断(variational inference)(ADVI)
优化最大惩罚似然估计(penalized maximum likelihood estimation)(L-BFGS)
stan的数学库提供了可微的概率函数和线性代数(C ++ autodiff),R包中还提供了基于表达式的线性建模,后验概率可视化和留一法交叉验证。
stan为R语言提供了接口,使用的包就是rstan,它的安装教程请看这里:https://github.com/stan-dev/rstan/wiki/Installing-RStan-on-Windows#toolchain
想要用好stan这种概率编程语言,就得先理解贝叶斯是一种什么样的方法。其实统计学界一直有两种,观点,一种称为频率学派,一种是贝叶斯学派。
按照我的理解,在贝叶斯看来,模型中的参数,都可以看作是一个随机变量,这其中包括你的数据x,还有你要预测的y,x的系数 β β ,模型中的噪声等等,都是可以是随机变量,他们都是服从某个分布的,我们一般称参数的分布为先验分布,比如服从参数可以服从正态分布,gamma分布等等。
但在频率学家看来就不太一样,他们觉得模型里面的参数就是一个数,是一个确定的事件,只要你找到足够的样本你就可以得到这个数准确的值,它并不是什么随机变量。
而贝叶斯学派则会是这样想,你的样本如果很多,我可以说你有99.9999%等于这个数,但也有可能等于其他数的,只是概率比较小而已罢了,因此它是从一个概率分布的角度来看到这个问题。
觉得先验分布这个概念比较抽象的读者可以先看看我之前写的文章:带你理解beta分布
现在我们用一个最小二乘回归来介绍stan的使用方法。
假设我们的模型为:
于是,我们可以得到y也是服从正态分布的, yi∼N(xiβ,σ2) y i ∼ N ( x i β , σ 2 )
那么我们可以使用stan,定义这个线性回归模型:
data { //这里是程序需要输入的参数
int0> n; // 样本量
int0> k; // X的维度
matrix[n, k] X; // 变量X,这是一个样本矩阵
vector[n] Y; // 输出变量Y
}
parameters { //这里是需要拟合的参数
real alpha; // 截距项
vector[k] beta; // 系数
real0> sigma; // 噪声的参数
}
model {
Y ~ normal(X * beta + alpha, sigma); // likelihood
}
程序里面的data就是我们模型需要输入的数据,我们可以用R语言使用一个list把这些数据传进去。另外在定义参数的时候还可以定义参数的取值范围,这可以用来初始化参数的值。我们将上面代码保存为一个叫做lm_demo.stan
的文件中,然后,我们在R中随机产生一些数据来看看这个线性回归的效果。
library(rstan)
#如果你有多个CPU和足够的内存可以用以下两条语句开启并行计算
rstan_options(auto_write = TRUE)
options(mc.cores = parallel::detectCores())
set.seed(0)
n=100
k=5
X<-matrix(runif(n*k,-1,1),nrow=n,ncol=k)
beta<-rnorm(k,0,4)
alpha<-rnorm(1,5,4)
Y<-alpha+X%*%beta+rnorm(n,0,4)
Y<-as.vector(Y)
data=list(n=n,k=k,X=X,Y=Y)
print(beta)
print(alpha)
在这里,我们的模型系数是:
> print(beta)
[1] 9.5809373 -0.9649906 -3.4383390 2.0016643 0.5542299
> print(alpha)
[1] 3.225041
于是我们使用rstan去拟合这个模型,
> fit1<-stan("lm_demo.stan",data=data)
> print(fit1)
Inference for Stan model: lm_demo.
4 chains, each with iter=2000; warmup=1000; thin=1;
post-warmup draws per chain=1000, total post-warmup draws=4000.
mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat
alpha 4.08 0.01 0.40 3.29 3.80 4.08 4.35 4.84 4000 1
beta[1] 9.92 0.01 0.66 8.59 9.48 9.92 10.37 11.21 4000 1
beta[2] -1.45 0.01 0.80 -3.03 -1.97 -1.44 -0.91 0.08 4000 1
beta[3] -3.66 0.01 0.69 -5.01 -4.14 -3.66 -3.20 -2.26 4000 1
beta[4] 2.08 0.01 0.73 0.68 1.59 2.08 2.56 3.53 4000 1
beta[5] 1.28 0.01 0.75 -0.20 0.79 1.27 1.77 2.76 4000 1
sigma 3.95 0.00 0.30 3.43 3.73 3.93 4.14 4.60 4000 1
lp__ -185.14 0.05 1.97 -189.84 -186.24 -184.79 -183.65 -182.36 1856 1
Samples were drawn using NUTS(diag_e) at Sat Apr 15 22:40:22 2017.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at
convergence, Rhat=1).
里面的表格给出了拟合出来的参数的值。这里的结果提供了其均值方差等信息,我们可以大致确定这些参数的置信区间,这在现实里面也是非常有用的信息。
从贝叶斯的角度来看待回归的问题,我们可以假设系数也服从正态分布,也就是 β∼N(0,τ2) β ∼ N ( 0 , τ 2 ) 这么一个先验分布。
于是,我们只需简单修改一下模型,就得到了新的回归,这么一个回归应该可以看作是Ridge regression:
data { //这里是程序需要输入的参数
int0> n; // 样本量
int0> k; // X的维度
matrix[n, k] X; // 变量X,这是一个样本矩阵
vector[n] Y; // 输出变量Y
}
parameters { //这里是需要拟合的参数
real alpha; // 截距项
vector[k] beta; // 系数
real0> sigma; // 噪声的参数
}
model {
beta~normal(0,4);
alpha~normal(5,4);
Y ~ normal(X * beta + alpha, sigma); // likelihood
}
它的结果如下:
> fit2<-stan("lm_bayesian_demo.stan",data=data)
> print(fit2)
Inference for Stan model: lm_bayesian_demo.
4 chains, each with iter=2000; warmup=1000; thin=1;
post-warmup draws per chain=1000, total post-warmup draws=4000.
mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat
alpha 4.08 0.01 0.40 3.29 3.81 4.08 4.35 4.85 4000 1
beta[1] 9.63 0.01 0.65 8.30 9.20 9.63 10.07 10.92 4000 1
beta[2] -1.35 0.01 0.74 -2.77 -1.83 -1.36 -0.85 0.11 4000 1
beta[3] -3.56 0.01 0.68 -4.87 -4.02 -3.55 -3.10 -2.22 4000 1
beta[4] 1.96 0.01 0.73 0.49 1.46 1.95 2.44 3.41 4000 1
beta[5] 1.24 0.01 0.74 -0.21 0.73 1.26 1.74 2.70 4000 1
sigma 3.95 0.00 0.29 3.44 3.75 3.93 4.14 4.59 4000 1
lp__ -188.74 0.05 1.88 -193.15 -189.80 -188.44 -187.34 -186.03 1633 1
Samples were drawn using NUTS(diag_e) at Sat Apr 15 22:40:26 2017.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at
convergence, Rhat=1).
可以看到,beta的每一项都比没加先验分布的结果要更接近0。
将他们的它们拟合的参数可以画出来,看到它们的取值范围:
library(gridExtra)
plot1=plot(fit1)+labs(title="lm_demo")
plot2=plot(fit2)+labs(title="lm_bayesian_demo")
grid.arrange(plot1, plot2, ncol=2)
两个方法在这个数据上也没什么区别,
除此之外,stan还能定义各种各样的概率模型,比如说高斯过程,时间序列等等。
想进一步了解可以参考:
https://github.com/stan-dev/rstan/wiki/RStan-Getting-Started#how-to-use-rstan
http://mc-stan.org/documentation/
概率编程语言Stan介绍《Stan: A Probabilistic Programming Language》B Carpenter, A Gelman, M Hoffman (2015) [Columbia University]
作为分享主义者(sharism),本人所有互联网发布的图文均遵从CC版权,转载请保留作者信息并注明作者a358463121专栏:http://blog.csdn.net/a358463121,如果涉及源代码请注明GitHub地址:https://github.com/358463121/。商业使用请联系作者。