Prophet 需求预测:Facebook 开源的时间序列工具实战

FreeGuideOnline 最新 2026-06-24

bash pip install prophet


如果使用 conda,推荐通过 conda-forge 安装以避免编译问题:

```bash
conda install -c conda-forge prophet

验证安装

from prophet import Prophet
print(Prophet.__version__)

注意:从 v1.1 开始包名改为 prophet,导入仍使用 from prophet import Prophet


数据格式要求

Prophet 要求输入 DataFrame 包含两列:

  • ds:日期时间列(必须为 pandas 的 datetime 类型)。
  • y:待预测的数值列(必须为数值型,不能有负数或零?视业务而定)。

示例:

ds y
2023-01-01 142
2023-01-02 138
2023-01-03 150

读取与预处理实战代码

import pandas as pd

df = pd.read_csv('demand_data.csv')
df['ds'] = pd.to_datetime(df['ds'])
df = df[['ds', 'y']]          # 保留必要列
df = df.sort_values('ds')     # 按日期升序排列
df = df.drop_duplicates('ds') # 去重
df = df.set_index('ds').asfreq('D').reset_index() # 可选:对齐日期频率

提示:需求预测通常以天或周为单位,建议检查并填充缺失日期,可用向前填充或插值处理缺失的 y 值。


构建第一个 Prophet 模型

初始化与训练

model = Prophet()   # 使用默认参数
model.fit(df)

默认情况下,Prophet 自动拟合线性趋势 + 年月周日季节性。如果想关闭某些季节性,可以在初始化时设置:

model = Prophet(
    yearly_seasonality=True,
    weekly_seasonality=True,
    daily_seasonality=False
)

生成未来时间框

future = model.make_future_dataframe(periods=30)  # 预测未来30天
forecast = model.predict(future)

forecast 包含以下关键列:dsyhat(预测值)、yhat_loweryhat_upper(80%不确定性区间)以及各成分分解值。

查看预测结果

forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail()

可视化与成分分解

Prophet 内置可视化工具,可快速展示预测曲线和趋势/季节性分解。

from prophet.plot import plot_plotly, plot_components_plotly
import plotly.graph_objects as go

# 交互式预测图
fig_pred = plot_plotly(model, forecast)
fig_pred.update_layout(title='需求预测结果')
fig_pred.show()

# 成分分解
fig_comp = plot_components_plotly(model, forecast)
fig_comp.show()

非交互式版本使用 model.plot(forecast)model.plot_components(forecast)(基于 matplotlib)。

解读要点

  • 趋势曲线展现长期增长或衰减。
  • 每周季节性体现工作日/周末模式。
  • 年度季节性捕捉淡旺季。
  • 节假日效应(如果添加)呈现促销、节日带来的短期波动。

添加节假日与特殊事件

需求预测中,促销、节假日、极端天气等事件至关重要。通过创建事件 DataFrame 传递给模型:

# 定义节假日
holidays = pd.DataFrame({
  'holiday': 'promo',
  'ds': pd.to_datetime(['2023-06-18', '2023-11-11', '2023-12-12']),
  'lower_window': -1,   # 影响从事件前一天开始
  'upper_window': 2,    # 延续到事件后两天
})

model = Prophet(holidays=holidays)
model.fit(df)

lower_windowupper_window 控制事件效应持续时间。也可以传入 prior_scale 调整节假日效应的强度(默认 10,越大效应越强)。


调参与优化策略

Prophet 的主要可调参数集中在趋势灵活性和季节性强度。

1. 趋势变化点控制

changepoint_prior_scale:控制趋势变化的灵活性(默认 0.05)。增大该值使趋势更贴近历史波动,但可能过拟合。

model = Prophet(changepoint_prior_scale=0.5)

同时可手动指定变化点位置:

model = Prophet(changepoints=['2023-03-01', '2023-07-01'])

2. 季节性强度调节

seasonality_prior_scale:控制季节性成分的波动幅度(默认 10)。数值越大,季节性模式越强。

model = Prophet(seasonality_prior_scale=15)

3. 节假日效应强度

holidays_prior_scale:控制节假日成分的强度(默认 10)。

model = Prophet(holidays=holidays, holidays_prior_scale=20)

4. 添加乘法季节性

当时间序列的波动幅度随时间增长,应考虑乘法模型,而非默认的加法模型:

model = Prophet(seasonality_mode='multiplicative')

5. 手动添加额外季节性

例如业务存在双周付款周期影响:

model.add_seasonality(name='biweekly', period=14, fourier_order=5)

交叉验证与性能评估

Prophet 提供时间序列交叉验证工具,支持滚动原点评估预测表现。

from prophet.diagnostics import cross_validation, performance_metrics

df_cv = cross_validation(model, initial='365 days', period='30 days', horizon='30 days')
df_p = performance_metrics(df_cv)
print(df_p.head())

常用评估指标:MSE、RMSE、MAE、MAPE,以及 Prophet 额外提供的 coverage(实际值落在置信区间的比例)。

调参策略:使用 for 循环遍历 changepoint_prior_scaleseasonality_prior_scale 等组合,记录交叉验证误差,选择最优参数。

快速参数扫描示例

params_grid = {
    'changepoint_prior_scale': [0.001, 0.01, 0.1, 0.5],
    'seasonality_prior_scale': [0.1, 1.0, 10.0],
}

best_rmse = float('inf')
best_params = {}
for cps in params_grid['changepoint_prior_scale']:
    for sps in params_grid['seasonality_prior_scale']:
        m = Prophet(changepoint_prior_scale=cps, seasonality_prior_scale=sps)
        m.fit(df)
        df_cv = cross_validation(m, initial='730 days', period='180 days', horizon='90 days')
        df_p = performance_metrics(df_cv)
        rmse = df_p['rmse'].values[0]
        if rmse < best_rmse:
            best_rmse = rmse
            best_params = {'cps': cps, 'sps': sps}
print(f'Best params: {best_params}, RMSE: {best_rmse}')

注意:交叉验证可能耗时,建议先快速调小数据范围和周期。


实际需求预测案例:电商日销售额

业务背景

某电商平台需预测未来45天日销售额,数据包含过去3年历史,同时受"双十一""618""黑五"等大促影响。

数据预览与清洗

df = pd.read_csv('sales_daily.csv')
df['ds'] = pd.to_datetime(df['ds'])
df = df.groupby('ds')['y'].sum().reset_index() # 若原始数据有分仓,先汇总
df = df.asfreq('D', fill_value=0).reset_index() # 确保日期连续

构建促销事件

promos = pd.DataFrame({
    'holiday': 'promo',
    'ds': pd.to_datetime(['2022-06-18','2022-11-11','2022-11-25',
                          '2023-06-18','2023-11-11','2023-11-24']),
    'lower_window': -3,
    'upper_window': 5,
})

建模与预测

model = Prophet(
    holidays=promos,
    seasonality_mode='multiplicative', # 销售额波动随规模增大
    changepoint_prior_scale=0.05,
    yearly_seasonality=10,             # 使用较大的傅里叶阶数捕获复杂年模式
    weekly_seasonality=True,
    daily_seasonality=False,
)
model.fit(df)
future = model.make_future_dataframe(periods=45)
forecast = model.predict(future)

结果解读与业务应用

  • 查看趋势成分:判断业务是否进入增长/下降期。
  • 促销周影响数值:通过 forecast['promo'] 查看大促带来的增量。
  • 使用 yhat_upperyhat_lower 指导安全库存和备货计划。
  • 将预测结果导出为 CSV,对接供应链系统。
forecast[['ds','yhat','yhat_lower','yhat_upper','trend','promo']].tail(60).to_csv('sales_forecast.csv', index=False)