如题所述
这是创建和调整预测模型的基础教程。旨在为0基础的用户提供一些基本sense。
你可以使用 PROPHET 或 SILVERKITE 模型,本文注重介绍 SILVERKITE 模型。
SILVERKITE 将时间序列分解为多个组件,并创建基于时间的特征、自回归特征以及用户提供的特征,如宏观经济特征及其相互作用,然后执行机器学习回归模型,以了解时间序列与这些特征之间的关系。预测基于已学习的关系和这些特征的未来值。因此,包含正确的特征是成功的关键。
常见特征包括:
包含从datetime衍生出来的特征,比如 day of year , hour of day , weekday , is_weekend 等等。这些特征在捕获特殊模式的时候时有用的。比如,对于大多数的商业相关数据,周末与否具有不同的模式。
首先定义了基本特征“ct1”,它以年为单位计算从训练数据的第一天起经过的时间(可以是分数)。比如,如果训练数据从"2018-01-01"开始,那么"2018-01-01"就有 ct1=0.0 ,"2018-01-02" 就是 ct1=1/365 ,"2019-01-01" 就是 ct1=1.0 。 ct1 的颗粒度可以根据需求定义。可以对 ct1 应用一个独立的生长函数,比如,可以定义 ct2 为 ct1 的平方,用来给指数生长建模。
Trend趋势描述时间序列的平均趋势。它是通过具有可能变化点的增长项定义的。在每个变化点,增长率都可能发生变化(更快或更慢)。例如,如果“ct1”(线性增长)与变更点一起使用,则趋势将建模为分段线性。
Seasonality周期性描述了时间序列的周期性模式。它包含多个层次,包括每日周期性、每周周期性、每月周期性、季度周期性和年度周期性。周期性通过不同阶次的傅立叶级数定义。阶次越大,模型可以学习的周期模式就越详细。但是,阶次过大可能会导致过拟合。
Events包括假期和其他可能暂时影响时间序列的短期事件,例如感恩节长周末。通常情况下,事件是有规律的,并在将来的已知时间重复。这些特征由涵盖活动日及其相邻日期的指标组成
自回归特征包括过去的时间序列观测及其聚合。例如,可以使用过去一天的观察、过去一周的同一工作日或过去7天的平均值等。请注意,自回归功能在短期预测中非常有用,但在长期预测中应避免使用。原因是长期预测更注重趋势、季节性和事件的正确性。根据预测值计算长期预测中的滞后项和自回归项。我们对未来的预测越深入,创建自回归项所需的预测值就越多,使预测越不稳定
与时间序列相关的额外特征,如预期会影响时间序列的宏观经济特征。请注意,这些功能需要在训练和预测期间手动提供。
上述特征之间的任何耦合
现在让我们用一个例子来过一下整个的创建和调整过程吧。用到的数据是Peyton Manning维基百科页面的浏览数据。
数据集范围是从2007-12-10 到 2016-01-20。
将df数据加载到UnivariateTimeSeries中,创建一个UnivariateTimeSeries对象。这个ts对象就可以方便地进行探索性数据分析和绘图。
绘制原始数据的时序图。
基于数据集可以创建一个简单的预测模型,注意如果你不提供任何额外的参数,所有的模型参数都是默认的。
默认参数都是取的比较保守的,所以可以将这个作为一个baseline模型来评估预测难度,必要时进行进一步改进。
简单预测模型的详细过程可以参考: https://www.jianshu.com/p/2c40becc7ae2
绘制出预测曲线
我们可以看到预测模型对于已有的数据吻合较好,但是我们没有证据说他对未来预测得很好。
训练集-测试集拆分
一般来说,评价模型的性能是将训练集保留一部分,然后用这部分来评价模型的性能。
因为我们总是预测未来的数据,所以我们将训练数据集从后往前保留一部分出来,用来作为测试集。
默认的, run_forecast_config 返回的结果就会创建一个训练-测试的拆分,并且把测试结果放在 result.backtest 。
测试集的范围跟我们要预测的时间范围默认是一致的。我们可以拿到评价结果:
评价指标
从这里,我们就可以看到模型对于测试集的预测性能。你可以关注其中的一个或几个指标。通常包括:
MSE:
均方误差。可能受到极值的影响。
RMSE:
均方根误差,MSE的平方根
MAE:
平均绝对误差,绝对误差的平均值。可能受到极值的影响。
MedAE:
中位数绝对误差,绝对误差的中位数。受极值影响较小。
MAPE:
平均绝对百分比误差,测量与真实值相对应的误差百分比。当您想考虑相对误差而不是绝对误差时,这很有用。例如,对于真实观测值10,误差1被视为10%,但对于真实观测值100,误差1被视为1%。 这是我们喜欢的默认指标 。
MedAPE:
中值绝对百分比误差,MAPE的中值版本,受极值影响较小。
让我们在本例中使用MAPE作为度量标准。看这些结果可以大概知道模型对于未知数据的预测效果。平均而言,基线模型的预测值与真实值相差11.3%。
时间序列交叉验证
预测质量在很大程度上取决于评估时间窗口。上面选择的评估窗口可能恰好是一个相对容易/难以预测的时期。因此,在数据集大小允许的情况下,在较长的时间窗口内进行评估更为稳健。让我们考虑一种更通用的评估预测模型的方法:时间序列交叉验证。
时间序列交叉验证是基于时间序列滚动拆分。比如说,我们想通过三重交叉验证进行评估,整个训练数据以3种不同的方式进行分割。由于我们的预测期限为365天,我们会:
第一折:训练 2007-12-10 to 2013-01-20,预测2013-01-21 to 2014-01-20,并对比预测值和实际值
第一折:训练 2007-12-10 to 2014-01-20,预测2014-01-21 to 2015-01-20,并对比预测值和实际值
第一折:训练 2007-12-10 to 2015-01-20,预测2015-01-21 to 2016-01-20,并对比预测值和实际值
拆分方式是可以灵活调整的,可以看帮助,在此不详述。
预测模型的性能就是三次评估的平均值。
默认的, run_forecast_config 返回的结果也已经在内部跑过交叉验证了。
你可以自己配置交叉验证的参数,这里要注意 test_horizon 数据从后面开始保留的数据,不用作交叉验证。
当我们调参时,就是要选择交叉验证性能最好的那一组参数。
现在你已经知道了如何评价模型的性能,让我们看看能否通过调参来提升模型性能吧。
异常
异常是指预计未来不会再次发生的指标偏差。异常点将导致模型将异常作为时间序列的固有属性进行拟合,从而导致预测不准确。可以通过叠加图overlays识别这些异常。
从上面的的重叠图,我们可以看到有两个比较大的异常数据:2012年3月和2010年6月。其他小的异常数据也能被检测到,但是他们的影响比较小。 SILVERKITE 模板现在支持通过提供 anomaly_info 字典来屏蔽异常点。你可以调整这些数值,或者直接赋空值(在这种情况下,异常点就不会被用来拟合)。
详细的介绍可以看 /pages/stepbystep/0300_input 。
这里,我们定义一个 anomaly_df DataFrame,用来把异常点屏蔽为空值,并且将它打包到 anomaly_info 字典里面。
添加相关特征
Growth and trend
生长和趋势
首先我们看生长growth和趋势trend。growth的细节配置可以看 /pages/model_components/0200_growth 。
在这两个特征里面,我们更关注长期的趋势。从原始数据的图可以看到,没有明显的增长模式,所以我们可以使用线性增长来拟合模型。
另一方面,可能会有潜在的趋势变化点,在这些趋势变化点上,线性增长模型会改变斜率。
changepoint变化点的细节可以看 /pages/model_components/0500_changepoints 。
这些变化点可以通过 ChangepointDetector 类检测到。可以看 Changepoint detection <../quickstart/0200_changepoint_detection.html> 。
这里我们探索一下 自动变化点检测 。
这个自动变化点检测的参数,是为本数据集做的定制。
从图中我们可以看到自动检测的趋势变化点。结果显示,在2012年之前整体趋势都是上涨的,然后整体就是下降的。
如果我们把趋势变化点的参数喂给模型,这些趋势变化特征就会自动加入到模型里面。
Seasonality
周期性特征
接下来我们看看周期性特征。配置详情可以看 /pages/model_components/0300_seasonality 。快速案例可以看 Seasonality Detection <../quickstart/0300_seasonality.html>
本例周期特征项的总结如下:
因此,为了净化季节性特征项,我们包括了weekly 和 yearly,季节性的阶次是可以调整的。这里我们把周的阶次调整为5,年的阶次调整为10.
调整信息可以参考 /pages/model_components/0300_seasonality
我们后面还会把周的特征跟足球赛季特征的耦合交互也加到模型里来。
SILVERKITE 模型也支持周期性的变化点,在该时间点之后,周期性效应表现出不同的行为。对于 SILVERKITE 模型,这意味着允许更改傅里叶级数系数。如果交叉验证性能较差,并且在探索性分析中检测到季节性变化点,我们可以决定添加此功能。
有关详细信息,请参阅:doc: /gallery/quickstart/0200\u changepoint\u detection 。
Holidays and events
假日和事件
然后我们看看假日和事件。细节的假日和事件配置可以看 /pages/model_components/0400_events 。
问问你自己,哪些假日有可能会影响时序值。我们觉得,美国主要假期会影响到维基百科页面的浏览,因为大部分的足球球迷在美国。(这个数据集是球星的百科页面浏览量,所以这么说。)
一些事件,比如超级碗,也可能提高页面的浏览量。因此,我们把美国假期和超级碗的日期添加进来,作为自定义事件。
通过年度周期图 Seasonality <../quickstart/0300_seasonality.html> ,其他影响时序值的重要事件也可以被发现。
其中holiday_lookup_countries可以选择的国家中,有"China"可以选择。自带了中国的公共假期。
Autoregression
自回归
自回归特征在短期预测中非常有用,但是在长期预测中可能会有风险。详情见 /pages/model_components/0800_autoregression
Custom
自定义
现在我们来考虑一些跟页面浏览可能相关的自定义特征。这里可以看到额外回归器的文档 /pages/model_components/0700_regressors 。
我们观察到足球赛季严重影响页面浏览量,因此我们需要使用回归函数来识别足球赛季。
有多种方法可以包含此功能:添加整个季节的指标;添加截至季节开始(结束)的天数和自季节开始(结束)的天数。
前者对所有季内日期都有一致的影响,而后者量化了赛季开始和结束的不同影响。
如果您不确定要包含哪个效果,那么可以同时包含这两个效果。
SILVERKITE 可以选用岭回归(Ridge regression)来作为拟合算法,以避免过拟合太多的特征。
注意很多的时间特征也可以被加到模型里面, SILVERKITE calculates some of these features, which can be added to
extra_pred_cols as an arbitrary patsy expression.(这句话没看懂)这些特征的完整列表可以看 ~greykite.common.features.timeseries_features.build_time_features_df
如果特征没有被 SILVERKITE 自动创建,我们需要事先创建它并将其附加到数据df中。
这里我们创建了"is_football_season"的特征。
请注意,我们也需要为预测期间提供自定义列。
具体方法,是首先创建一个df,覆盖预测期间的timestamps,这个可以通过 UnivariateTimeSeries 类中的 .make_future_dataframe 函数实现,
然后,我们为这个df创建自定义回归器的新列。
Interactions
交互耦合
最后,让我们考虑一下预测问题的交互耦合。通常说,如果一个特征会受到另一个特征的影响,那么这两个特征就有现在的耦合关系。
就像 Seasonality <../quickstart/0300_seasonality.html> 中提到的,weekly的周期性受到了是否足球赛季的影响。
因此,乘法项 is_football_season x weekly_seasonality 可以捕捉到这个模式。
seasonality周期性特征和其他特征的耦合,可以使用 cols_interact 函数创建。
另外,乘法项 month x weekly_seasonality 和 dow_woy 特征也会对weekly的周期性产生影响,也可以加上这些特征,但这里我们不管。
你可以再次使用 cols_interact 来创建 month x weekly_seasonality ,就跟前面的 is_football_season x weekly_seasonality 类似。
dow_woy 是 SILVERKITE 自动计算的,你可以简单地把名字append到 extra_pred_cols 上。
Putting things together
把东西放到一起
现在,让我们把这些东西都放在一起,创建新的预测模型。详情可以看 /pages/stepbystep/0400_configuration 。
我们首先配置 MetadataParam 类,这个类包括了时间序列本身的基本属性。
接下来,我们定义 ModelComponentsParam 类,这个类包含了跟模型本身相关的属性。
现在,让我们用新的配置来跑模型。评估模型的参数使用跟前面一致的,这样调参对比起来更公平。
现在,我们可以看到,在分析了问题并且增加了合适特征之后,交叉验证的测试MAPE是5.4%,比baseline的7.3%更好了。
三折的MAPE分别是3.9%, 8.7% and 3.8%。第一折提高最显著。研究一下可以发现第二折没有提高,这是因为在测试周期刚开始的时候,刚好有一个趋势变化点。除非我们看到,否则很难预知这样的情况。
在交叉验证的步骤中,避免这个情况的方式,是设置不同的评价时段。但是不管这个时间段也是可以的,因为未来还有可能再次发生。
在预测时段,我们可以监控预测和实际值,并且根据最新的数据模式重新训练模型。在changepoints变化点的字典中,相应的调整 regularization_strength 和 no_changepoint_distance_from_end ,或将手动指定的变更点添加到自动检测的变更点。详情见 /pages/model_components/0500_changepoints 。
我们也可以绘制预测图。
为了进一步研究模型机制,看一看模型的summary也是有帮助的。
ModelSummary 模块提供了模型的估计值、显著性、p值、置信区间等。这些可以帮助用户理解模型如何工作以及如何做进一步提升。
模型summary是一种类方法,可按如下方式使用。
模型摘要显示了模型信息、系数及其重要性以及一些摘要统计信息。例如,我们可以看到变化点以及增长率在每个变化点的变化程度。
我们可以看到一些假期在模型中有显著的影响,如圣诞节、劳动节、感恩节等。我们可以看到足球赛季和每周季节性之间相互作用的重要性等。有关模型摘要的更详细指南,请参阅:doc: /gallery/quickstart/0400\u model\u summary
在这个示例之后,您可能对如何选择参数和优化模型有一些了解。
这里我们列出了一些可能有助于选择最佳模型的步骤和技巧。
您可以做什么:
( ~greykite.framework.input.univariate_time_series.UnivariateTimeSeries.plot_quantiles_and_overlays ).
把这些点赋值NA,除非你对修正异常值很有信心。
如果没有一个典型的增长形状符合时间序列,则可以考虑具有趋势变化点的线性增长。尝试不同的变更点检测配置。您还可以绘制检测到的变更点,并查看其对您是否有意义。该模板还支持自定义变更点。如果自动变更点检测结果对您没有意义,您可以提供自己的变更点
阶次越高,学习的细节越多,但是阶次太高会导致过拟合。这些也可以通过叠加图overlay plots来发现。没有一种统一的方法来选择周期性,因此探索不同的周期性阶次并比较结果。
是否需要增加自定义的事件?如果要增加自定义事件,记得也要加上预测时段。
请注意,您还需要提供预测期内回归系数的值。你可以使用另一个时间序列作为回归器,只要你有一个覆盖你预测期的基本事实/良好预测。
如果两个特征之间具有相关性,那么这两个特征就是耦合的。比如“是否足球赛季”与“week的周期性”是耦合的。也可以试试使用叠加图overlay plot plot_quantiles_and_overlays 。默认的,我们有一些预先定义好的耦合项,参看 feature_set_enabled <../../pages/model_components/0600_custom.html#interactions>
这是给特征和事件序列之间建模的算法,可选算法的完整列表可以看 fit_algorithm <../../pages/model_components/0600_custom.html#fit-algorithm>
如果你不知道他们的区别,可以试一试比较结果,如果你不想试,就用"ridge",岭回归算法,这是一个安全的选择。
值得注意的是,该模板支持使用不同的参数集进行自动网格搜索。对于每个参数,如果在列表中提供配置,它将自动运行每个组合并选择交叉验证性能最好的一个。这将节省大量时间。有关详细信息,请参阅 grid search <../quickstart/0500_grid_search.html> 。
遵循你的洞察力和直觉,并利用这些参数,你会得到很好的预测结果!