Greykite模型的优化调参

给你的第一个Greykite预测模型调参

这是创建和调整预测模型的基础教程。旨在为0基础的用户提供一些基本sense。

你可以使用PROPHETSILVERKITE 模型,本文注重介绍SILVERKITE模型。

SILVERKITE 将时间序列分解为多个组件,并创建基于时间的特征、自回归特征以及用户提供的特征,如宏观经济特征及其相互作用,然后执行机器学习回归模型,以了解时间序列与这些特征之间的关系。预测基于已学习的关系和这些特征的未来值。因此,包含正确的特征是成功的关键。

常见特征包括:

  • Datetime derivatives日期衍生:

包含从datetime衍生出来的特征,比如day of year,hour of day,weekday, is_weekend 等等。这些特征在捕获特殊模式的时候时有用的。比如,对于大多数的商业相关数据,周末与否具有不同的模式。

  • Growth生长:

首先定义了基本特征“ct1”,它以年为单位计算从训练数据的第一天起经过的时间(可以是分数)。比如,如果训练数据从"2018-01-01"开始,那么"2018-01-01"就有ct1=0.0,"2018-01-02" 就是 ct1=1/365,"2019-01-01" 就是ct1=1.0ct1的颗粒度可以根据需求定义。可以对ct1应用一个独立的生长函数,比如,可以定义ct2ct1的平方,用来给指数生长建模。

  • Trend趋势:

Trend趋势描述时间序列的平均趋势。它是通过具有可能变化点的增长项定义的。在每个变化点,增长率都可能发生变化(更快或更慢)。例如,如果“ct1”(线性增长)与变更点一起使用,则趋势将建模为分段线性。

  • Seasonality周期性:

Seasonality周期性描述了时间序列的周期性模式。它包含多个层次,包括每日周期性、每周周期性、每月周期性、季度周期性和年度周期性。周期性通过不同阶次的傅立叶级数定义。阶次越大,模型可以学习的周期模式就越详细。但是,阶次过大可能会导致过拟合。

  • Events事件:

Events包括假期和其他可能暂时影响时间序列的短期事件,例如感恩节长周末。通常情况下,事件是有规律的,并在将来的已知时间重复。这些特征由涵盖活动日及其相邻日期的指标组成

  • Autoregression自回归特征:

自回归特征包括过去的时间序列观测及其聚合。例如,可以使用过去一天的观察、过去一周的同一工作日或过去7天的平均值等。请注意,自回归功能在短期预测中非常有用,但在长期预测中应避免使用。原因是长期预测更注重趋势、季节性和事件的正确性。根据预测值计算长期预测中的滞后项和自回归项。我们对未来的预测越深入,创建自回归项所需的预测值就越多,使预测越不稳定

  • Custom自定义特征:

与时间序列相关的额外特征,如预期会影响时间序列的宏观经济特征。请注意,这些功能需要在训练和预测期间手动提供。

  • Interactions耦合:

上述特征之间的任何耦合

现在让我们用一个例子来过一下整个的创建和调整过程吧。用到的数据是Peyton Manning维基百科页面的浏览数据。
数据集范围是从2007-12-10 到 2016-01-20。

import datetime

import numpy as np
import pandas as pd
import plotly

from greykite.common.data_loader import DataLoader
from greykite.algo.changepoint.adalasso.changepoint_detector import ChangepointDetector
from greykite.algo.forecast.silverkite.constants.silverkite_holiday import SilverkiteHoliday
from greykite.algo.forecast.silverkite.constants.silverkite_seasonality import SilverkiteSeasonalityEnum
from greykite.algo.forecast.silverkite.forecast_simple_silverkite_helper import cols_interact
from greykite.common import constants as cst
from greykite.common.features.timeseries_features import build_time_features_df
from greykite.common.features.timeseries_features import convert_date_to_continuous_time
from greykite.framework.benchmark.data_loader_ts import DataLoaderTS
from greykite.framework.templates.autogen.forecast_config import EvaluationPeriodParam
from greykite.framework.templates.autogen.forecast_config import ForecastConfig
from greykite.framework.templates.autogen.forecast_config import MetadataParam
from greykite.framework.templates.autogen.forecast_config import ModelComponentsParam
from greykite.framework.templates.forecaster import Forecaster
from greykite.framework.templates.model_templates import ModelTemplateEnum
from greykite.framework.utils.result_summary import summarize_grid_search_results
from greykite.framework.input.univariate_time_series import UnivariateTimeSeries
dl = DataLoader()
df = dl.load_peyton_manning()
df
df

