时间序列简介

欢迎阅读《使用Python进行现代时间序列预测》!本书面向数据科学家或机器学习ML)工程师,他们希望通过学习ML世界中的新高级技术来提升时间序列分析技能。时间序列分析在常规的ML书籍、课程等中常被忽视。它们通常从分类开始,涉及回归,然后继续。但时间序列分析在业务中极具价值且无所不在。我们从三维视角看世界。时间是我们很少考虑但无处不在的隐藏维度。只要时间是我们所生活的四个维度之一,时间序列数据也就无处不在。

分析时间序列数据为企业释放了大量价值。时间序列分析并不新鲜——它自20世纪20年代就已存在。但在当前数据时代,企业收集的时间序列数据每时每刻都在变得更大更宽。结合收集数据量的激增以及对ML重新燃起的兴趣,时间序列分析的格局也发生了巨大变化。本书试图带你超越经典统计方法,如自回归积分滑动平均模型ARIMA),并向你介绍ML世界中时间序列分析的最新技术。

我们将从一些基本概念开始,并迅速扩展到更复杂的主题。在本章中,我们将涵盖以下主要主题:

技术要求

你需要按照本书《前言》中的说明设置Anaconda环境,以获得包含本书代码所需的所有库和数据集的运行环境。任何额外的库将在运行笔记本时安装。

本章的配套代码可以在https://github.com/PacktPublishing/Modern-Time-Series-Forecasting-with-Python-2E/tree/main/notebooks/Chapter01找到。

什么是时间序列?

简单来说,时间序列是一组按时间顺序依次获取的观测值。重点在于“时间”这个词。如果我们在不同时间点持续获取相同的观测值,就会得到一个时间序列。例如,如果你持续记录一个月内巧克力的块数,你就会得到巧克力消费的时间序列。假设你每个月初记录体重,就会得到另一个体重时间序列。这两个时间序列之间有关系吗?很可能有。但到本书结束时,我们将能够科学地分析这种关系。

时间序列的其他例子包括你关注的股票每周收盘价、所在城市的日降雨量或降雪量,以及智能手表每小时的心率读数。

时间序列的类型

基于时间间隔,时间序列数据有两种类型,如下所述:

本书仅关注规则时间序列,即时间上均匀间隔的序列。不规则时间序列稍显复杂,需要专门的技术来处理。关于该主题的几篇综述论文是入门不规则时间序列的好方法,你可以在本章的扩展阅读部分找到它们。

时间序列分析的主要应用领域

时间序列分析大致有三个重要的应用领域,概述如下:

本书的重点主要是时间序列预测,但你学到的技术将帮助你以最小的方法变化来处理时间序列分类问题。解释也略有涉及,但因果推断是本书未讨论的领域,因为它需要完全不同的方法。

现在我们已经对时间序列有了概述,让我们构建一个关于时间序列数据如何生成的思维模型。

数据生成过程(DGP)

我们已经看到,时间序列数据是沿时间维度顺序进行的观测的集合。任何时间序列又是由某种机制生成的。例如,你最喜欢的巧克力从制造工厂每日发货的时间序列数据受到许多因素的影响,比如一年中的时间(例如假期)、可可的可用性、工厂机器的工作时间等等。在统计学中,这个生成时间序列的底层过程被称为DGP。时间序列数据是由随机过程和确定性过程产生的。确定性过程涉及随时间以可预测方式演变的量。例如,放射性元素的衰变,剩余量根据精确的数学公式减少,导致随时间一致地减少。但大多数有趣的时间序列(从预测角度来看)是由随机过程生成的。随机过程是一种描述事物随时间以随机但某种程度上可预测的方式变化的方法,就像天气每天如何变化,其中包含一些模式和概率。因此,让我们更多地讨论由随机过程生成的时间序列。

如果我们对现实拥有完全而完美的认识,那么我们只需将这一数据生成过程以数学形式组合起来,就能得到最准确的预测。但遗憾的是,没人对现实拥有完全而完美的认识。因此,我们尝试在数学上尽可能近似数据生成过程,使我们对数据生成过程的模仿能给出最佳的预测(或分析所需的任何其他输出)。这种模仿被称为一个模型,它提供了对数据生成过程的有用近似。

但我们必须记住,模型不是数据生成过程,而是对现实某些基本方面的表示。例如,让我们考虑班加罗尔的航拍图和一张班加罗尔的地图,如下所示:

图1.1 – 班加罗尔的航拍图(左)和班加罗尔的地图(右)

图1.1: 班加罗尔的航拍图(左)和班加罗尔的地图(右)

班加罗尔的地图当然很有用——我们可以用它从A点到B点。但班加罗尔的地图并不等同于班加罗尔的照片。它没有展现繁华的夜生活或难以忍受的交通。地图只是一个模型,表示某个地点的一些有用特征,比如道路和场所。下面的图表可能有助于我们理解这一概念并记住它:

图1.2 – 数据生成过程、模型和时间序列

图1.2: 数据生成过程、模型和时间序列

自然,下一个问题会是:我们有一个有用的模型吗?每个模型都有局限性和挑战。如我们所见,班加罗尔的地图并不能完美地代表班加罗尔。但如果我们的目的是在班加罗尔导航,那么地图就是一个非常有用的模型。如果我们想了解文化呢?地图无法让你感受到文化的韵味。所以,同样是那个曾经有用的模型,在新的情境下就变得毫无用处了。

在不同的情境下,针对不同的目标,需要不同类型的模型。例如,最适合预测的模型可能并非最适合进行因果推断的模型。

我们可以利用数据生成过程的概念来生成多个具有不同复杂度的合成时间序列。

生成合成时间序列

合成时间序列,或称人工时间序列,是极好的工具,你可以借助它们理解时间序列空间、试验不同技术,甚至测试新模型或新的建模配置。这些时间序列被设计为可预测的,尽管有点挑战性。让我们看一些实际示例,在这些示例中,我们可以使用一组基本构建模块生成一些时间序列。你可以发挥创意,任意混合搭配这些组件,甚至将它们加在一起,生成任意复杂度的序列

白噪声与红噪声

一个生成时间序列的随机过程的极端情况是白噪声过程。它具有零均值和恒定方差的随机数序列。这也是时间序列中最流行的噪声假设之一。

让我们看看如何生成这样一个时间序列并绘制它:

# Generate the time axis with sequential numbers upto 200
time = np.arange(200)
# Sample 200 hundred random values
values = np.random.randn(200)*100
plot_time_series(time, values, "White Noise")

输出结果如下:

图1.3 – 白噪声过程

图1.3:白噪声过程

红噪声则具有零均值和恒定方差,但在时间上是序列相关的。这种序列相关性或红度由相关系数r参数化,使得:

$$x_{j+1} = r \cdot x_j + (1 - r^2)^{\frac{1}{2}} \cdot w$$

其中w是来自白噪声分布的随机样本。

让我们看看如何生成它,如下所示:

# Setting the correlation coefficient
r = 0.4
# Generate the time axis
time = np.arange(200)
# Generate white noise
white_noise = np.random.randn(200)*100
# Create Red Noise by introducing correlation between subsequent values in the white noise
values = np.zeros(200)
for i, v in enumerate(white_noise):
    if i==0:
        values[i] = v
    else:
        values[i] = r*values[i-1]+ np.sqrt((1-np.power(r,2))) *v
plot_time_series(time, values, "Red Noise Process")

输出结果如下:

图1.4 – 红噪声过程

图1.4:红噪声过程

周期或季节性信号

在时间序列中最常见的信号之一是季节性信号或周期信号。因此,你可以通过几种方式将季节性引入生成的序列中。

让我们借助一个非常有用的库来生成剩余的时间序列——TimeSynth。更多信息请参考https://github.com/TimeSynth/TimeSynth

这是一个用于生成时间序列的有用库。它包含了各种DGP,你可以混合搭配并创建逼真的合成时间序列。

笔记本提示

有关确切的代码和用法,请参考相关的Jupyter笔记本。

让我们看看如何使用正弦函数创建周期循环。TimeSynth中有一个有用的函数generate_timeseries,它帮助我们组合信号并生成时间序列。请看下面的代码片段:

#Sinusoidal Signal with Amplitude=1.5 & Frequency=0.25
signal_1 =ts.signals.Sinusoidal(amplitude=1.5, frequency=0.25)
#Sinusoidal Signal with Amplitude=1 & Frequency=0. 5
signal_2 = ts.signals.Sinusoidal(amplitude=1, frequency=0.5)
#Generating the time series
samples_1, regular_time_samples, signals_1, errors_1 = generate_timeseries(signal=signal_1)
samples_2, regular_time_samples, signals_2, errors_2 = generate_timeseries(signal=signal_2)
plot_time_series(regular_time_samples,
                 [samples_1, samples_2],
                 "Sinusoidal Waves",
                 legends=["Amplitude = 1.5 | Frequency = 0.25", "Amplitude = 1 | Frequency = 0.5"])

输出结果如下:

图1.5 – 正弦波

图1.5:正弦波

注意两个正弦波在频率(时间序列穿越零点的速度)和振幅(时间序列离零点的距离)上是不同的。

TimeSynth 还有另一个信号称为 PseudoPeriodic。这类似于 Sinusoidal 类,但频率和幅度具有一定的随机性。在下面的代码片段中我们可以看到,这比来自 Sinusoidal 类的普通正弦和余弦波更加真实:

# PseudoPeriodic signal with Amplitude=1 & Frequency=0.25
signal = ts.signals.PseudoPeriodic(amplitude=1, frequency=0.25)
#Generating Timeseries
samples, regular_time_samples, signals, errors = generate_timeseries(signal=signal)
plot_time_series(regular_time_samples,
                 samples,
                 "Pseudo Periodic")

以下是输出:

图1.6 – 伪周期信号

图1.6:伪周期信号

自回归信号

现实世界中另一个非常流行的信号是 自回归(AR)信号。我们将在 第4章建立强大的基准预测 中更详细地讨论这一点,但就目前而言,AR 信号指的是当前时间步的时间序列值依赖于前几个时间步的时间序列值。这种序列相关性是 AR 信号的一个关键特性,它由几个参数定义,如下所述:

让我们看看如何生成 AR 信号并观察其外观,如下所示:

# We have re-implemented the class in src because of a bug in TimeSynth
from src.synthetic_ts.autoregressive import AutoRegressive
# Autoregressive signal with parameters 1.5 and -0.75
# y(t) = 1.5*y(t-1) - 0.75*y(t-2)
signal= AutoRegressive(ar_param=[1.5, -0.75])
#Generate Timeseries
samples, regular_time_samples, signals, errors = generate_timeseries(signal=signal)
plot_time_series(regular_time_samples,
                 samples,
                 "Auto Regressive")

输出结果如下:

图1.7 – AR信号

图1.7:AR信号

混合搭配

您可以使用许多其他组件来创建您的DGP,从而生成时间序列,但让我们快速看看如何将我们已经见过的组件组合起来,生成一个逼真的时间序列。

让我们使用一个带有白噪声的伪周期信号,并将其与一个AR信号组合,如下所示:

#Generating Pseudo Periodic Signal
pseudo_samples, regular_time_samples, _, _ = generate_timeseries(signal=ts.signals.PseudoPeriodic(amplitude=1, frequency=0.25), noise=ts.noise.GaussianNoise(std=0.3))
# Generating an Autoregressive Signal
ar_samples, regular_time_samples, _, _ = generate_timeseries(signal= AutoRegressive(ar_param=[1.5, -0.75]))
# Combining the two signals using a mathematical equation
ts = pseudo_samples*2+ar_samples
plot_time_series(regular_time_samples,
                 ts,
                 "Pseudo Periodic with AutoRegression and White Noise")

输出结果如下:

图1.8 – 带有AR和白噪声的伪周期信号

图1.8:带有AR和白噪声的伪周期信号

平稳和非平稳时间序列

在时间序列中,平稳性非常重要,并且是许多建模方法中的关键假设。具有讽刺意味的是,许多(如果不是大多数)真实世界的时间序列是非平稳的。因此,让我们从外行的角度理解什么是平稳时间序列。

理解平稳性有多种方式,但最清晰、最直观的方式之一是考虑时间序列的概率分布或数据分布。当概率分布在每个时间点保持不变时,我们称该时间序列是平稳的。换句话说,如果你选取不同的时间窗口,所有这些窗口中的数据分布应该是相同的。

标准高斯分布由两个参数定义——均值和方差。因此,平稳性假设有两种方式可能被打破,如下所述:

让我们详细了解这些假设,并更好地理解它们。

均值随时间的变化

这是非平稳时间序列最常见的表现形式。如果时间序列存在上升或下降趋势,那么两个时间窗口内的均值将不相同。

非平稳性的另一种表现形式是季节性。假设我们观察过去5年每月平均气温的时间序列。根据经验,我们知道温度在夏季达到峰值,冬季下降。因此,当我们取冬季平均温度和夏季平均温度时,它们将是不同的。

我们生成一个带有趋势和季节性的时间序列,看看它如何表现:

# Sinusoidal Signal with Amplitude=1 & Frequency=0.25
signal=ts.signals.Sinusoidal(amplitude=1, frequency=0.25)
# White Noise with standard deviation = 0.3
noise=ts.noise.GaussianNoise(std=0.3)
# Generate the time series
sinusoidal_samples, regular_time_samples, _, _ = generate_timeseries(signal=signal, noise=noise)
# Regular_time_samples is a linear increasing time axis and can be used as a trend
trend = regular_time_samples*0.4
# Combining the signal and trend
ts = sinusoidal_samples+trend
plot_time_series(regular_time_samples,
                 ts,
                 "Sinusoidal with Trend and White Noise")

输出结果如下:

图1.9 – 带趋势和白噪声的正弦信号

图1.9:带趋势和白噪声的正弦信号

如果你仔细观察图1.9中的时间序列,你将能够看到明确的趋势和季节性,这两者共同使得数据分布的均值在不同时间窗口间剧烈变化。

方差随时间的变化

非平稳性也可以表现为时间序列方差的波动。如果时间序列开始时方差较小,随着时间的推移,方差变得越来越大,那么这就是一个非平稳时间序列。在统计学中,这种现象有一个吓人的名字——异方差性。Air Passengers 数据集,即时间序列的“鸢尾花数据集”(最流行、被过度使用且无用的数据集),是异方差时间序列的经典例子。让我们看看这个图:

图1.10:Air Passengers 数据集——异方差时间序列示例

在图中,你可以看到随着时间推移,季节性峰值变得越来越宽,这是时间序列异方差性的典型标志。但并非所有异方差时间序列都容易识别。我们有统计检验来检查每种平稳性情况,这将在第7章《时间序列预测的目标变换》中介绍。

本书仅试图让你理解平稳与非平稳时间序列。本讨论中跳过了大量统计理论和深度内容,以便我们专注于时间序列的实践方面。

掌握了DGP的思维模型,我们便可以思考另一个重要问题:我们能够预测什么?

我们能预测什么?

在继续之前,我们还需要理解时间序列预测的另一个方面——时间序列的可预测性。预测时间序列时最基本的假设是未来依赖于过去。但并非所有时间序列都具有同等的可预测性。

让我们看几个例子,并按照可预测性(从最容易到最难)排序如下:

直观上,我们很容易对它们排序。下周一的潮汐最容易预测,因为它非常规律;下周五的特斯拉股票价格难以预测,但并非不可能;而彩票号码则非常难以预测,因为它们几乎是随机的。

然而,对于那些以为能用本书介绍的高级技术预测股票价格并发财的人,这(很可能)不会发生。虽然值得深入讨论,但我们可以用一小段总结关键点。

