【Python】Facebook开源时间序列数据预测模型Prophet

文章目录

一、简介

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 内部应用于多种业务场景,显示出了其有效性和可靠性。

🟢主要特点:

  1. 自动处理季节性和节假日

    Prophet 可以自动识别和建模季节性模式(如每日、每周或每年的季节性),并允许用户手动指定额外的节假日效应,这对于有显著节假日影响的数据尤为重要。

  2. 处理缺失值和异常值

    Prophet 具有一定的鲁棒性,可以处理时间序列中的缺失值和异常值,而无需进行复杂的预处理。

  3. 灵活的趋势建模

    Prophet 提供了两种趋势模型:线性趋势和对数趋势,用户可以根据数据的实际情况选择合适的趋势模型。

  4. 简洁的接口

    Prophet 提供了 Python 和 R 语言的接口,用户可以用简单的几行代码完成建模和预测。

🟢工作原理:

Prophet 的核心思想是将时间序列数据分解为三个主要部分:趋势(Trend)、季节性(Seasonality)和节假日效应(Holiday Effects)(另外还有突变点)。具体工作流程如下:

  1. 趋势建模

    使用一个分段线性或分段对数模型来描述数据的长期趋势。用户可以设置趋势的变化点,以更好地捕捉趋势的变化。

  2. 季节性建模

    对数据进行周期性分解,以捕捉每日、每周或每年的季节性模式。季节性可以是周期性的,也可以是自定义的。

  3. 节假日效应

    用户可以添加自定义的节假日效应,用于建模特定日期对数据的影响(如春节、圣诞节等)。

  4. 模型训练和预测

    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处的观测值、趋势项、季节项、节假日项、噪声。

  • 趋势是非周期的,分为非线性和线性增长两种类型;
  • 季节项是周期性的,借助傅里叶级数处理;
  • 每个节假日都不同,是独立模型。

🟨缺点:

  1. 不适用于所有类型的时间序列数据
    • 短期数据:Prophet 主要设计用于长时间序列数据,对于非常短的数据集,它可能无法充分捕捉到趋势和季节性模式。
    • 复杂季节性模式:虽然 Prophet 支持每日、每周和每年的季节性,但对于非常复杂或不规则的季节性模式,模型可能不够灵活。
  2. 对异常值敏感
    • 异常值处理:虽然 Prophet 对缺失值和一些异常值有一定的鲁棒性,但对极端异常值的处理仍然有限。异常值可能会显著影响模型的预测效果。
  3. 趋势变化点的选择
    • 自动变化点:Prophet 自动选择变化点以捕捉趋势的变化,但这个自动选择可能不总是符合实际情况。用户需要手动调整变化点的位置,才能更好地适应数据中的实际变化。
  4. 模型复杂性
    • 参数调整:尽管 Prophet 的接口简单,但在某些情况下,用户仍需调整许多参数(如季节性周期、傅里叶级数阶数等)以获得最佳预测效果。对于没有足够经验的用户,这可能是一项挑战。
  5. 季节性建模的局限性
    • 固定周期:Prophet 的季节性建模基于傅里叶级数,假设季节性具有固定的周期。如果数据中存在非固定周期的季节性变化,Prophet 可能无法很好地建模这些变化。
  6. 节假日效应的建模限制
    • 节假日效应的局限性:虽然 Prophet 允许用户添加节假日效应,但在处理非常特殊或个别的事件时,可能需要手动调整和验证,这可能会增加建模的复杂性。
  7. 预测精度的限制
    • 不确定性区间:Prophet 提供了预测的不确定性区间,但这些区间可能会在实际应用中表现出较大的偏差,尤其是在趋势变化剧烈或季节性模式不稳定的情况下。
  8. 对外部因素的建模能力
    • 外部因素:Prophet 对外部因素(如经济变化、市场波动等)建模的能力有限。如果这些因素对预测结果有显著影响,可能需要结合其他模型进行综合分析。

尽管存在这些缺点,Prophet 仍然是一个非常有用的工具,特别是对于具有强季节性和趋势的数据。如果使用得当,并结合其他数据分析技术,Prophet 可以成为强大的时间序列预测工具。

二、项目的文件解读

它的 GitHub 仓库中有一个名为 python 的文件夹,里面包含与 Python 版本相关的内容。这个文件夹中的主要文件和目录及其作用:

  1. plot.py :这个文件包含绘图函数,用于可视化预测结果和诊断信息。它提供了如预测值图、成分图等常用的可视化工具。
  2. setup.py:这个文件包含安装脚本,用于定义如何安装这个包以及它的依赖项。它通常用于打包和分发 Prophet。
  3. stan 文件夹:这个文件夹包含 Stan 模型定义文件(.stan 文件),用于定义 Prophet 使用的统计模型。Stan 是一种概率编程语言,用于进行贝叶斯推断。
  4. 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
相关推荐
疯一样的码农几秒前
Python 正则表达式(RegEx)
开发语言·python·正则表达式
&岁月不待人&23 分钟前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
StayInLove26 分钟前
G1垃圾回收器日志详解
java·开发语言
无尽的大道34 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
爱吃生蚝的于勒38 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
binishuaio1 小时前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE1 小时前
【Java SE】StringBuffer
java·开发语言
就是有点傻1 小时前
WPF中的依赖属性
开发语言·wpf
洋2401 小时前
C语言常用标准库函数
c语言·开发语言
进击的六角龙1 小时前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel