如何使用滞后预测时间序列
如何使用滞后预测时间序列
如何使用滞后预测时间序列
.以下是如何利用它们来为你带来优势

作者截图
时间序列模型的特点是过去值往往会影响未来值。当你的数据有任何形式的季节性(换句话说,你的数据遵循每小时、每天、每周、每月或每年的周期)时,这种关系甚至更加强烈。
通过特征如小时、星期几、月份等来捕捉这种关系,但你也可以添加滞后,这可以迅速将你的模型提升到下一个层次。
什么是滞后?
滞后值简单来说就是:在某个时间点或另一个时间点,先于你的当前值。
假设你有一个时间序列数据集,具有以下值:[5,10,15,20,25]。
25,作为你最新的值,是时间 t 的值。
20 是 t-1 的值,15 是 t-2 的值,以此类推,直到数据集的开始。
这在直观上是有意义的,因为“滞后”这个词暗示着某物“落后”于另一物。
当我们使用滞后特征训练模型时,我们可以训练它识别与先前值如何影响当前和未来值相关的模式。
为什么使用滞后?(+ 如何实现)
为了展示滞后如何使你的模型受益,我将通过一个例子来指导你,使用一个每小时能源消耗数据集 (CC0 1.0 许可)。
这里是这个数据集大约四周的样本,这样你可以感受到它的样子:

作者截图
如你所见,周末(用红色圆圈表示)的利用率在这四周切片中较低,存在一些周季节性。还有明显的日季节性,因为一天的高峰通常在 17:00 到 19:00(下午 5 点到 7 点)之间。
当你放大查看时,你还可以看到不同月份的年使用模式不同(尤其是夏季与冬季月份)。

作者截图
如果我要训练一个常规的时间序列模型,我会关注以下特征:
-
一天中的小时
-
星期几
-
年份中的月份
我将用一个例子来展示如何使用NIXTLA mlforecast 库,因为它不仅使时间序列预测变得非常简单,而且还能轻松地将滞后特征添加到你的时间序列模型中。
首先,我使用我列出的特征训练了一个常规模型。首先,我将数据集加载进来,并为其准备 NIXTLA 库:
import pandas as pd
from mlforecast import MLForecast
from sklearn.ensemble import RandomForestRegressor
# Load in data and basic data cleaning
df = pd.read_csv('AEP_hourly.csv')
df['Datetime']=pd.to_datetime(df['Datetime'])
# Sort by date
df.set_index('Datetime',inplace=True)
df.sort_index(inplace=True)
df.reset_index(inplace=True)
# This dataset is huge with over 100,000 rows
# Get only the last 10,000 rows of hourly data (a little over a year of data)
df = df.tail(10000)
# NIXTLA requires that your date/timestamp column be named "ds"
# and your target variable be named y
df.rename(columns={'Datetime':'ds','AEP_MW':'y'},inplace=True)
# NIXTLA requires a "unique_id" column in case you are training
# more than one model using different datasets, but if you're only
# training with 1 dataset, I just create a dummy constant variable
# column with a value of 1
df['unique_id']=1
然后,我通过将数据分为训练集和测试集来准备我的建模数据:
# Split into train/test sets. For this problem,
# I don't want a huge test set, since when using lags, you'll have to
# predict using predictions after the first hour forecast.
# (More on this later)
# So my test set will be only 48 hours long (48 rows)
train_size = df.shape[0] - 48
df_train = df.iloc[:train_size]
df_test = df.iloc[train_size:]
接下来,我使用 NIXTLA 训练了一个随机森林模型:
# NIXTLA allows you to train multiple models, so it requires
# a list as an input. For this exercise, I only trained 1 model.
models = [
RandomForestRegressor(random_state=0)
]
# Instantiate an MLForecast object and pass in:
# - models: list of models for training
# - freq: timestamp frequency (in this case it is hourly data "H")
# - lags: list of lag features (blank for now)
# - date_features: list of time series date features like hour, month, day
fcst = MLForecast(
models=models,
freq='H',
lags=[],
date_features=['hour','month','dayofweek']
)
# Fit to train set
fcst.fit(df_train)
最后,我在测试集上进行了预测(使用预测对象预测接下来的 48 小时,并将其与测试集值进行比较),以及运行了 3 个窗口的交叉验证,每个窗口预测 24 小时块:
from sklearn.metrics import mean_squared_error
from utilsforecast.evaluation import evaluate
from utilsforecast.losses import rmse
# Predict
predictions = fcst.predict(48)
# Compare to test set. This returns a result of 689.9 RMSE
print(mean_squared_error(df_test.y.values,predictions.RandomForestRegressor.values,squared=False))
# Run cross validation with train df
cv_df = fcst.cross_validation(
df=df_train,
h=24,
n_windows=3,
)
# Get CV RMSE metric
cv_rmse = evaluate(
cv_df.drop(columns='cutoff'),
metrics=[rmse],
agg_fn='mean'
)
# Prints out 1264.1
print(f"RMSE using cross-validation: {cv_rmse['RandomForestRegressor'].item():.1f}")
因此,使用这个时间序列模型——使用小时、星期几和月份——平均交叉验证 RMSE 为 1264.1,测试集 RMSE 为 689.9。
让我们比较一下基于滞后的模型。
# Pass in lags as a list argument - I'm tracking lags for 24 hours
# since the goal of our model is to forecast 24 hours at a time
fcst_lags = MLForecast(
models=models,
freq='H',
lags=range(1,25),
date_features=[]
)
fcst_lags.fit(df_train)
# Predict 24 hours twice for the test set (48 hours)
predictions_lags = fcst_lags.predict(48)
# RMSE test score w/ lags: 421.86
print(mean_squared_error(df_test.y.values,predictions_lags.RandomForestRegressor.values,squared=False))
# Cross validation:
cv_df_lags = fcst_lags.cross_validation(
df=df_train,
h=24,
n_windows=3,
)
cv_rmse_lags = evaluate(
cv_df_lags.drop(columns='cutoff'),
metrics=[rmse],
agg_fn='mean'
)
# RMSE for CV w/ lags: 1038.7
print(f"RMSE using cross-validation: {cv_rmse_lags['RandomForestRegressor'].item():.1f}")
让我们并排比较一下指标:
-
无滞后模型 + 时间序列特征(小时、星期几、月份)测试 RMSE: 689.9
-
无滞后模型 + 时间序列特征 CV RMSE: 1264.1
-
具有滞后模型的测试 RMSE: 421.86
-
具有滞后模型的 CV RMSE: 1038.7
备注:在两种情况下,CV RMSE 都远高于测试 RMSE。这是因为 CV 评估的数据与测试集不同。
CV 在以下 3 天进行评估:7 月 29 日至 31 日,每次预测 24 小时,并取平均值。保留测试集在 8 月 1 日至 2 日进行评估,每次预测 48 小时。
为了进一步调查这个问题,我绘制了交叉验证预测值与实际值的对比图,并得到了每个分割窗口(共有 3 个——每天一个)的 RMSE。
在这两种情况下,模型对 7 月 30 日(RMSE 为 1445)的预测都存在显著的低估,对 7 月 31 日(RMSE 为 888)的预测略有高估。这导致了 CV 平均值上升。

