Kaggle时间序列(Time Series)教程 2-趋势(Trend)

什么是趋势(Trend)?

时间序列的趋势部分表示该序列平均值的持续、长期变化。 趋势是一系列中移动最慢的部分,代表了最大时间尺度的重要性。 在产品销售的时间序列中,随着越来越多的人逐年意识到该产品,销售量可能是增加的趋势。

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第1张图片

四个时间序列中的趋势

在本节课中,我们将关注均值趋势。 更一般地说,一个序列中任何持续的和缓慢移动的变化都可能构成一个趋势——例如,时间序列通常具有变化的趋势。

移动平均图(moving average plot)

要查看时间序列可能具有什么样的趋势,我们可以使用移动平均图。 为了计算时间序列的移动平均值,我们计算某个定义的宽度的滑动窗口内的值的平均值。 图表上的每个点代表位于任一侧窗口内的系列中所有值的平均值。 这个想法是为了消除序列中的任何短期波动,以便只保留长期的变化。

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第2张图片

线性趋势的移动平均图。 曲线上的每个点(蓝色)是大小为 12 的窗口内的点(红色)的平均值。

请注意上面的 Mauna Loa 系列如何年复一年地重复上下运动——这是一种短期的季节性变化。 要使变化成为趋势的一部分,它应该比任何季节性的变化发生的时间更长。 因此,为了可视化趋势,我们在比该系列中任何的季节性的周期更长的时间段内取平均值。 对于 Mauna Loa 系列,我们选择了大小为 12 的窗口来平滑每年的季节。

趋势工程(Engineering Trend)

一旦我们确定了趋势的形状,我们就可以尝试使用时间步长(time-step)特征对其建模。 我们已经看到如何使用时间虚拟变量(time dummy)本身来模拟线性趋势:

target = a * time + b

我们可以通过时间虚拟变量(time dummy)的转换来拟合许多其他类型的趋势。 如果趋势看起来是二次的(抛物线),我们只需将时间虚拟变量(time dummy)的平方添加到特征集,得到:

target = a * time ** 2 + b * time + c

线性回归将学习系数abc

下图中的趋势曲线都是使用这些特征和 scikit-learn 的 LinearRegression 拟合的:

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第3张图片

上: 具有线性趋势的系列。 下: 具有二次趋势的系列。

如果您以前没有见过这个技巧,那么您可能没有意识到线性回归可以拟合除直线以外的曲线。 这个想法是,如果您可以提供适当形状的曲线作为特征,那么线性回归可以学习如何以最适合目标的方式组合它们。

示例 - 隧道流量(Tunnel Traffic)

在此示例中,我们将为 隧道流量(Tunnel Traffic) 数据集创建一个趋势模型。


from pathlib import Path
from warnings import simplefilter

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

simplefilter("ignore")  # ignore warnings to clean up output cells

# Set Matplotlib defaults
plt.style.use("seaborn-whitegrid")
plt.rc("figure", autolayout=True, figsize=(11, 5))
plt.rc(
    "axes",
    labelweight="bold",
    labelsize="large",
    titleweight="bold",
    titlesize=14,
    titlepad=10,
)
plot_params = dict(
    color="0.75",
    style=".-",
    markeredgecolor="0.25",
    markerfacecolor="0.25",
    legend=False,
)
%config InlineBackend.figure_format = 'retina'


# Load Tunnel Traffic dataset
data_dir = Path("./ts-course-data")
tunnel = pd.read_csv(data_dir / "tunnel.csv", parse_dates=["Day"])
tunnel = tunnel.set_index("Day").to_period()

让我们做一个移动平均图,看看这个系列有什么样的趋势。 因为这个系列记录有每天的观察,所以我们选择一个365天的窗口来平滑一年内的任何短期变化。

要创建移动平均图,首先使用rolling方法开始窗口计算。 然后使用 mean 方法来计算窗口上的平均值。 正如我们所见,隧道流量(Tunnel Traffic) 的趋势似乎是线性的。

moving_average = tunnel.rolling(
    window=365,       # 365-day window
    center=True,      # puts the average at the center of the window
    min_periods=183,  # choose about half the window size
).mean()              # compute the mean (could also do median, std, min, max, ...)

ax = tunnel.plot(style=".", color="0.5")
moving_average.plot(
    ax=ax, linewidth=3, title="Tunnel Traffic - 365-Day Moving Average", legend=False,
);

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第4张图片
在第1课中,我们直接使用Pandas设置了时间虚拟对象(time dummy)。 但是,从现在开始,我们将使用 statsmodels 库中的一个名为 DeterministicProcess 的函数。 使用这个函数将帮助我们避免一些可能与时间序列和线性回归有关的棘手的失败案例。 order 参数是指多项式次数:1 表示线性,2 表示二次,3 表示三次,依此类推。

from statsmodels.tsa.deterministic import DeterministicProcess

dp = DeterministicProcess(
    index=tunnel.index,  # dates from the training data
    constant=True,       # dummy feature for the bias (y_intercept)
    order=1,             # the time dummy (trend)
    drop=True,           # drop terms if necessary to avoid collinearity
)
# `in_sample` creates features for the dates given in the `index` argument
X = dp.in_sample()

X.head()

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第5张图片
(顺便说一下,deterministic process是 非随机 或 完全确定 的时间序列的技术术语,就像 consttrend 系列一样。从时间索引得出的特征通常会是完全确定的。)

我们基本上像以前一样创建趋势模型,但请注意这里添加了 fit_intercept=False 参数。

from sklearn.linear_model import LinearRegression

y = tunnel["NumVehicles"]  # the target

# The intercept is the same as the `const` feature from
# DeterministicProcess. LinearRegression behaves badly with duplicated
# features, so we need to be sure to exclude it here.

# intercept 与 DeterministicProcess 中的 `const` 功能相同。 LinearRegression 对重复特征表现不佳,因此我们需要确保在此处排除它。
model = LinearRegression(fit_intercept=False)
model.fit(X, y)

y_pred = pd.Series(model.predict(X), index=X.index)

我们的“线性回归”模型发现的趋势几乎与移动平均图相同,这表明在这种情况下使用线性趋势是正确的决定。


ax = tunnel.plot(style=".", color="0.5", title="Tunnel Traffic - Linear Trend")
_ = y_pred.plot(ax=ax, linewidth=3, label="Trend")

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第6张图片
为了进行预测,我们将模型应用于“样本外”特征。 “样本外”是指训练数据的观察期之外的时间。 以下是我们如何进行 30 天预测的方法:

X = dp.out_of_sample(steps=30)

y_fore = pd.Series(model.predict(X), index=X.index)

y_fore.head()

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第7张图片
让我们绘制该系列的一部分以查看未来 30 天的趋势预测:


ax = tunnel["2005-05":].plot(title="Tunnel Traffic - Linear Trend Forecast", **plot_params)
ax = y_pred["2005-05":].plot(ax=ax, linewidth=3, label="Trend")
ax = y_fore.plot(ax=ax, linewidth=3, label="Trend Forecast", color="C3")
_ = ax.legend()

Kaggle时间序列(Time Series)教程 2-趋势(Trend)_第8张图片

我们在本课中学到的趋势模型之所以有用,有很多原因。 除了作为更复杂模型的基线或起点之外,我们还可以将它们用作有些无法学习趋势(如 XGBoost 和随机森林)的算法的“混合模型”中的一个组件。 我们将在第 5 课中了解有关此技术的更多信息。

轮到你了

商店销售中的模型趋势 并了解使用高阶多项式进行预测的风险。

你可能感兴趣的:(机器学习,python,机器学习)