探索性数据分析 (EDA)

将df数据加载到UnivariateTimeSeries中,创建一个UnivariateTimeSeries对象。这个ts对象就可以方便地进行探索性数据分析和绘图。

ts = UnivariateTimeSeries()
ts.load_data(
    df=df,
    time_col="ts",
    value_col="y",
    freq="D")  # optional, but recommended if you have missing data points
               # W for weekly, D for daily, H for hourly, etc. See ``pd.date_range``
# describe
print(ts.describe_time_col())
print(ts.describe_value_col())
ts.describe

绘制原始数据的时序图。

fig = ts.plot()
plotly.io.show(fig)
原始时序图

Baseline 模型

基于数据集可以创建一个简单的预测模型,注意如果你不提供任何额外的参数,所有的模型参数都是默认的。
默认参数都是取的比较保守的,所以可以将这个作为一个baseline模型来评估预测难度,必要时进行进一步改进。
简单预测模型的详细过程可以参考:https://www.jianshu.com/p/2c40becc7ae2

# 忽略警告 
from collections import defaultdict
import warnings

warnings.filterwarnings("ignore")
# Specifies dataset information定义数据集参数
metadata = MetadataParam(
    time_col="ts",  # name of the time column
    value_col="y",  # name of the value column
    freq="D"  # "H" for hourly, "D" for daily, "W" for weekly, etc.
)
# 创建预测模型
forecaster = Forecaster()
result = forecaster.run_forecast_config(
    df=df,
    config=ForecastConfig(
        model_template=ModelTemplateEnum.SILVERKITE.name,
        forecast_horizon=365,  # forecasts 365 steps ahead
        coverage=0.95,  # 95% prediction intervals
        metadata_param=metadata
    )
)

绘制出预测曲线

forecast = result.forecast
fig = forecast.plot()
plotly.io.show(fig)
预测结果

模型性能评价

我们可以看到预测模型对于已有的数据吻合较好,但是我们没有证据说他对未来预测得很好。

训练集-测试集拆分

一般来说,评价模型的性能是将训练集保留一部分,然后用这部分来评价模型的性能。
因为我们总是预测未来的数据,所以我们将训练数据集从后往前保留一部分出来,用来作为测试集。

默认的,run_forecast_config返回的结果就会创建一个训练-测试的拆分,并且把测试结果放在result.backtest
测试集的范围跟我们要预测的时间范围默认是一致的。我们可以拿到评价结果:

pd.DataFrame(result.backtest.test_evaluation, index=["Value"]).transpose()  # formats dictionary as a pd.DataFrame
模型性能指标

评价指标

从这里,我们就可以看到模型对于测试集的预测性能。你可以关注其中的一个或几个指标。通常包括:

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数据从后面开始保留的数据,不用作交叉验证。

# 定义模型评估的参数,这个其实不是必须的,可以默认
evaluation_period = EvaluationPeriodParam(
    test_horizon=365,             # 留下365天用作测试集
    cv_horizon=365,               # 每个交叉验证的折是365天 (跟预测周期一致)
    cv_max_splits=3,              # 3折交叉验证
    cv_min_train_periods=365 * 4  # 使用最少4年的数据作为训练集,因为我们总共有8年的数据
)

# 跑预测模型
result = forecaster.run_forecast_config(
    df=df,
    config=ForecastConfig(
        model_template=ModelTemplateEnum.SILVERKITE.name,
        forecast_horizon=365,  # forecasts 365 steps ahead
        coverage=0.95,  # 95% prediction intervals
        metadata_param=metadata,
        evaluation_period_param=evaluation_period
    )
)

