Prophet 需求预测:Facebook 开源的时间序列工具实战
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 包含以下关键列:ds、yhat(预测值)、yhat_lower、yhat_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_window 和 upper_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_scale 和 seasonality_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_upper和yhat_lower指导安全库存和备货计划。 - 将预测结果导出为 CSV,对接供应链系统。
forecast[['ds','yhat','yhat_lower','yhat_upper','trend','promo']].tail(60).to_csv('sales_forecast.csv', index=False)