文章目录
- 一、简介
- 二、项目的文件解读
- 三、Prophet类主要方法和参数
-
- [3.1 主要参数](#3.1 主要参数)
- [3.2 主要方法](#3.2 主要方法)
- 四、用法示例
一、简介
Prophet
是由 Facebook 开发的一个开源工具,用于时间序列数据的预测。它特别适用于处理具有强季节性和趋势的时间序列数据,并且对节假日和突发事件有较好的处理能力。Prophet 通过简洁的接口和灵活的模型,帮助数据科学家和分析师轻松进行时间序列预测。支持R和Python。
Python源码:https://github.com/facebook/prophet/tree/main/python
入门文档:https://facebook.github.io/prophet/docs/quick_start.html
在传统的时间序列预测中,常用的方法有 ARIMA、SARIMA 等。虽然这些方法功能强大,但往往需要复杂的参数调整和数据预处理。Prophet 旨在简化这个过程,使预测变得更加直观和易于实现。Prophet 在 Facebook 内部应用于多种业务场景,显示出了其有效性和可靠性。
🟢主要特点:
-
自动处理季节性和节假日 :
Prophet 可以自动识别和建模季节性模式(如每日、每周或每年的季节性),并允许用户手动指定额外的节假日效应,这对于有显著节假日影响的数据尤为重要。
-
处理缺失值和异常值 :
Prophet 具有一定的鲁棒性,可以处理时间序列中的缺失值和异常值,而无需进行复杂的预处理。
-
灵活的趋势建模 :
Prophet 提供了两种趋势模型:线性趋势和对数趋势,用户可以根据数据的实际情况选择合适的趋势模型。
-
简洁的接口 :
Prophet 提供了 Python 和 R 语言的接口,用户可以用简单的几行代码完成建模和预测。
🟢工作原理:
Prophet 的核心思想是将时间序列数据分解为三个主要部分:趋势(Trend)、季节性(Seasonality)和节假日效应(Holiday Effects)(另外还有突变点)。具体工作流程如下:
-
趋势建模 :
使用一个分段线性或分段对数模型来描述数据的长期趋势。用户可以设置趋势的变化点,以更好地捕捉趋势的变化。
-
季节性建模 :
对数据进行周期性分解,以捕捉每日、每周或每年的季节性模式。季节性可以是周期性的,也可以是自定义的。
-
节假日效应 :
用户可以添加自定义的节假日效应,用于建模特定日期对数据的影响(如春节、圣诞节等)。
-
模型训练和预测 :
Prophet 使用贝叶斯回归方法来估计模型参数。通过训练后的模型,可以对未来的数据进行预测,并给出预测的不确定性区间。
🟢应用场景:
Prophet 广泛应用于各种时间序列预测任务,包括但不限于:
- 销售预测:预测未来的销售量,帮助企业制定销售策略。
- 流量预测:预测网站或应用的流量,以便于资源管理和优化。
- 财务预测:预测财务指标(如收入、支出)以便于预算编制和财务规划。
🟢数学模型:
Prophet 的最终模型是趋势、季节性和节假日效应的加权和:
y ( t ) = g ( t ) + S ( t ) + H ( t ) + ϵ t y(t)=g(t)+S(t)+H(t)+ϵ_t y(t)=g(t)+S(t)+H(t)+ϵt
分别是:时间t处的观测值、趋势项、季节项、节假日项、噪声。
- 趋势是非周期的,分为非线性和线性增长两种类型;
- 季节项是周期性的,借助傅里叶级数处理;
- 每个节假日都不同,是独立模型。
🟨缺点:
- 不适用于所有类型的时间序列数据
- 短期数据:Prophet 主要设计用于长时间序列数据,对于非常短的数据集,它可能无法充分捕捉到趋势和季节性模式。
- 复杂季节性模式:虽然 Prophet 支持每日、每周和每年的季节性,但对于非常复杂或不规则的季节性模式,模型可能不够灵活。
- 对异常值敏感
- 异常值处理:虽然 Prophet 对缺失值和一些异常值有一定的鲁棒性,但对极端异常值的处理仍然有限。异常值可能会显著影响模型的预测效果。
- 趋势变化点的选择
- 自动变化点:Prophet 自动选择变化点以捕捉趋势的变化,但这个自动选择可能不总是符合实际情况。用户需要手动调整变化点的位置,才能更好地适应数据中的实际变化。
- 模型复杂性
- 参数调整:尽管 Prophet 的接口简单,但在某些情况下,用户仍需调整许多参数(如季节性周期、傅里叶级数阶数等)以获得最佳预测效果。对于没有足够经验的用户,这可能是一项挑战。
- 季节性建模的局限性
- 固定周期:Prophet 的季节性建模基于傅里叶级数,假设季节性具有固定的周期。如果数据中存在非固定周期的季节性变化,Prophet 可能无法很好地建模这些变化。
- 节假日效应的建模限制
- 节假日效应的局限性:虽然 Prophet 允许用户添加节假日效应,但在处理非常特殊或个别的事件时,可能需要手动调整和验证,这可能会增加建模的复杂性。
- 预测精度的限制
- 不确定性区间:Prophet 提供了预测的不确定性区间,但这些区间可能会在实际应用中表现出较大的偏差,尤其是在趋势变化剧烈或季节性模式不稳定的情况下。
- 对外部因素的建模能力
- 外部因素:Prophet 对外部因素(如经济变化、市场波动等)建模的能力有限。如果这些因素对预测结果有显著影响,可能需要结合其他模型进行综合分析。
尽管存在这些缺点,Prophet 仍然是一个非常有用的工具,特别是对于具有强季节性和趋势的数据。如果使用得当,并结合其他数据分析技术,Prophet 可以成为强大的时间序列预测工具。
二、项目的文件解读
它的 GitHub 仓库中有一个名为 python
的文件夹,里面包含与 Python 版本相关的内容。这个文件夹中的主要文件和目录及其作用:
plot.py
:这个文件包含绘图函数,用于可视化预测结果和诊断信息。它提供了如预测值图、成分图等常用的可视化工具。setup.py
:这个文件包含安装脚本,用于定义如何安装这个包以及它的依赖项。它通常用于打包和分发 Prophet。stan
文件夹:这个文件夹包含 Stan 模型定义文件(.stan 文件),用于定义 Prophet 使用的统计模型。Stan 是一种概率编程语言,用于进行贝叶斯推断。tests
文件夹:这个文件夹包含测试代码,用于确保 Prophet 的各个功能模块正常工作。通常包括单元测试和集成测试。
文件名 | 描述 |
---|---|
diagnostics.py |
包含用于诊断和评估模型的功能,如计算模型的残差、预测误差和其他性能指标,帮助识别模型的潜在问题。 |
forecaster.py |
包含 Prophet 类的预测相关方法,包括生成未来的时间数据框 (make_future_dataframe ) 和进行预测 (predict )。 |
make_holidays.py |
处理假日效应的相关功能,提供创建和处理假日数据的工具,通常用于在模型中添加假日效应。 |
models.py |
包含模型的定义和实现,例如趋势模型、季节性模型以及其他组件的实现。用于构建和训练 Prophet 模型。 |
plot.py |
提供用于可视化 Prophet 模型结果的功能,包括绘制预测图、趋势图和季节性图等。 |
serialize.py |
包含用于序列化和反序列化 Prophet 模型的功能,允许将模型保存到磁盘并在以后重新加载。 |
utilities.py |
提供辅助函数和工具,用于数据处理、转换、验证等操作,支持主功能的实现。 |
__init__.py |
prophet 包的初始化文件,定义了包的导入接口,并可能包含一些包级别的设置。 |
__version__.py |
包含 prophet 项目的版本信息,提供当前安装版本的相关信息。 |
代码不多的,总共4000多行,我根据需要精简到了1500行。
三、Prophet类主要方法和参数
Prophet是主要的类,用来训练、预测、绘图等。
输入数据是 pd.DataFrame,2列,列名必须是ds
(时间)和y
(数据)。
如:
python
dates = pd.date_range(start='2023-01-01', periods=365)
data = {
'ds': dates,
'y': [x + (x % 30) * 0.1 for x in range(365)]
}
df = pd.DataFrame(data)
3.1 主要参数
Prophet 类的参数:
参数名称 | 类型 | 描述 |
---|---|---|
growth |
String | 'linear', 'logistic' 或 'flat',指定线性、逻辑或平趋势。 |
changepoints |
List[dates] | 包含潜在变化点的日期列表。如果未指定,潜在变化点将自动选择。 |
n_changepoints |
Integer | 要包括的潜在变化点的数量。如果提供了 changepoints ,则不使用该参数。 |
changepoint_range |
Float | 估计趋势变化点的历史比例,默认值为 0.8(前 80%)。如果指定了 changepoints ,则不使用该参数。 |
yearly_seasonality |
'auto', bool, int | 是否拟合年度季节性。可以是 'auto'、True、False 或用于生成的傅里叶项的数量。 |
weekly_seasonality |
'auto', bool, int | 是否拟合每周季节性。可以是 'auto'、True、False 或用于生成的傅里叶项的数量。 |
daily_seasonality |
'auto', bool, int | 是否拟合每日季节性。可以是 'auto'、True、False 或用于生成的傅里叶项的数量。 |
holidays |
pd.DataFrame | 包含假日数据的 DataFrame,列包括 holiday(字符串)和 ds(日期类型),可选列包括 lower_window、upper_window 和 prior_scale。 |
seasonality_mode |
String | 'additive'(默认)或 'multiplicative'。 |
seasonality_prior_scale |
Float | 调节季节性模型强度的参数。较大的值允许模型拟合较大的季节性波动,较小的值则抑制季节性。可以使用 add_seasonality 为单个季节性指定。 |
holidays_prior_scale |
Float | 调节假日成分模型强度的参数,除非在假日输入中覆盖。 |
changepoint_prior_scale |
Float | 调节自动变化点选择灵活性的参数。较大的值允许更多变化点,较小的值则允许较少变化点。 |
mcmc_samples |
Integer | 如果大于 0,将使用指定数量的 MCMC 样本进行全贝叶斯推断。如果为 0,将进行 MAP 估计。 |
interval_width |
Float | 提供预测不确定性区间的宽度。如果 mcmc_samples=0,这将仅是不确定趋势的 MAP 估计。如果 mcmc_samples>0,这将包括所有模型参数的不确定性。 |
uncertainty_samples |
Integer | 用于估计不确定性区间的模拟抽样数。将该值设置为 0 或 False 将禁用不确定性估计并加快计算速度。 |
stan_backend |
String | 如 StanBackendEnum 中定义的字符串,默认值:None - 将尝试遍历所有可用的后端并找到可工作的后端。 |
holidays_mode |
String | 'additive' 或 'multiplicative'。默认为 seasonality_mode。 |
Prophet 类内部用于模型配置和训练的参数:
参数名称 | 描述 |
---|---|
self.start |
用于保存时间序列数据的开始时间。通常在处理数据时设定。 |
self.y_min |
保存目标变量 y 的最小值。用于标准化或缩放处理。 |
self.y_scale |
保存目标变量 y 的缩放因子。用于标准化处理,将数据缩放到模型适合的范围。 |
self.logistic_floor |
布尔值,表示是否使用逻辑斯蒂(logistic)模型的下限(floor)。当设置为 True 时,y 被限制在某个下限以上。 |
self.t_scale |
保存时间(t )的缩放因子。用于对时间变量进行标准化处理。 |
self.changepoints_t |
存储变化点的时间。变化点是在时间序列中趋势发生显著变化的点。 |
self.seasonalities |
存储季节性成分的字典,其中每个季节性成分都有其自己的配置。 |
self.extra_regressors |
存储额外回归量的字典。额外回归量是在模型中添加的额外特征,用于增强模型的预测能力。 |
self.country_holidays |
存储国家假日信息的对象。用于添加假日效应对预测的影响。 |
self.stan_fit |
存储 Stan 模型的拟合结果。包括模型的所有参数和后验分布。 |
self.params |
存储模型的参数。包括趋势、季节性和假日成分的相关参数。 |
self.history |
存储历史数据。用于模型训练的实际时间序列数据。 |
self.history_dates |
存储历史数据的日期信息。用于时间序列数据的索引。 |
self.train_component_cols |
存储用于训练的组件列名。包括趋势、季节性和假日成分的列名。 |
self.component_modes |
存储模型组件模式的字典。例如,季节性和假日的加法或乘法模式。 |
self.train_holiday_names |
存储训练数据中的假日名称。用于假日效应的分析。 |
self.fit_kwargs |
存储拟合模型时的额外参数或配置选项。 |
self.validate_inputs() |
用于验证输入数据的有效性。确保数据符合模型的要求。 |
self._load_stan_backend(stan_backend) |
加载指定的 Stan 后端。用于模型的贝叶斯推断计算。 |
看源码,我添加了注释:
python
class Prophet(object):
def __init__(
self,
growth='linear',
changepoints=None,
n_changepoints=25,
changepoint_range=0.8,
yearly_seasonality='auto',
weekly_seasonality='auto',
daily_seasonality='auto',
holidays=None,
seasonality_mode='additive',
seasonality_prior_scale=10.0,
holidays_prior_scale=10.0,
changepoint_prior_scale=0.05,
mcmc_samples=0,
interval_width=0.80,
uncertainty_samples=1000,
stan_backend=None,
scaling: str = 'absmax',
holidays_mode=None,
):
# 增长趋势,默认Linear
self.growth = growth
# 潜在变化点(突变点)列表,默认为None
self.changepoints = changepoints
# 如果提供了潜在变化点列表,将其转换为 pandas 的 Series
# 同时计算 n_changepoints 即变化点的数量(默认25),该参数无需再次指定
# 将变量 specified_changepoints 设置为True,即指定了潜在变化点
if self.changepoints is not None:
self.changepoints = pd.Series(pd.to_datetime(self.changepoints), name='ds')
self.n_changepoints = len(self.changepoints)
self.specified_changepoints = True
else:
self.n_changepoints = n_changepoints
self.specified_changepoints = False
# 变化点的历史比例,默认0.8(前80%)
self.changepoint_range = changepoint_range
# 是否拟合年度季节性,默认auto
self.yearly_seasonality = yearly_seasonality
# 是否拟合每周季节性,默认auto
self.weekly_seasonality = weekly_seasonality
# 是否拟合每日季节性,默认auto
self.daily_seasonality = daily_seasonality
# 包含假日数据的 DataFrame,默认none
self.holidays = holidays
# 指定季节性成分的模式,默认additive:加法模式,即季节性变化是独立于数据水平的变化
# 季节性成分的影响与数据的总体水平无关,季节性波动是恒定的
self.seasonality_mode = seasonality_mode
# 假日成分的模式,默认None,即和季节的模式保持相同
self.holidays_mode = holidays_mode
if holidays_mode is None:
self.holidays_mode = self.seasonality_mode
# 调节季节性模型的强度,较大的值允许模型拟合较大的季节性波动,较小的值则抑制季节性
self.seasonality_prior_scale = float(seasonality_prior_scale)
# 调节假日成分模型的强度
self.holidays_prior_scale = float(holidays_prior_scale)
# 调节自动变化点选择灵活性,较大的值允许更多变化点,较小的值则允许较少变化点。
self.changepoint_prior_scale = float(changepoint_prior_scale)
# 控制模型的贝叶斯推断方式,默认0.如果大于 0,将使用指定数量的 MCMC 样本进行全贝叶斯推断。如果为 0,将进行 MAP 估计。
self.mcmc_samples = mcmc_samples
# 预测不确定性区间的宽度,默认0.8。如果 mcmc_samples=0,这将仅是不确定趋势的 MAP 估计。如果 mcmc_samples>0,这将包括所有模型参数的不确定性
self.interval_width = interval_width
# 用于估计不确定性区间的模拟抽样数,默认1000。将该值设置为 0 或 False 将禁用不确定性估计并加快计算速度。
self.uncertainty_samples = uncertainty_samples
# 数据标准化方法,绝对最大值缩放 absmax 和最大最小值缩放 minmax
if scaling not in ("absmax", "minmax"):
raise ValueError("scaling must be one of 'absmax' or 'minmax'")
self.scaling = scaling
# 训练或者其它方法所需参数
# 开始时间
self.start = None
# 目标变量y的最小值
self.y_min = None
# y的缩放因子
self.y_scale = None
# logistic模型下限
self.logistic_floor = False
# 时间的缩放因子
self.t_scale = None
# 突变点的时间
self.changepoints_t = None
# 季节性成分字典
self.seasonalities = OrderedDict({})
# 额外回归量的字典
self.extra_regressors = OrderedDict({})
# 国家假日信息
self.country_holidays = None
# stan模型你和结果
self.stan_fit = None
# 模型参数,包括趋势、季节性和假日成分的相关参数。
self.params = {}
# 历史数据
self.history = None
# 历史数据日期
self.history_dates = None
# 训练的组件列名。包括趋势、季节性和假日成分的列名。
self.train_component_cols = None
# 模型组件模式的字典。例如,季节性和假日的加法或乘法模式。
self.component_modes = None
# 练数据中的假日名称
self.train_holiday_names = None
# 额外参数或配置选项
self.fit_kwargs = {}
# 验证输入数据的有效性。确保数据符合模型的要求
self.validate_inputs()
# 加载指定的 Stan 后端,用于模型的贝叶斯推断计算
# stan_backend,如 StanBackendEnum 中定义的字符串,默认值:None - 将尝试遍历所有可用的后端并找到可工作的后端
self._load_stan_backend(stan_backend)
3.2 主要方法
Prophet 类中主要方法:
方法名称 | 描述 |
---|---|
__init__() |
初始化 Prophet 类的实例。 |
fit(df, **kwargs) |
拟合模型,训练数据为 df 。 |
predict(df) |
生成预测结果,输入为 df 。 |
predictive_samples(df) |
从模型的后验分布中生成预测样本。 |
make_future_dataframe(periods, freq) |
创建一个包含未来时间的 DataFrame。 |
plot(fcst, ax, uncertainty, plot_cap) |
绘制预测结果。 |
plot_components(fcst, **kwargs) |
绘制预测结果的各个组成部分。 |
add_seasonality(name, period, fourier_order, prior_scale, mode, condition_name) |
添加自定义季节性组件。 |
add_country_holidays(country_name) |
添加指定国家的节假日。 |
add_regressor(name, prior_scale, standardize, mode) |
添加外部回归变量。 |
train_holiday_names |
返回模型训练时使用的节假日名称。 |
stan_backend |
返回 Stan 后端接口。 |
stan_init |
返回 Stan 初始化数据。 |
stan_fit |
返回 Stan 模型拟合结果。 |
set_auto_seasonality |
设置是否自动检测和添加季节性组件。 |
initialize_scales |
初始化数据标准化参数。 |
setup_dataframe(df, initialize_scales) |
准备数据框架以进行模型训练。 |
piecewise_linear(t) |
定义分段线性趋势模型。 |
piecewise_logistic(t) |
定义分段逻辑回归趋势模型。 |
growth_discontinuity_prior(gamma) |
设置增长不连续性的先验。 |
logistic_floor(t) |
定义逻辑回归模型的地板值。 |
parse_seasonality_args(name, period, fourier_order, prior_scale, mode) |
解析季节性参数。 |
set_seasonality_params |
设置季节性参数。 |
validate_column_name(name) |
验证列名称是否有效。 |
validate_inputs |
验证输入数据的有效性。 |
make_all_seasonality_features(df) |
创建所有季节性特征。 |
make_seasonality_features(df, name, period, fourier_order) |
创建指定季节性的特征。 |
seasonality_features_for_dates(dates, name, period, fourier_order) |
为指定日期创建季节性特征。 |
add_changepoints_to_holidays |
添加节假日变化点。 |
make_changepoints(df) |
创建变化点。 |
history_full |
返回完整的历史数据。 |
history_dates |
返回历史数据的日期。 |
compute_components_sums |
计算各个组成部分的和。 |
component_properties |
返回各个组件的属性。 |
add_group_specific_timestamps |
添加特定于组的时间戳。 |
sample_model |
从模型中采样参数。 |
apply_seasonality_switching |
应用季节性切换。 |
normalize |
标准化输入数据。 |
is_changepoint_outlier |
判断是否为变化点异常值。 |
set_changepoint_prior_scale |
设置变化点先验尺度。 |
parse_changepoints |
解析变化点。 |
fit_predict |
拟合模型并生成预测结果。 |
stan_model |
返回 Stan 模型对象。 |
fit_stan_model |
拟合 Stan 模型。 |
四、用法示例
要用它,首先要明确你的数据是否合适,其次要了解它的数学模型,这样你才能更好地设置参数。
或者你把它的代码读一遍也可以,总共就4000来行,你看forecast那个文件的1900多行差不多就能明白了。
来个简单的示例:
python
import pandas as pd
from fbprophet import Prophet
import matplotlib.pyplot as plt
# 创建示例数据
dates = pd.date_range(start='2023-01-01', periods=365)
data = {
'ds': dates,
'y': [x + (x % 30) * 0.1 for x in range(365)]
}
df = pd.DataFrame(data)
# 初始化 Prophet 模型
model = Prophet()
# 拟合模型
model.fit(df)
# 生成未来日期
pred_len = 30 # 预测未来 30 天
future = model.make_future_dataframe(periods=pred_len, freq='D')
# 进行预测
forecast = model.predict(future)
# 展示结果
fig1 = model.plot(forecast)
plt.title('Prophet Forecast')
plt.xlabel('Date')
plt.ylabel('Value')
plt.show()
# 打印预测的最后几行
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail())
bash
ds yhat yhat_lower yhat_upper
390 2024-01-26 391.452024 389.329087 393.542118
391 2024-01-27 392.434908 390.270313 394.764440
392 2024-01-28 393.468846 390.929671 395.868170
393 2024-01-29 394.467450 391.870685 397.082774
394 2024-01-30 395.445139 392.744768 398.179136