# 总结交叉验证的结果
cv_results = summarize_grid_search_results(
    grid_search=result.grid_search,
    decimals=1,
    # The below saves space in the printed output. Remove to show all available metrics and columns.
    cv_report_metrics=None,
    column_order=["rank", "mean_test", "split_test", "mean_train", "split_train", "mean_fit_time", "mean_score_time", "params"])
# Transposes to save space in the printed output
cv_results["params"] = cv_results["params"].astype(str)
cv_results.set_index("params", drop=True, inplace=True)
cv_results.transpose()

交叉验证评价指标

默认会对所有的交叉验证拆分,计算全部的评价指标。这里我们只展示最常看的MAPE。
从结果我们可以看到,交叉验证的mean_test_MAPE 是 7.3%,意思是我们的预测值跟实际值有平均7.3%的误差。
我们也能看到3个折的误差分别是5.1%, 8.5% 和 8.4%。

当我们调参时,就是要选择交叉验证性能最好的那一组参数。

开始调参

现在你已经知道了如何评价模型的性能,让我们看看能否通过调参来提升模型性能吧。

异常

异常是指预计未来不会再次发生的指标偏差。异常点将导致模型将异常作为时间序列的固有属性进行拟合,从而导致预测不准确。可以通过叠加图overlays识别这些异常。

fig = ts.plot_quantiles_and_overlays(
    groupby_time_feature="month_dom",
    show_mean=True,
    show_quantiles=False,
    show_overlays=True,
    overlay_label_time_feature="year",
    overlay_style={"line": {"width": 1}, "opacity": 0.5},
    center_values=True,
    xlabel="day of year",
    ylabel=ts.original_value_col,
    title="yearly seasonality for each year (centered)",
)
plotly.io.show(fig)
叠加图

从上面的的重叠图,我们可以看到有两个比较大的异常数据:2012年3月和2010年6月。其他小的异常数据也能被检测到,但是他们的影响比较小。SILVERKITE模板现在支持通过提供anomaly_info字典来屏蔽异常点。你可以调整这些数值,或者直接赋空值(在这种情况下,异常点就不会被用来拟合)。
详细的介绍可以看/pages/stepbystep/0300_input
这里,我们定义一个anomaly_dfDataFrame,用来把异常点屏蔽为空值,并且将它打包到anomaly_info字典里面。

anomaly_df = pd.DataFrame({
    # start and end date are inclusive
    # each row is an anomaly interval
    cst.START_DATE_COL: ["2010-06-05", "2012-03-01"],  # inclusive
    cst.END_DATE_COL: ["2010-06-20", "2012-03-20"],  # inclusive
    cst.ADJUSTMENT_DELTA_COL: [np.nan, np.nan],  # mask as NA
})
# Creates anomaly_info dictionary.
# This will be fed into the template.
anomaly_info = {
    "value_col": "y",
    "anomaly_df": anomaly_df,
    "adjustment_delta_col": cst.ADJUSTMENT_DELTA_COL,
}

添加相关特征

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>

这里我们探索一下自动变化点检测

这个自动变化点检测的参数,是为本数据集做的定制。

  • 我们保持yearly_seasonality_order不变,作为年度周期特征的阶次。
  • regularization_strength正则化强度控制了检测出多少个变化点。0.5是一个好选择,你也可以改成0.4或者0.6来看看区别。
  • resample_freq被设置为7天,因为我们有很长的历史数据,所以我们要把这个数据设定得相对长。(直觉是比较短的改变会被忽略)
  • 我们放了25个潜在的变化点,因为我们不想要太多的变化。但是这有可能更高。
  • yearly_seasonality_change_freq被设置为365天,这意味着我们每年都要重新调整年度季节性,因为从时间序列图可以看出,年度季节性每年都在变化。
  • no_changepoint_distance_from_end被设置为365天,这意味着我们不允许在过去365天的训练数据中有任何变化点。这避免了拟合最终趋势的时候数据太少。对于长期的预测,这通常是等于要预测的时间周期,对于短期预测,这个可以是预测周期的数倍。