股票价格不是其历史值的函数,而是对其未来值的预期,这违背了我们预测时的第一个假设。如果这还不够糟,金融股票价格通常具有极低的信噪比。最后的障碍是有效市场假说EMH)。这个看似无害的假说声称,关于股票价格的所有已知信息都已反映在股价中。该假说的含义是,如果你能准确预测,许多其他人也能做到,因此股票的市场价格已经反映了该预测带来的价格变化。

M6竞赛选择直面这一问题,通过举办为期一年的预测与投资策略竞赛来评估有效市场假说(EMH)是否成立。尽管并非定论,但结果显示,除少数顶尖团队外,EMH对绝大多数参与者成立。即便在顶尖团队中,他们也发现预测准确性与投资组合中股票选择之间并无显著相关性,即团队并未选择那些他们能够更好预测的股票(完整报告链接见延伸阅读部分)。

回到当前主题——可预测性,有三个主要因素构成了一个思维模型,如下所示:

尽管你已有了一个关于如何思考可预测性的思维模型,但我们将在第3章分析和可视化时间序列数据》中介绍更具体的评估时间序列可预测性的方法,但关键要点是,并非所有时间序列都具有同等的可预测性。

为了充分理解后续章节的讨论,我们需要建立标准符号并学习时间序列分析特有的术语。

预测术语

有几个术语有助于你理解本书以及其他关于时间序列的文献。下面将更详细地介绍这些术语:

预测是利用时间序列的已知过去值和/或其他相关变量来预测未来值。这与机器学习中的预测非常相似,我们使用模型来预测未见过的数据。

多元时间序列由多个时间序列变量组成,这些变量不仅依赖于其过去的值,还与其他变量存在一定的依赖关系。例如,一组宏观经济指标,如国内生产总值GDP)和通货膨胀,对于一个特定国家来说,可以被视为多元时间序列。多元预测的目标是建立一个模型,该模型能够捕捉不同变量之间的相互关系,以及它们与过去的关系,并共同预测所有时间序列的未来值。

除了时间序列的过去值,我们可能使用其他信息来预测时间序列的未来值。例如,在预测零售店销售额时,有关促销活动(包括历史和未来)的信息通常是有帮助的。这种利用自身历史之外信息的预测类型称为解释性预测。

从训练数据中留出一个验证集来评估模型,这在机器学习领域是一种常见做法。回测是时间序列中验证的等价物,即利用历史数据来评估已训练的模型。我们将在后面介绍对时间序列数据进行验证和交叉验证的不同方法。

再次与机器学习类比,样本内指训练数据,样本外指未见数据或测试数据。当你听到样本内指标时,指的是在训练数据上计算的指标;样本外指标指的是在测试数据上计算的指标。

外生变量是平行的时间序列变量,它们不直接建模用于输出,而是用于帮助我们对感兴趣的时间序列进行建模。通常,外生变量不受系统中其他变量的影响。内生变量是受系统中其他变量影响的变量。纯粹的内生变量是完全依赖于系统中其他变量的变量。稍微放宽严格假设,我们可以将目标变量视为内生变量,而将模型中包含的解释性回归量视为外生变量。

时间序列中的预测组合类似于机器学习中的集成学习。预测组合是一个过程,通过该过程我们使用某种函数(无论是学习得到的还是基于启发式的,例如三个预测模型的简单平均)将多个预测组合起来。

还有更多专门针对时间序列的术语,其中一些我们将在本书中陆续介绍。但这些术语应该是一个很好的起点,能够让你对该领域有基本的了解。

小结

在本章中,我们首次接触了时间序列,讨论了不同类型的时间序列,了解了数据生成过程如何生成时间序列,并探讨了如何思考一个重要问题:我们能对时间序列预测得多好? 我们还快速回顾了理解本书其余内容所需的术语。在下一章中,我们将亲自动手,学习如何获取和处理时间序列数据。如果你还没有设置好环境,不妨休息一下,花些时间完成这个设置。

延伸阅读