图 5:使用正弦/余弦变换拟合。垂直线将训练集和测试集分开。
图 5 显示,该模型能够拾取数据的总体趋势,识别具有较高和较低的周期。但是,预测的幅度似乎不太准确,乍一看,这种拟合似乎比使用第一种方法,虚拟变量,实现的拟合更差(图 2)。
在我们讨论第三种特征工程技术之前,值得一提的是,这种方法存在一个严重的缺点,尤其会在使用基于树的模型时,缺点很明显。最初设计,基于树的模型就是基于当时的单个特征进行拆分。正如我们之前提到的,正弦/余弦特征应该同时考虑,以便正确识别一段时间内的时间点。
方法#3:径向基函数最后一种方法使用径向基函数。我们不会详细介绍它们的实际情况,但您可以在此处阅读有关该主题的更多信息。从本质上讲,我们再次希望解决第一种方法遇到的问题,即我们的时间特征具有连续性。
我们使用方便的scikit-lego库,它提供了RepeatmentBasisFunction类,并指定了以下参数:
- 我们要创建的基函数的数量(我们选择:12个)。
- 用于为 径向基函数(RBF)编制索引的列。我们这里采用的列是,该观测值来自一年中的哪一天。
- 输入范围 – 我们这里,范围是从1到365。
- 如何处理数据帧的其余列,我们将使用这些数据帧来拟合估计器。"drop"将仅保留创建的 RBF 功能,"passthrough "将保留旧功能和新功能。
rbf = RepeatingBasisFunction(n_periods=12,
column="day_of_year",
input_range=(1,365),
remainder="drop")
rbf.fit(X)
X_3 = pd.DataFrame(index=X.index,
data=rbf.transform(X))
X_3.plot(subplots=True, figsize=(14, 8),
sharex=True, title="Radial Basis Functions",
legend=False);
图 6:12 个径向基函数。
图 6 展示,我们使用日数作为输入,创建了 12 个径向基函数。每条曲线都包含有关多靠近本年某一天的信息(在选择此列的情况下)。例如,第一条曲线测量从1月1日开始的距离,因此它在每年的第一天达到峰值,在之后和当初升高的幅度对称地减小。
根据设计,基函数在输入范围内的间距相等。我们选择了12,因为我们希望RBF类似于月份。这样,每个函数都会显示到月份第一天的距离(由于月份的长度不相等)。
与前面的方法类似,让我们使用 12 个RBF 特征去拟合线性回归模型。
model_3 = LinearRegression().fit(X_3.iloc[:TRAIN_END], y.iloc[:TRAIN_END])
results_df["model_3"] = model_3.predict(X_3)
results_df[["actuals", "model_3"]].plot(figsize=(16,4), title="使用RBF特征拟合")
plt.axvline(date(2020, 1, 1), c="m", linestyle="--");
图 7:使用径向基函数拟合。垂直线将训练集和测试集分开。
图 7 显示,当使用 RBF 功能时,该模型能够准确地捕获真实数据。
使用径向基函数时,我们可以调整两个关键参数:
- 径向基函数的数目,
- 钟形曲线的形状 – 可以使用 RepeatingBasis 函数的宽度参数对其进行修改。
调整这些参数值的一种方法是使用网格搜索来确定给定数据集的最佳值。
最终比较我们可以执行以下代码段,以生成编码时间相关信息的不同方法的数字比较。
results_df.plot(title="对比不同时间特征的拟合",figsize=(16,4), color = ["c", "k", "b", "r"])
plt.axvline(date(2020, 1, 1), c="m", linestyle="--");
图 8:使用基于不同时间特征获得的模型,比较拟合。垂直线分开的是训练集和测试集
图 8 表明,径向基函数与所考虑的方法最接近。正弦/余弦特征允许模型拾取主要模式,但不足以完全捕获系列的动态。
使用下面的代码段,我们计算每个模型在训练集和测试集上的平均绝对误差。我们预计训练集和测试集的分数之间非常相似,因为生成的序列几乎完全是周期性的 - 年份之间的唯一区别是随机分量。
当然,在现实生活中情况并非如此,在现实中,随着时间的推移,我们会在同一时期之间遇到更多的变化。但是,在这种情况下,我们还会使用许多其他特征(例如趋势,或时间流逝的某种度量)来解释这些变化。
score_list = []
for fit_col in ["model_1", "model_2", "model_3"]:
scores = {
"model": fit_col,
"train_score": mean_absolute_error(
results_df.iloc[:TRAIN_END]["actuals"],
results_df.iloc[:TRAIN_END][fit_col]
),
"test_score": mean_absolute_error(
results_df.iloc[TRAIN_END:]["actuals"],
results_df.iloc[TRAIN_END:][fit_col]
)
}
score_list.append(scores)
scores_df = pd.DataFrame(score_list)
scores_df
与之前一样,我们可以看到使用RBF特征的模型产生了最佳拟合,而正弦/余弦特征的表现最差。我们对训练集和测试集所得分数之间的相似性假设也得到了证实。