model = ChangepointDetector()
res = model.find_trend_changepoints(
    df=df,  # data df
    time_col="ts",  # time column name
    value_col="y",  # value column name
    yearly_seasonality_order=10,  # yearly seasonality order, fit along with trend
    regularization_strength=0.5,  # between 0.0 and 1.0, greater values imply fewer changepoints, and 1.0 implies no changepoints
    resample_freq="7D",  # data aggregation frequency, eliminate small fluctuation/seasonality
    potential_changepoint_n=25,  # the number of potential changepoints
    yearly_seasonality_change_freq="365D",  # varying yearly seasonality for every year
    no_changepoint_distance_from_end="365D")  # the proportion of data from end where changepoints are not allowed
fig = model.plot(
    observation=True,
    trend_estimate=False,
    trend_change=True,
    yearly_seasonality_estimate=False,
    adaptive_lasso_estimate=True,
    plot=False)
plotly.io.show(fig)
趋势变化点检查

从图中我们可以看到自动检测的趋势变化点。结果显示,在2012年之前整体趋势都是上涨的,然后整体就是下降的。
如果我们把趋势变化点的参数喂给模型,这些趋势变化特征就会自动加入到模型里面。

# The following specifies the growth and trend changepoint configurations.
growth = {
    "growth_term": "linear"
}
changepoints = {
    "changepoints_dict": dict(
        method="auto",
        yearly_seasonality_order=10,
        regularization_strength=0.5,
        resample_freq="7D",
        potential_changepoint_n=25,
        yearly_seasonality_change_freq="365D",
        no_changepoint_distance_from_end="365D"
    )
}

Seasonality
周期性特征

接下来我们看看周期性特征。配置详情可以看/pages/model_components/0300_seasonality。快速案例可以看Seasonality Detection <../quickstart/0300_seasonality.html>

本例周期特征项的总结如下:

  • daily 的季节特征不可用(因为频率是每日)
  • weekly 和 yearly的模式很明显(weekly与足球赛季也是有关的)
  • monthly 和 quarterly的模式不明显

因此,为了净化季节性特征项,我们包括了weekly 和 yearly,季节性的阶次是可以调整的。这里我们把周的阶次调整为5,年的阶次调整为10.
调整信息可以参考/pages/model_components/0300_seasonality

# Includes yearly seasonality with order 10 and weekly seasonality with order 5.
# Set the other seasonality to False to disable them.
yearly_seasonality_order = 10
weekly_seasonality_order = 5
seasonality = {
    "yearly_seasonality": yearly_seasonality_order,
    "quarterly_seasonality": False,
    "monthly_seasonality": False,
    "weekly_seasonality": weekly_seasonality_order,
    "daily_seasonality": False
}

我们后面还会把周的特征跟足球赛季特征的耦合交互也加到模型里来。
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"可以选择。自带了中国的公共假期。

# Includes major holidays and the superbowl date.
events = {
    # These holidays as well as their pre/post dates are modeled as individual events.
    "holidays_to_model_separately": SilverkiteHoliday.ALL_HOLIDAYS_IN_COUNTRIES,  # all holidays in "holiday_lookup_countries"
    "holiday_lookup_countries": ["UnitedStates"],  # only look up holidays in the United States
    "holiday_pre_num_days": 2,  # also mark the 2 days before a holiday as holiday
    "holiday_post_num_days": 2,  # also mark the 2 days after a holiday as holiday
    "daily_event_df_dict": {
        "superbowl": pd.DataFrame({
            "date": ["2008-02-03", "2009-02-01", "2010-02-07", "2011-02-06",
                     "2012-02-05", "2013-02-03", "2014-02-02", "2015-02-01", "2016-02-07"],  # 数据必须要覆盖训练和预测周期.
            "event_name": ["event"] * 9  # labels
        })
    },
}

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创建自定义回归器的新列。

