本文来源公众号“Coggle数据科学”,仅用于学术分享,侵权删,干货满满。
原文链接:Kaggle 知识点:时序模型 Prophet
Prophet
算法
在时间序列中Prophet
是Facebook开源的时间序列预测算法,可以有效处理节假日信息,并按周、月、年对时间序列数据的变化趋势进行拟合。
https://facebook.github.io/prophet/
# pip
python -m pip install prophet
# conda
conda install -c conda-forge prophet
截至2023年1月,这个Python包通过PyPI已被下载超过1600万次,每月下载量仍保持在100万次。
Prophet
对具有强烈周期性特征的历史数据拟合效果很好,不仅可以处理时间序列存在一些异常值的情况,也可以处理部分缺失值的情形。
模型定义
Prophet
使用了可分解的时间序列模型,模型包含三个主要组件:趋势、季节性和假日。它们通过以下方程组合在一起:
-
是趋势函数,用于模拟时间序列值的非周期性变化
-
表示周期性变化(例如每周和每年的季节性变化)
-
表示假日效应,这些假日在一个或多个不规则时间安排的日子内发生
-
误差项表示模型未能捕捉的变化
Prophet
适用场景
-
有至少几个月(最好是一年)的每小时、每天或每周观察的历史数据;
-
有多种人类规模级别的较强的季节性趋势:每周的一些天和每年的一些时间;
-
有事先知道的以不定期的间隔发生的重要节假日(比如国庆节);
-
缺失的历史数据或较大的异常数据的数量在合理范围内;
-
有历史趋势的变化(比如因为产品发布);
Prophet
出发点
Prophet
的出发点是提供一种灵活的、可解释的回归模型,该模型可以直观地由具有时间序列知识的分析师调整。这种模型的设计考虑了以下几个关键点:
-
易于使用:
Prophet
旨在使没有时间序列方法训练的大量人员也能进行预测。 -
灵活性:它能够适应具有潜在特殊特征的多种预测问题。
-
自动化与人工干预相结合:
Prophet
通过自动化的方式进行预测,同时在模型性能不佳或需要人工干预时,允许分析师进行调整。 -
大规模评估:在创建大量预测时,需要有效、自动化的方法来评估和比较预测结果,并检测可能表现不佳的情况。
-
可解释性:
Prophet
的参数具有直观的解释,使得即使非专家也能根据领域知识进行模型配置。
Prophet
模型的设计允许它捕捉时间序列数据中的多种特征,如趋势、季节性、假日效应等,同时提供了一种机制来评估预测性能并根据需要进行调整。
Prophet
使用案例
案例 1:拟合基础模型
import pandas as pd
from prophet import Prophet
# 需要有两列,ds 列和 y 列
df = pd.read_csv('https://mirror.coggle.club/prophet/example_wp_log_peyton_manning.csv')
# 定义模型,并训练
m = Prophet()
m.fit(df)
# 推理未来的日期,并镜像预测
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
-
模型预测结果
-
模型分解结果
案例2:自动识别趋势变化
实际的时间序列经常会在轨迹上发生突然变化。默认情况下,Prophet 会自动检测这些变化点,并允许趋势适当调整。
Prophet 通过首先指定大量潜在的变化点来检测变化点,在这些点上允许速率变化。默认情况下,Prophet 指定了 25 个潜在的变化点,这些变化点均匀地分布在时间序列的前 80% 部分。
import pandas as pd
from prophet import Prophet
df = pd.read_csv('https://mirror.coggle.club/prophet/example_wp_log_peyton_manning.csv')
m = Prophet()
fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)
案例 3:自定义节假日
如果你有假期或其他重复出现的事件需要建模,必须为它们创建一个数据框。数据框包含两列(holiday 和 ds),每行对应一次假期的发生。数据框必须包括假期的所有发生时间,既包括过去的(从历史数据开始)也包括未来的(预测范围内)。如果假期在未来不会重复,Prophet 会对其进行建模,但不会将其纳入预测中。
playoffs = pd.DataFrame({
'holiday': 'playoff',
'ds': pd.to_datetime(['2008-01-13', '2009-01-03', '2010-01-16',
'2010-01-24', '2010-02-07', '2011-01-08',
'2013-01-12', '2014-01-12', '2014-01-19',
'2014-02-02', '2015-01-11', '2016-01-17',
'2016-01-24', '2016-02-07']),
'lower_window': 0,
'upper_window': 1,
})
superbowls = pd.DataFrame({
'holiday': 'superbowl',
'ds': pd.to_datetime(['2010-02-07', '2014-02-02', '2016-02-07']),
'lower_window': 0,
'upper_window': 1,
})
special_days = pd.DataFrame({
'holiday': ['Christmas', 'Christmas Eve', 'Black Friday'],
'ds': ['2023-12-25', '2023-12-24', '2023-11-24'],
'lower_window': [0, -1, 0],
'upper_window': [0, 0, 1],
'prior_scale': [10, 5, 3]
})
holidays = pd.concat((playoffs, superbowls, special_days))
m = Prophet(holidays=holidays)
forecast = m.fit(df).predict(future)
案例4:多元回归
Prophet
使用 add_regressor 方法或函数将额外的回归变量添加到模型的线性部分。需要在拟合和预测的数据框中都包含一个带有回归变量值的列。
添加的额外回归因子必须对于历史数据和未来日期都是已知的。这意味着它要么是已知未来值的变量(,要么是在其他地方已经预测过的变量。
def nfl_sunday(ds):
date = pd.to_datetime(ds)
if date.weekday() == 6 and (date.month > 8 or date.month < 2):
return 1
else:
return 0
df['nfl_sunday'] = df['ds'].apply(nfl_sunday)
m = Prophet()
m.add_regressor('nfl_sunday')
m.fit(df)
future['nfl_sunday'] = future['ds'].apply(nfl_sunday)
forecast = m.predict(future)
fig = m.plot_components(forecast)
案例5:兼容缺失值
df = pd.read_csv('https://mirror.coggle.club/prophet/example_wp_log_R_outliers1.csv')
m = Prophet()
m.fit(df)
future = m.make_future_dataframe(periods=1096)
forecast = m.predict(future)
fig = m.plot(forecast)
处理异常值的最佳方法是将其从数据中移除。Prophet 可以很好地处理缺失数据。 Prophet 能够通过拟合趋势变化来处理历史数据中的异常值。不确定性模型可能会预期未来也会出现类似幅度的趋势变化,这可能导致预测区间变宽。
df.loc[(df['ds'] > '2010-01-01') & (df['ds'] < '2011-01-01'), 'y'] = None
model = Prophet().fit(df)
fig = model.plot(model.predict(future))
案例6:模型调参
import itertools
import numpy as np
import pandas as pd
param_grid = {
'changepoint_prior_scale': [0.001, 0.01, 0.1, 0.5],
'seasonality_prior_scale': [0.01, 0.1, 1.0, 10.0],
}
# Generate all combinations of parameters
all_params = [dict(zip(param_grid.keys(), v)) for v in itertools.product(*param_grid.values())]
rmses = [] # Store the RMSEs for each params here
df = pd.read_csv('https://mirror.coggle.club/prophet/example_retail_sales.csv')
# Use cross validation to evaluate all parameters
for params in all_params:
m = Prophet(**params).fit(df) # Fit model with given params
df_cv = cross_validation(m, cutoffs=cutoffs, horizon='30 days', parallel="processes")
df_p = performance_metrics(df_cv, rolling_window=1)
rmses.append(df_p['rmse'].values[0])
# Find the best parameters
tuning_results = pd.DataFrame(all_params)
tuning_results['rmse'] = rmses
print(tuning_results)
案例 7:模型微调
使用热启动技术可以在添加新数据时显著加快模型的拟合速度。热启动对于数据的小幅度更新(如例子中一天的数据)效果很好,但如果数据发生了较大变化(例如,添加了很多天的数据),热启动可能不如从头开始拟合模型来得有效。
def warm_start_params(m):
res = {}
for pname in ['k', 'm', 'sigma_obs']:
if m.mcmc_samples == 0:
res[pname] = m.params[pname][0][0]
else:
res[pname] = np.mean(m.params[pname])
for pname in ['delta', 'beta']:
if m.mcmc_samples == 0:
res[pname] = m.params[pname][0]
else:
res[pname] = np.mean(m.params[pname], axis=0)
return res
df = pd.read_csv('https://mirror.coggle.club/prophet/example_wp_log_peyton_manning.csv')
df1 = df.loc[df['ds'] < '2016-01-19', :] # All data except the last day
m1 = Prophet().fit(df1) # A model fit to all data except the last day
%timeit m2 = Prophet().fit(df) # Adding the last day, fitting from scratch
%timeit m2 = Prophet().fit(df, init=warm_start_params(m1)) # Adding the last day, warm-starting from m1
Prophet
参数含义与调参
参数含义
参数名称 | 说明 |
---|---|
growth | 趋势类型,可选值有 'linear', 'logistic', 或 'flat'。 |
changepoints | 变化点日期列表。如果未指定,将自动选择潜在变化点。 |
n_changepoints | 潜在变化点的数量。如果未指定 changepoints ,则在历史数据的前 changepoint_range 比例内均匀选择 |
changepoint_range | 用于估计趋势变化点的历史比例。 |
yearly_seasonality | 是否拟合年度季节性。可以是 'auto', True, False,或傅里叶项的数量。 |
weekly_seasonality | 是否拟合每周季节性。可以是 'auto', True, False,或傅里叶项的数量。 |
daily_seasonality | 是否拟合每日季节性。可以是 'auto', True, False,或傅里叶项的数量。 |
holidays | 包含假期数据的 pd.DataFrame , |
seasonality_mode | 季节性模式,可选值为 'additive'(加性)或 'multiplicative'(乘性)。 |
seasonality_prior_scale | 调节季节性模型强度的参数。值越大,模型可以拟合的季节性波动越大;值越小,季节性波动幅度越小。 |
holidays_prior_scale | 调节假期组件模型强度的参数,除非在假期输入中被覆盖。 |
changepoint_prior_scale | 调节自动变化点选择灵活性的参数。值越大,允许的变化点越多;值越小,允许的变化点越少。 |
interval_width | 预测的不确定区间的宽度。 |
uncertainty_samples | 用于估计不确定区间的模拟抽样数量。将此值设置为 0 或 False 将禁用不确定性估计并加快计算速度。 |
超参数调优
主要可调参数
-
changepoint_prior_scale:
-
作用:确定趋势的灵活性,特别是趋势在变化点的变化幅度。
-
默认值:0.05
-
调优范围:[0.001, 0.5]
-
说明:值越大,趋势变化越灵活,过大可能导致过拟合,过小可能导致欠拟合。
-
-
seasonality_prior_scale:
-
作用:控制季节性的灵活性。
-
默认值:10
-
调优范围:[0.01, 10]
-
说明:值越大,季节性变化越大,值越小,季节性幅度越小。
-
-
holidays_prior_scale:
-
作用:控制假期效应的灵活性。
-
默认值:10
-
调优范围:[0.01, 10]
-
说明:与季节性灵活性类似,调整假期效应的幅度。
-
-
seasonality_mode:
-
作用:季节性的模式,可以选择加性(
'additive'
)或乘性('multiplicative'
)。 -
默认值:
'additive'
-
说明:商业时间序列中,季节性变化随时间序列幅度变化的情况适合乘性模式。
-
可能需要调优的参数
-
changepoint_range:
-
作用:确定趋势变化的历史比例。
-
默认值:0.8(80% 的历史数据)
-
调优范围:[0.8, 0.95]
-
说明:增加该参数可能有助于避免在时间序列末尾过拟合。
-
一般不需要调优的参数
-
growth:选择增长模式('linear' 或 'logistic')。
-
changepoints:手动指定变化点位置。
-
n_changepoints:自动放置的变化点数量,默认 25。
-
yearly_seasonality:是否启用年度季节性(默认 'auto')。
-
weekly_seasonality:是否启用每周季节性(默认 'auto')。
-
daily_seasonality:是否启用每日季节性(默认 'auto')。
-
holidays:传入指定假期的数据框。
-
mcmc_samples:是否使用 MCMC,取决于时间序列的长度和参数不确定性的重要性。
-
interval_width:指定预测区间的宽度(默认 0.8,对应 80% 置信区间)。
-
uncertainty_samples:用于计算不确定性区间的样本数量,默认 1000。
THE END !
文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。