数据STUDIO

用于多期概率预测的线性回归

Image

Image

线性回归模型对时间序列进行点估计,这点并不奇怪。它之所以吸引人,是因为速度快、可解释性强,且易于部署。在许多组织中,仍然是一个不错的选择。线性回归的常见类型是自回归模型,然而,现实世界中的许多用例要求我们提供(1)概率预测(或称为预测区间或预测不确定性),以及(2)多期超前预测。如何扩展线性回归来实现上述两种结果呢?

解决 (1) 的方法是利用分为数回归来预测不确定性。图(A)展示了分位数预测,在任意未来时间 t,它可以提供第 10、50 和 90 百分位数的预测样本。如果需要,还可以生成更多的样本。

分位数回归(英语:Quantile regression)是回归分析的方法之一。最早由Roger Koenker和Gilbert Bassett于1978年提出。

一般地,传统的回归分析研究自变量与因变量的条件期望之间的关系,相应得到的回归模型可由自变量的估计因变量的条件期望;分位数回归研究自变量与因变量的条件分位数之间的关系,相应得到的回归模型可由自变量估计因变量的条件分位数。相较于传统回归分析仅能得到因变量的中央趋势,分量回归可以进一步推论因变量的条件概率分布。分量回归属于非参数统计方法之一。

Image

图(A):时间序列的分位数回归

如何满足(2)?线性回归能够进行单期预测,但如何实现多期预测呢?一种方法是使用递归应用相同的模型。通过使用模型进行一周期的预测,将此结果作为下一个周期的输入。然后,将第二期的预测用作第三期的输入。通过使用前一期的预测结果来遍历所有时期,实现了递归或迭代预测策略。图(A)显示,模型首先产生,然后利用yt+1产生yt+2,依此类推。

Image
图(B):递归策略

另一种策略是建立n个单独的模型。每个模型分别对 n 个周期进行预测。如果我们想预测 10 个时期,我们将训练 10 个模型,每个模型预测一个特定步骤。这就是直接预测策略。这种策略如图(B)所示。

Image
图 (C):直接预测策略

当然,线性回归并不局限于单变量时间序列,还可以包括其他变量,即协变量。图 (D) 中还涵盖了其他协变量 xt 及其过去的 p 项。

Image

图 (D):包含其他协变量的线性回归

当线性模型需要执行量化预测和直接预测时,就显得非常复杂。不过,Python 时间序列库 Darts 已经设计了这样的过程。该库封装了许多 scikit-learn 函数,因此可以充分利用 scikit-learn的功能,包括sklearn 中的量化回归器。因此使用 Darts 库。

  • Darts 库的线性回归模型
  • 从下列单变量数据开始
  • 包括其他协变量,然后
  • 包括量化预测。

注意:Darts 库有其特殊的时间序列数据格式。

数据

先加载数据。

将使用 Kaggle.com 上的沃尔玛数据集,该数据集包含 2010-02-05 至 2012-11-01 期间的每周商店销售额。该数据集包含:

  • 日期 - 销售周
  • 商店 - 商店编号
  • 周销售额 - 商店的销售额
  • 假日标志 - 该周是否为特殊假日周 1 - 假日周 0 - 非假日周
  • 温度 - 销售当天的温度
  • 燃料价格 - 该地区的燃料成本

还有两个会影响零售额的宏观经济指标:消费价格指数和失业率。我将以 Pandas 数据框架的形式加载数据集。

%matplotlib inline
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt

data = pd.read_csv('/walmart.csv', delimiter=",")
data['ds'] = pd.to_datetime(data['Date'], format='%d-%m-%Y')
data.index = data['ds']
data = data.drop('Date', axis=1)
data.head()

Image

Darts 的主要数据类是其 TimeSeries 类。Darts以数组形状(时间、维度、样本)存储数值:

  • 时间:时间索引,如上例中的 143 周。
  • 维度:多元序列的 "列"。
  • 样本:一段时间内的数值。如果是概率预测,如图(A)中第 10、50 和 90 百分位数的三个样本,则会有三个样本。

