深入剖析时序Prophet模型:工作原理与源码解析|得物技术
目录
一、引入
二、准备知识
1. 参数估计
2. Stan开源框架
3. Prophet基本原理
三、Prophet源码剖析
1. 代码结构
2. 模型框架
3. 初始参数
4. 训练过程
4.1 数据预处理
4.2 自动设置周期性
4.3 生成特征宽表
4.4 设置间断点
4.5 初始化stan参数
4.6 参数拟合
5. 预测过程
5.1 构建预测dataframe
5.2 点预测
5.3 预测的不确定性
四、总结
随着得物业务的快速发展,积累了大量的时序数据,这些数据对精细化运营,提升效率、降低成本有着重要作用。在得物的时序数据挖掘场景中,时序预测Prophet模型使用频繁,本文对Prophet的原理和源码进行深入分析,欢迎阅读和交流。
一
引入
Prophet模型是如何进行训练和预测? 模型如何进行概率预测,得到预测的上界和下界?
二
准备知识
参数估计
Stan开源框架
https://mc-stan.org/ : Stan is a state-of-the-art platform for statistical modeling and high-performance statistical computation.
Prophet基本原理
变量和数据
data {int T; // Number of time periodsint<lower=1> K; // Number of regressorsvector[T] t; // Timevector[T] cap; // Capacities for logistic trendvector[T] y; // Time seriesint S; // Number of changepointsvector[S] t_change; // Times of trend changepointsmatrix[T,K] X; // Regressorsvector[K] sigmas; // Scale on seasonality priorreal<lower=0> tau; // Scale on changepoints priorint trend_indicator; // 0 for linear, 1 for logistic, 2 for flatvector[K] s_a; // Indicator of additive featuresvector[K] s_m; // Indicator of multiplicative features}
模型
model {//priorsk ~ normal(0, 5);m ~ normal(0, 5);delta ~ double_exponential(0, tau);sigma_obs ~ normal(0, 0.5);beta ~ normal(0, sigmas);// Likelihoody ~ normal_id_glm(X_sa,trend .* (1 + X_sm * beta),beta,sigma_obs);}
三
Prophet源码剖析
代码结构
|-- stan|-- Prophet.stan # stan语言实现的Prophet模型|-- setup.py|-- Prophet|-- serialize.py # Prophet训练完成的模型的序列化、模型的存储和加载,以便后续重用。|-- plot.py # 可视化模块|-- models.py # stan模型定义|-- diagnostics.py # 用于诊断 Prophet 模型性能的函数,比如计算误差指标、绘制诊断图等。|-- tests # 封装的测试脚本|-- __init__.py|-- __version__.py|-- forecaster.py # Prophet 类的定义,模型的核心逻辑,数据的处理、模型的拟合和预测等功能|-- utilities.py # 包含了一些辅助函数,用于处理时间序列数据、特征工程等。|-- make_holidays.py # 节假日具体日期的构造
Prophet.stan:用Stan编程语言实现的Prophet模型脚本。 models.py:python和Stan语言交互的模块,定义使用Stan脚本语言时的输入数据,拟合参数、输出数据,控制Stan进行参数拟合、采样。 forecaster.py:Prophet模型核心代码,定义了Prophet类,涉及整个模型的数据处理、模型训练和模型推理等功能。
模型框架
初始参数
Prophet类初始化 初始化模块主要是读取预先设定和Prophet有关的模型参数。分别有以下几类: 趋势项相关
growth: String 'linear', 'logistic' or 'flat' to specify a linear, logistic orflat trend.changepoints: List of dates at which to include potential changepoints. Ifnot specified, potential changepoints are selected automatically.n_changepoints: Number of potential changepoints to include. Not usedif input `changepoints` is supplied. If `changepoints` is not supplied,then n_changepoints potential changepoints are selected uniformly fromthe first `changepoint_range` proportion of the history.changepoint_range: Proportion of history in which trend changepoints willbe estimated. Defaults to 0.8 for the first 80%. Not used if`changepoints` is specified.changepoint_prior_scale: Parameter modulating the flexibility of theautomatic changepoint selection. Large values will allow manychangepoints, small values will allow few changepoints.
季节性相关
yearly_seasonality: Fit yearly seasonality.Can be 'auto', True, False, or a number of Fourier terms to generate.weekly_seasonality: Fit weekly seasonality.Can be 'auto', True, False, or a number of Fourier terms to generate.daily_seasonality: Fit daily seasonality.Can be 'auto', True, False, or a number of Fourier terms to generate.holidays: pd.DataFrame with columns holiday (string) and ds (date type)and optionally columns lower_window and upper_window which specify arange of days around the date to be included as holidays.lower_window=-2 will include 2 days prior to the date as holidays. Alsooptionally can have a column prior_scale specifying the prior scale forthat holiday.seasonality_mode: 'additive' (default) or 'multiplicative'.seasonality_prior_scale: Parameter modulating the strength of theseasonality model. Larger values allow the model to fit larger seasonalfluctuations, smaller values dampen the seasonality. Can be specifiedfor individual seasonalities using add_seasonality.holidays_prior_scale: Parameter modulating the strength of the holidaycomponents model, unless overridden in the holidays input.holidays_mode: 'additive' or 'multiplicative'. Defaults to seasonality_mode.
参数拟合相关
growth: String 'linear', 'logistic' or 'flat' to specify a linear, logistic orflat trend.changepoints: List of dates at which to include potential changepoints. Ifnot specified, potential changepoints are selected automatically.n_changepoints: Number of potential changepoints to include. Not usedif input `changepoints` is supplied. If `changepoints` is not supplied,then n_changepoints potential changepoints are selected uniformly fromthe first `changepoint_range` proportion of the history.changepoint_range: Proportion of history in which trend changepoints willbe estimated. Defaults to 0.8 for the first 80%. Not used if`changepoints` is specified.
不确定性相关
mcmc_samples: Integer, if greater than 0, will do full Bayesian inferencewith the specified number of MCMC samples. If 0, will do MAPestimation.interval_width: Float, width of the uncertainty intervals providedfor the forecast. If mcmc_samples=0, this will be only the uncertaintyin the trend using the MAP estimate of the extrapolated generativemodel. If mcmc.samples>0, this will be integrated over all modelparameters, which will include uncertainty in seasonality.uncertainty_samples: Number of simulated draws used to estimateuncertainty intervals. Settings this value to 0 or False will disableuncertainty estimation and speed up the calculation.stan_backend: str as defined in StanBackendEnum default: None - will try to
训练过程
数据预处理
数据检查
python.Prophet.forecaster.Prophet.setup_dataframe
检查输入数据中是否有y列,ds列是否符合时间输入规范,是否有缺失值。 检查添加的额外回归项,是否有缺失值,是否输入数据中有添加的回归项数据。 季节性项的condition列值是否是bool值等,用于控制模型选择性的学习condition为True的样本。 数据归一化
python.Prophet.forecaster.Prophet.initialize_scales
AbsMax归一化: 含义:AbsMax归一化是将原始数据缩放到[-1, 1]的范围内,使数据的绝对值最大值为1。 适用场景:AbsMax归一化适用于数据中存在明显的异常值或极端值的情况,可以保留数据的分布形状并减少异常值对模型的影响。 MinMax归一化: 含义:MinMax归一化是将原始数据缩放到[0, 1]的范围内,使数据的最小值对应0,最大值对应1。 适用场景:MinMax归一化适用于需要将数据映射到一个固定范围内的情况,保留了原始数据的相对关系,在大部分机器学习算法中经常用到。
if self.scaling == "absmax":self.y_min = 0.self.y_scale = float((df['y']).abs().max())elif self.scaling == "minmax":self.y_min = df['y'].min()self.y_scale = float(df['y'].max() - self.y_min)......
python/Prophet/forecaster.py:389
自动设置周期性
python.Prophet.forecaster.Prophet.set_auto_seasonalities
当历史数据大于等于两年,则增加yearly seasonality,默认周期为365.25;当历史数据大于等于两周,且相邻两数据之间的时间之差小于1周,则打开weekly seasonality,默认周期为7;当历史数据大于等于2天,且相邻两数据之间的时间小于1天,则打开daily seasonality,默认周期为1;
生成特征宽表
m = Prophet(holidays=pd.DataFrame({'holiday': '618','ds': pd.to_datetime(['2021-06-18', '2022-06-18', '2023-06-18', '2024-06-18']),'lower_window': -1,'upper_window': 0,'mode': 'additive'}))model.add_seasonality({'name':'seasonal_1','period':7, 'fourier_order':1,'mode': 'additive'})model.add_seasonality({'name':'seasonal_2','period':365, 'fourier_order':2,'mode': 'multiplicative'})
设置间断点
python.Prophet.forecaster.Prophet.set_changepoints
初始化stan参数
python.Prophet.forecaster.Prophet.calculate_initial_params
参数拟合
牛顿法/LBFGS法进行最大后验估计
python.Prophet.models.CmdStanPyBackend.fit
马尔可夫链蒙特卡罗法算法进行参数估计
python.Prophet.models.CmdStanPyBackend.sampling
预测过程
构建预测dataframe
python.Prophet.forecaster.Prophet.make_future_dataframe
点预测
趋势预测
python.Prophet.forecaster.Prophet.predict_trend
def predict_trend(self, df):k = np.nanmean(self.params['k'])m = np.nanmean(self.params['m'])deltas = np.nanmean(self.params['delta'], axis=0)t = np.array(df['t'])if self.growth == 'linear':trend = self.piecewise_linear(t, deltas, k, m, self.changepoints_t)elif self.growth == 'logistic':cap = df['cap_scaled']trend = self.piecewise_logistic(t, cap, deltas, k, m, self.changepoints_t)elif self.growth == 'flat':# constant trendtrend = self.flat_trend(t, m)return trend * self.y_scale + df['floor']
python.Prophet.forecaster.Prophet.piecewise_linear
回归项预测
python.Prophet.forecaster.Prophet.predict_seasonal_components
预测汇总
python/Prophet/forecaster.py:1287
预测的不确定性
观测噪声不确定性
python/Prophet/forecaster.py:1556
sigma = self.params['sigma_obs'][iteration]noise_terms = np.random.normal(0, sigma, trends.shape) * self.y_scale
趋势不确定性
python.Prophet.forecaster.Prophet._make_trend_shift_matrix
参数的不确定性
python.Prophet.forecaster.Prophet.predict_uncertainty
不确定性结果输出
lower_p = 100 * (1.0 - self.interval_width) / 2upper_p = 100 * (1.0 + self.interval_width) / 2
四
总结
往期回顾
1. 深入理解Babel - 项目管理工具lerna解析|得物技术
2. 星创编辑器在投放业务中的落地|得物技术
3. Java程序陷入时间裂缝:探索代码深处的神秘停顿|得物技术
4. KubeAI大模型推理加速实践|得物技术
5. 供应链PC实操落地实践|得物技术
文 / 探流
关注得物技术,每周一、三、五更新技术干货
要是觉得文章对你有帮助的话,欢迎评论转发点赞~
未经得物技术许可严禁转载,否则依法追究法律责任。
“
扫码添加小助手微信
如有任何疑问,或想要了解更多技术资讯,请添加小助手微信: