Stan 是一种用于统计建模和高性能统计计算的先进平台。Stan已经在社会、生物和物理科学、工程和商业领域被应用于统计建模、数据分析和预测。
基于Stan概率编程语言开发统计模型
进行MCMC采样
基于变分推理的近似贝叶斯计算
基于正则项的极大似然函数的优化方法
Stan提供Python和R语言安装包,Stan可以自动化实现统计学模型转化为C++代码的功能,以方便用户进行部署调用。本文主要讲述怎样使用Stan进行统计学模型参数估计,并嵌入C++开发平台。
下面是Stan语言模型构建程序骨架:
functions模块包含了用户自定义函数
data指明定义了模型的输入数据格式及其数据类型
transformed data模块允许用户定义常量或从data转换过来的数据
parameters模块声明模型的参数
transformed parameters模块允许定义变量来保存由data或parameters生成的中间数据
model模块定义了模型的对数密度函数
generated quantities 模块允许基于parameters,data, 及随机数生成用户需要的数据
functions {
// ... function declarations and definitions ...
}
data {
// ... declarations ...
}
transformed data {
// ... declarations ... statements ...
}
parameters {
// ... declarations ...
}
transformed parameters {
// ... declarations ... statements ...
}
model {
// ... declarations ... statements ...
}
generated quantities {
// ... declarations ... statements ...
}
Stan提供优化算法来搜索使用Stan语言定义的密度函数模式,此模式可被用来进行参数估计,或用来做贝叶斯后验分析。Stan提供三种优化算法,分别为牛顿法和两种近似牛顿法(BFGS、LBFGS)。
在使用优化算法过程中,一个主要问题是收敛性的监测问题,在Stan优化算法可以使用多种参数进行监测。任意一个监测参数满足时则认为该函数已经收敛。可以通过将其相应的容差参数设置为零来禁止此种收敛监测。
参数收敛监测,如果参数 在第 次迭代过程中,其变化量小于tol_param时,则认为收敛,公式如下:
密度函数收敛监测,如果对于 在给定数据集 上,对数密度函数 的变化量小于tot_obj,则认为收敛,公式如下:
当对数密度函数的相对变化量小于tol_rel_obj,则认为收敛,公式如下:
梯度收敛监测,当梯度的二范数小于容差tol_grad时,则认为收敛,公式如下:
其中 ,在第i轮迭代时的计算值。
相对梯度收敛监测,当相对变化量小于tol_rel_grad时,则认为收敛,公式如下:
其中 是第i轮的 Hessian估计, 是机器精度。
Prophet是由Facebook开源的一种基于可加模型预测时间序列数据的python分析组件,其非线性趋势与年、星期、日、季节性以及假日效应相吻合。它最适用于具有强烈季节性影响和多个季节历史数据的时间序列。Prophet 对缺失数据和趋势变化具有稳健性,并且通常可以很好地处理异常值。
经过研究其源码可以发现,其后端主要依赖于pyStan、pycmdStan等Stan相关组件,Prophet模型是由Stan语言定义的一个统计学模型。如果将Prophet嵌入到C++开发环境中,则需要用C++语言实现Prophet模型的建模,在这种情况下,可以借助Stan语言及其工具链进行集成开发。
模型定义文件prophet.stan如下(摘取部分),该文件来自Porphet源码。其中data为模型的输入数据格式及其类型,parameters 为该模型参数,model定义了该模型的密度函数。
data {
int T; // Number of time periods
int K; // Number of regressors
vector[T] t; // Time
vector[T] cap; // Capacities for logistic trend
vector[T] y; // Time series
int S; // Number of changepoints
vector[S] t_change; // Times of trend changepoints
matrix[T,K] X; // Regressors
vector[K] sigmas; // Scale on seasonality prior
real tau; // Scale on changepoints prior
int trend_indicator; // 0 for linear, 1 for logistic, 2 for flat
vector[K] s_a; // Indicator of additive features
vector[K] s_m; // Indicator of multiplicative features
}
parameters {
real k; // Base trend growth rate
real m; // Trend offset
vector[S] delta; // Trend rate adjustments
real sigma_obs; // Observation noise
vector[K] beta; // Regressor coefficients
}
model {
//priors
k ~ normal(0, 5);
m ~ normal(0, 5);
delta ~ double_exponential(0, tau);
sigma_obs ~ normal(0, 0.5);
beta ~ normal(0, sigmas);
// Likelihood
y ~ normal(
trend
.* (1 + X * (beta .* s_m))
+ X * (beta .* s_a),
sigma_obs
);
}
使用stanc生成prophet.hpp如下:
class prophet_model final : public model_base_crtp {
private:
int T;
int K;
Eigen::Matrix t;
Eigen::Matrix cap;
Eigen::Matrix y;
int S;
Eigen::Matrix t_change;
Eigen::Matrix X;
Eigen::Matrix sigmas;
double tau;
int trend_indicator;
Eigen::Matrix s_a;
Eigen::Matrix s_m;
Eigen::Matrix A;
public:
~prophet_model() { }
inline std::string model_name() const final { return "prophet_model"; }
prophet_model(stan::io::var_context& context__,
unsigned int random_seed__ = 0,
std::ostream* pstream__ = nullptr) : model_base_crtp(0) {
...
...
}
模型优化计算,调用Stan优化方法搜索概率密度函数模型参数。
int lbfgs(Model& model, const stan::io::var_context& init,
unsigned int random_seed, unsigned int chain, double init_radius,
int history_size, double init_alpha, double tol_obj,
double tol_rel_obj, double tol_grad, double tol_rel_grad,
double tol_param, int num_iterations, bool save_iterations,
int refresh, callbacks::interrupt& interrupt,
callbacks::logger& logger, callbacks::writer& init_writer,
callbacks::writer& parameter_writer)
为验证方便,借助Stan辅助工具CmdStan(Command-Line Interface),直接执行 make examples/prophet/prophet 进行自动化编译,在make过程中会调用stanc转换翻译prophet.stan,同时会将该模型包装成命令行,生成prophet的可执行文件。
运行prophet模型,并将模型参数输出到csv,可以从下面的结果看到此模型在优化过程中的相对梯度达到收敛监测指标。根据优化后获取的模型参数构建模型时间序列预测函数。
./prophet method method=optimize algorithm=lbfgs iter=10000 data file=data_file.json init=stan_init.json random seed=10000
Initial log joint probability = -19.4685
Iter log prob ||dx|| ||grad|| alpha alpha0 # evals Notes
742 8004.29 4.87051e-07 65.1727 0.04812 1 971
Optimization terminated normally:
Convergence detected: relative gradient magnitude is below tolerance
Stan为用户提供了快速创建统计模型的中间语言,实现自动化将统计学模型快速翻译成C++语言,在统计学习模型落地部署过程中,使用户省去了大量的模型开发工作,同时Stan还提供统计模型加速优化器,为用户提供了快速求解统计模型的优化方法。同时还可利用Stan平台进行统计模型采样和基于变分推理的近似贝叶斯推理计算。
https://mc-stan.org/docs/2_27/stan-users-guide/index.html
https://mc-stan.org/users/interfaces/cmdstan
https://github.com/stan-dev/cmdstan
https://github.com/stan-dev/stan
https://facebook.github.io/prophet/
https://github.com/facebook/prophet