# Makes augmented df with forecast horizon 365 days
# 创建扩展df
df_full = ts.make_future_dataframe(periods=365)
# Builds "df_features" that contains datetime information of the "df"
df_features = build_time_features_df(
    dt=df_full["ts"],
    conti_year_origin=convert_date_to_continuous_time(df_full["ts"][0])
)

# Roughly approximates the football season.
# "woy" is short for "week of year", created above.
# Football season is roughly the first 6 weeks and last 17 weeks in a year.
# df_full就是在原来df的基础上,增加了一列“is_football_season”,并且时间覆盖到预测的周期。
# 足球赛季一般都是一年的前6周和后17周。
is_football_season = (df_features["woy"] <= 6) | (df_features["woy"] >= 36)
# Adds the new feature to the dataframe.
df_full["is_football_season"] = is_football_season.astype(int).tolist()
df_full.reset_index(drop=True, inplace=True)

# Configures regressor column.
regressors = {
    "regressor_cols": ["is_football_season"]
}

Interactions
交互耦合

最后,让我们考虑一下预测问题的交互耦合。通常说,如果一个特征会受到另一个特征的影响,那么这两个特征就有现在的耦合关系。
就像Seasonality <../quickstart/0300_seasonality.html>中提到的,weekly的周期性受到了是否足球赛季的影响。
因此,乘法项is_football_season x weekly_seasonality可以捕捉到这个模式。

fig = ts.plot_quantiles_and_overlays(
    groupby_time_feature="str_dow",
    show_mean=True,
    show_quantiles=False,
    show_overlays=True,
    center_values=True,
    overlay_label_time_feature="month",  # splits overlays by month
    overlay_style={"line": {"width": 1}, "opacity": 0.5},
    xlabel="day of week",
    ylabel=ts.original_value_col,
    title="weekly seasonality by month",
)
plotly.io.show(fig)

weekly周期性与月份的耦合

现在让我们创建is_football_seasonweekly seasonality之间的耦合吧。

seasonality周期性特征和其他特征的耦合,可以使用cols_interact函数创建。

football_week = cols_interact(
    static_col="is_football_season",
    fs_name=SilverkiteSeasonalityEnum.WEEKLY_SEASONALITY.value.name,
    fs_order=weekly_seasonality_order,
    fs_seas_name=SilverkiteSeasonalityEnum.WEEKLY_SEASONALITY.value.seas_names
)

extra_pred_cols = football_week

另外,乘法项month x weekly_seasonalitydow_woy特征也会对weekly的周期性产生影响,也可以加上这些特征,但这里我们不管。
你可以再次使用cols_interact来创建month x weekly_seasonality,就跟前面的is_football_season x weekly_seasonality类似。
dow_woySILVERKITE自动计算的,你可以简单地把名字append到extra_pred_cols上。

Putting things together
把东西放到一起

现在,让我们把这些东西都放在一起,创建新的预测模型。详情可以看/pages/stepbystep/0400_configuration
我们首先配置MetadataParam 类,这个类包括了时间序列本身的基本属性。

metadata = MetadataParam(
    time_col="ts",              # column name of timestamps in the time series df
    value_col="y",              # column name of the time series values
    freq="D",                   # data frequency, here we have daily data
    anomaly_info=anomaly_info,  # 这是我们前面定义好的异常点信息
    train_end_date=datetime.datetime(2016, 1, 20)
)

接下来,我们定义ModelComponentsParam类,这个类包含了跟模型本身相关的属性。

model_components = ModelComponentsParam(
    seasonality=seasonality,
    growth=growth,
    events=events,
    changepoints=changepoints,
    autoregression=None,
    regressors=regressors,  # 前面定义的is_football_season 
    uncertainty={
        "uncertainty_dict": "auto",
    },
    custom={
        # 时间序列和特征之间关系,使用什么学习算法
        # 建议使用正则化拟合算法来缓解高相关性和过度拟合。如果你不知道用什么算法,"ridge" 岭回归是一个好选择。
        "fit_algorithm_dict": {
            "fit_algorithm": "ridge",
        },
        "extra_pred_cols": extra_pred_cols  # 前面is_football_season 和 weekly seasonality 之间的耦合
    }
)