滞后预测模型交叉验证预测值与实际值。图片由作者提供
因此,可能由于某些原因(可能是我们没有考虑的其他变量,例如天气),在两种情况下,CV 验证集的表现都不太好。
当你的指标看起来有点不正常时,总是很重要去调查发生了什么。
在一个真实的机器学习项目案例中,我会深入调查为什么这些天特别难以预测,但为了本文的目的,我不会这样做——只是指出,这样做总是个好主意。
如果我取平均值:
无滞后模型的模型: 997
具有滞后模型的模型: 730.28
然而,无论平均数如何,具有滞后的模型在 CV 和保留测试集上都优于无滞后的模型。
一点注意事项
滞后可以为你的模型提供有用的信息并提高其性能。它们也相对容易实现,尤其是在像 NIXTLA(注意:我不是 NIXTLA 的赞助商)这样的良好构建的时间序列库的帮助下。
但过度依赖滞后可能会成为一个问题,尤其是如果你的目标是预测更长时间的范围。
基本上,关于滞后的处理是这样的:在某个时刻,模型不再有实际值作为特征来使用,因此它必须依赖预测。这给模型引入了一些误差。随着你做出越来越多的预测,误差会累积。
例如,假设你只使用了一个滞后列,并且你的数据集如下所示:[1,2,3,4,5]。你在这个数据集上训练了你的模型,现在你需要预测接下来的 5 行。
在第一次遍历中,我们来到了超过 5 个时间步之后,让我们称它为时间 t。t-1 的滞后特征是 5。模型预测下一个值将是 6。为了预测 t+1 的下一个值,我们需要使用我们的预测:6。这引入了不确定性,因为 6 是一个预测值,而不是一个真实的滞后值。
如果模型在 t+1 时预测 8,那么下一个预测,在 t+2 时必须将 8(由于使用了 6 作为特征而具有额外不确定性的预测)作为下一个滞后特征。
以此类推,每次预测的不确定性都会增加。
因此,你可以看到这可能会在更长的预测范围内导致更差的表现。
结论
滞后项对于预测较短的时间范围非常有用,例如 1 到 48 行。之后你需要仔细观察你的误差。使用预测区间来衡量不确定性。
除了滞后项之外,优先考虑其他数值和分类特征也很重要。标记是否是假日、周末还是工作日,或者季节,也可以改善你的模型,以及包括外部变量,如温度。
然而,一切取决于你的具体数据集,所以总是要尝试多个特征和组合进行实验。
你可以在这里找到完整的源代码和数据集。

浙公网安备 33010602011771号