我们将使用函数 .from_group_dataframe() 来加载沃尔玛商店的销售额。组 ID 是 "Store"。因此参数 group_cols 为 "Store"。时间索引为 "ds" 列。

from darts import TimeSeries
darts_group_df = TimeSeries.from_group_dataframe(data, group_cols='Store', time_col='ds')
print("组/存储的数量为:", len(darts_group_df))
print("周期数为: ", len(darts_group_df[0]))
组/存储的数量为 45
周期数为 143

我们可以使用 .components 函数列出列:

darts_group_df[0].components
(['Weekly_Sales', 'Holiday_Flag', 'Temperature', 'Fuel_Price', 'CPI'、
Unemployment'], dtype='object', name='component')

要建立 1 号店的销售模型,我们只需使用 1 号店的数据。它是 darts_group_df[0]。我们将把它分为训练数据和测试数据。

store1 = darts_group_df[0]
train = store1[:130]
test = store1[130:]
len(train), len(test) # (130, 13)

我们的目标序列是 Weekly_Sales。除了时间序列之外,我们可以添加其他协变量。Darts 库也使用相同的术语来表示两种协变量:过去协变量和未来协变量。过去的协变量是在当前时间之前的可观测变量。而未来协变量是未来可观测变量。您可能会问,我们是如何得知未来值的?首先,它们是确定性的值,例如未来的节假日。其次,它们是来自其他来源的预测值,比如未来几天的天气预报。在我们的案例中,我们使用 "燃油价格" 和 "CPI" 作为过去协变量,以及 "假日标志" 作为未来协变量。

注意,训练数据中的目标和过去协变量共有 130 个数据点。然而,未来协变量延伸到了未来,共有 143 个数据点。

target = train['Weekly_Sales'] #130 weeks
past_cov = train[['Fuel_Price','CPI']] # 130 weeks
future_cov = store1['Holiday_Flag'][:143] #143 weeks

(1)只有单变量数据,没有协变量

下面的代码是 Darts 的.LinearRegressionMode类中的基本公式。

from darts.models import LinearRegressionModel
n = 11
model = LinearRegressionModel(
    lags=12,
    multi_models = True # The default
)

其主要输入参数为

  • lags:滞后项的数量
  • multi_models:多期超前预测的直接预测策略或递归预测策略。默认值为 True,即直接预测策略。

然后,我们用单变量序列 "目标" 拟合数据。我们将预测下一个 n 期。

model.fit(target)
pred = model.predict(n)
pred.values()

输出结果是对未来 n 期的预测。请注意,上述代码已经执行了直接预测策略。

array([[1614776.88276074],
[1495528.54391639],
[1534813.43578372],
[1560262.66213467],
[1606824.32357539],
[1577824.62885009],
[1555804.15138195],
[1560071.35179605],
[1571818.55034631],
[1570541.81547509],
[1554062.56036279]])

把训练数据、预测值和实际值绘制成图:

import matplotlib.pyplot as plt
target.plot(label = 'train')
pred.plot(label = 'prediction')
test['Weekly_Sales'][:n].plot(label = 'actual')
Image

使用平均绝对误差或平均绝对百分比误差来评估模型性能。

from darts.metrics.metrics import mae, mape
print("Mean Absolute Error:", mae(test['Weekly_Sales'][:n], pred))
print("Mean Absolute Percentage Error", mape(test['Weekly_Sales'][:n], pred))

平均绝对误差为 4.07%:

  • 平均绝对误差 63404.82928050449
  • 平均绝对误差 4.070126403190025

(2)添加过去和未来的协变量

协变量是附加的变量,Darts 在建模时使用两种协变量:lags_past_covariates 表示滞后的过去协变量,lags_future_covariates 表示未来的协变量。未来协变量指的是这些协变量在未来时间步的值,而滞后值指的是前一时间段的未来协变量。因此,在未来的 t + n 步时间内,模型会考虑协变量在 t 至 t + (n-1) 阶段的特征值。

from darts.models import LinearRegressionModel
n = 12
model = LinearRegressionModel(
    lags=12,
    lags_past_covariates=12,
    lags_future_covariates=[0,1,2,3,4,5,6,7,8,9,10,11,12],
    output_chunk_length=12,
)
model.fit(target, past_covariates=past_cov, future_covariates=future_cov)
pred = model.predict(n)
pred.values()

参数output_chunk_length的含义需要进一步说明。这与从单变量序列生成样本有关。图(E)显示了从 y0 到 y15 序列生成的样本。每个样本都有一个输入块和一个输出块。假设输入块长度为5,输出块长度为2。第一个样本的输入块是y0 - y4,输出块是y5, y6。通过在序列中滑动窗口来创建样本,直到序列结束。

Image

图 (E):输入块和输出块

块长度的定义为12,若要预测的长度超过12,将收到错误信息。参数 multi_models 指定了直接预测策略,其默认值为True。

array([[1701316.86085439],
[1518461.82066896],
[1534248.83049093],
[1603205.75887748],
[1874920.59155577],
[1803856.24296516],
[1767518.21014623],
[1512584.36011806],
[1697662.46119284],
[1759681.91425129],
[1524124.60535424],
[1476424.91128828]])

建模和预测之后,把实际值和预测值绘制成图。

import matplotlib.pyplot as plt
target.plot(label = 'train')
pred.plot(label = 'prediction')
test['Weekly_Sales'][:n].plot(label = 'actual')
Image

来衡量一下模型性能。

print("Mean Absolute Error:", mae(test['Weekly_Sales'][:n], pred))
print("Mean Absolute Percentage Error", mape(test['Weekly_Sales'][:n], pred))
  • 平均绝对误差 119866.3976798996
  • 平均绝对误差百分比 7.738643655822244

其 MAPE 为 7.73%,小于前一个模型。我们可以选择前一个模型。接下来,我们将学习如何生成量化预测。

(3)量化预测

下面的代码添加了 quantiles=[0.01,0.05,0.50,0.95,0.99]。由于有 5 个样本,我们将在.predict()中指定num_samples=5。

from darts.models import LinearRegressionModel
n = 12
chunk_length = n
model = LinearRegressionModel(
    lags=12,
    lags_past_covariates=12,
    lags_future_covariates=[0,1,2,3,4,5,6,7,8,9,10,11,12],
    output_chunk_length=chunk_length,
    likelihood = 'quantile', # Can be set to quantile or poisson.
    # If set to quantile, the sklearn.linear_model.QuantileRegressor is used. 
    # Similarly, if set to poisson, the sklearn.linear_model.PoissonRegressor is used.
    quantiles=[0.01, 0.05, 0.50, 0.95,0.99]
)
model.fit(target, past_covariates=past_cov, future_covariates=future_cov)
pred = model.predict(n, num_samples=5)
pred

每个周期有五个样本。每个周期的预测结果将是 5 个样本,而不是 1 个样本。(这就是为什么darts的数据格式被称为 "样本")。

<TimeSeries (DataArray) (ds: 12, component: 1, sample: 5)>
array([[[1648721.08935805, 1642706.54654864, 1673668.20059665,
1529363.22689418, 1526422.43847604]],
[[1587939.19686075, 1538051.34908923, 1490354.90288137,
1470637.03716696, 1446139.87263204]],
[[1650027.07076067, 1622427.58463436, 1452286.79045295,
1579802.72329859, 1564271.99950787]],
...

我们将把实际值和概率预测值绘制成图。

import matplotlib.pyplot as plt
target.plot(label = 'train')
pred.plot(label = 'prediction')
test['Weekly_Sales'][:n].plot(label = 'actual')
Image

上述预测中,浅蓝色区域为概率预测。

结论

本文我们研究了Darts库的线性回归模型类,它可以用于建立多期前瞻概率预测的线性模型。我们讨论了模型类的关键输入,包括过去和未来的协变量,以及多期前预测的直接或递归预测策略选项。此外,我们还学习了如何建立量化概率预测模型。如果对比有所帮助,点个赞哇!

🏴‍☠️宝藏级🏴‍☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉Python|MySQL|数据分析|数据可视化|机器学习与数据挖掘|爬虫 等,从入门到进阶!

长按👇关注- 数据STUDIO -设为星标,干货速递ImageImage