现在,让我们用新的配置来跑模型。评估模型的参数使用跟前面一致的,这样调参对比起来更公平。

# Runs the forecast
result = forecaster.run_forecast_config(
    df=df_full,
    config=ForecastConfig(
        model_template=ModelTemplateEnum.SILVERKITE.name,
        forecast_horizon=365,  # forecasts 365 steps ahead
        coverage=0.95,  # 95% prediction intervals
        metadata_param=metadata,
        model_components_param=model_components,
        evaluation_period_param=evaluation_period
    )
)

# Summarizes the cv result
cv_results = summarize_grid_search_results(
    grid_search=result.grid_search,
    decimals=1,
    # The below saves space in the printed output. Remove to show all available metrics and columns.
    cv_report_metrics=None,
    column_order=["rank", "mean_test", "split_test", "mean_train", "split_train", "mean_fit_time", "mean_score_time", "params"])
# Transposes to save space in the printed output
cv_results["params"] = cv_results["params"].astype(str)
cv_results.set_index("params", drop=True, inplace=True)
cv_results.transpose()
调参后的模型性能

现在,我们可以看到,在分析了问题并且增加了合适特征之后,交叉验证的测试MAPE是5.4%,比baseline的7.3%更好了。
三折的MAPE分别是3.9%, 8.7% and 3.8%。第一折提高最显著。研究一下可以发现第二折没有提高,这是因为在测试周期刚开始的时候,刚好有一个趋势变化点。除非我们看到,否则很难预知这样的情况。

在交叉验证的步骤中,避免这个情况的方式,是设置不同的评价时段。但是不管这个时间段也是可以的,因为未来还有可能再次发生。

在预测时段,我们可以监控预测和实际值,并且根据最新的数据模式重新训练模型。在changepoints变化点的字典中,相应的调整regularization_strengthno_changepoint_distance_from_end,或将手动指定的变更点添加到自动检测的变更点。详情见/pages/model_components/0500_changepoints

我们也可以绘制预测图。

forecast = result.forecast
fig = forecast.plot()
plotly.io.show(fig)

调参后的预测图

Check model summary
检查模型summary

为了进一步研究模型机制,看一看模型的summary也是有帮助的。
ModelSummary模块提供了模型的估计值、显著性、p值、置信区间等。这些可以帮助用户理解模型如何工作以及如何做进一步提升。
模型summary是一种类方法,可按如下方式使用。

summary = result.model[-1].summary()  # -1 retrieves the estimator from the pipeline
print(summary)

模型摘要显示了模型信息、系数及其重要性以及一些摘要统计信息。例如,我们可以看到变化点以及增长率在每个变化点的变化程度。

我们可以看到一些假期在模型中有显著的影响,如圣诞节、劳动节、感恩节等。我们可以看到足球赛季和每周季节性之间相互作用的重要性等。有关模型摘要的更详细指南,请参阅:doc:/gallery/quickstart/0400\u model\u summary

模型调参的总结

在这个示例之后,您可能对如何选择参数和优化模型有一些了解。
这里我们列出了一些可能有助于选择最佳模型的步骤和技巧。
您可以做什么:

用叠加图overlay plots检测异常点anomaly points

(~greykite.framework.input.univariate_time_series.UnivariateTimeSeries.plot_quantiles_and_overlays).
把这些点赋值NA,除非你对修正异常值很有信心。

选择合适的方式来给增长growth建模 (linear, quadratic, square root, etc.)

如果没有一个典型的增长形状符合时间序列,则可以考虑具有趋势变化点的线性增长。尝试不同的变更点检测配置。您还可以绘制检测到的变更点,并查看其对您是否有意义。该模板还支持自定义变更点。如果自动变更点检测结果对您没有意义,您可以提供自己的变更点

选择合适的seasonality周期性阶次

阶次越高,学习的细节越多,但是阶次太高会导致过拟合。这些也可以通过叠加图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>
遵循你的洞察力和直觉,并利用这些参数,你会得到很好的预测结果!

你可能感兴趣的:(Greykite模型的优化调参)