> 技术文档 > 使用 Spark 进行时间序列分析: 1 什么是时间序列?_spark 中高效地处理和聚合时间序列数据

使用 Spark 进行时间序列分析: 1 什么是时间序列?_spark 中高效地处理和聚合时间序列数据

数据与人工智能领域的专业人士,特别是处理时间相关数据集的人员,将会发现 《使用 Spark 进行时间序列分析》 对于提升他们利用 Apache Spark 和 Databricks 进行时间序列分析的技能大有裨益。 本书面向广泛读者群体,既适合时间序列分析和 Apache Spark 的初学者,也适合希望利用 Spark 进行时序数据分析的经验丰富的从业者。

更具体地说,数据工程师将提升他们使用 Spark 和 Databricks 进行大规模时间序列数据准备的能力。 机器学习 ML)工程师会发现更容易扩展其 ML 项目的范围。 数据科学家和分析师将获得新的时间序列分析技能,以拓宽他们的工具范围。

本书内容概览

第 1 章 , 什么是时间序列?,介绍了时间序列数据的概念及其分析中的独特挑战。 这是有效分析和预测时间相关数据的基础。

第 2 章 , 为何进行时间序列分析?,详细阐述了分析时间相关数据对于实现预测建模、趋势识别和异常检测的重要性。 并通过跨行业实际应用案例加以说明。

第 3 章 ,Apache Spark 简介 ,深入探讨了 Apache Spark 及其分布式计算能力在大规模时间序列数据处理中的应用。

第 4 章 , 时间序列分析项目的端到端视角 ,将带领我们完整了解时间序列分析项目的全流程。 从用例场景出发,涵盖数据处理、特征工程、模型选择及评估等关键阶段。

第 5 章 , 数据准备 ,深入探讨时间序列数据的整理、清洗与转换等关键步骤。 内容涵盖缺失值处理、异常值应对以及数据结构化等技巧,从而提升后续分析流程的可靠性。

第 6 章 , 探索性数据分析 ,通过探索性数据分析揭示时间序列数据中的模式和洞见。 这些步骤对于识别趋势和季节性等特征至关重要,为后续的建模决策提供依据。

第 7 章 , 构建与测试模型 ,重点介绍时间序列预测模型的构建,涵盖各类模型的选择、训练、调参及评估方法。

第 8 章 , 规模化应用 ,探讨了在大型分布式计算环境中扩展时间序列分析的注意事项。 本章涵盖了使用 Apache Spark 扩展特征工程、超参数调优以及单模型与多模型训练的不同方法。

第 9 章 , 生产部署 ,深入研究了将时间序列模型部署到生产环境时涉及的实践考量与实施步骤,同时确保时间序列模型在运行环境中的可靠性与有效性。

第 10 章 , 深入使用 Apache Spark,通过使用 Databricks 这一基于云的托管平台即服务解决方案,为平台设置和管理中的挑战提供解决方案,助您更深入地使用 Apache Spark。

第 11 章 , 时间序列分析的最新进展 ,探讨了时间序列分析领域的最新发展,包括将生成式 AI 这一激动人心的领域应用于时间序列预测的方法,以及使时间序列分析结果能够以非技术方式呈现的新方法。

20年工作经验,承接微信小程序,App,网站,网站后端开发。有意向私聊我哈。微信:akluse

时间序列简介

本节中,我们将理解时间序列的定义及其相关术语, 并通过实践案例演示如何可视化时间序列。 我们将观察不同类型的时间序列及其特征。 掌握时间序列的本质特性,对于我们在后续章节中选择合适的时间序列分析方法至关重要。

让我们以毛里求斯自 1950 年以来每年平均气温的时间序列为例开始。 数据的一个简短样本如表 1.1 所示.

年份

平均气温

1950

22.66

1951

22.35

1952

22.50

1953

22.71

1954

22.61

1955

22.40

1956

22.22

1957

22.53

1958

22.71

1959

22.49

表1.1:时间序列数据样本——平均气温

在可视化和解释这个示例的过程中,我们将接触到一些与时间序列相关的术语。 可视化该数据集的代码将在本章的实践部分进行讲解。

下图中,我们可以看到自 1950 年以来温度随年份的变化。 若重点关注 1980 年后的时期,便能更细致地观察温度变化,这些年呈现类似的升温趋势(趋势线——两图中均以虚线表示)直至当前温度。

 

图1.1:毛里求斯自1950年以来的平均气温

如果气温持续以相同方式上升,我们将迈向一个更加温暖的未来,这是目前被广泛认可的全球变暖现象的具体表现。 在气温逐年升高的同时,夏季气温也会周期性上升而冬季则下降( 季节性 )。 我们将在本章实践部分可视化这一现象及温度时间序列的其他组成要素。

随着近年来气温不断升高( 趋势 ),全球变暖对地球及其居民产生了影响( 因果关系 )。 这种影响也可以通过时间序列来呈现——例如海平面或降雨量测量数据。 全球变暖的后果可能是剧烈且不可逆转的,这进一步凸显了理解这一趋势的重要性。

这些随时间连续记录的测温数据构成了我们所说的时间序列。 分析和理解这类时间序列对于我们的未来至关重要。

那么更广义的时间序列是什么? 它本质上是源系统生成的、带有特定时间戳的时序测量数据序列 。 以温度为例,源系统就是特定地理位置的温度计。

时间序列也可以聚合形式呈现,比如如表 1.1 所示的逐年平均温度.

通过这个示例化的定义,现在让我们更深入探讨时间序列的本质。 本书后续章节还将详细阐述这里提到的术语,包括趋势性、季节性和因果性。

时间顺序

本章开头定义时间序列时提到了时间顺序,这是因为在处理时间序列数据时,顺序是区别于其他数据集处理方法的主要因素。 顺序之所以重要,其中一个关键原因在于时间序列可能存在自相关性,即时间点 t 的测量值与 n 个时间步长前( 滞后 )的测量值相关。 忽略这种顺序会导致分析不完整甚至错误。 我们将在后续第 6 章关于探索性数据分析的内容中介绍识别自相关性的方法。

值得注意的是,在时间序列的许多情况下,自相关性往往使得时间上更接近的测量值在数值上也更为接近,相比之下,时间间隔较远的测量值则差异较大。

遵循时间顺序的另一个原因是为了避免模型训练时的数据泄露。 在部分分析和预测方法中,我们将基于历史数据训练模型以预测未来目标日期的数值。 必须确保所用数据点均早于目标日期。 训练时的数据泄露(在时间序列数据中往往难以察觉)会破坏方法的完整性,导致模型在开发阶段表现出误导性的优异性能,而在面对新的未见数据时表现欠佳。

此处引入的术语(如自相关、滞后和数据泄露)将在本书后续章节中进一步阐述。

时间顺序,即此处讨论的内容,是时间序列的一个定义性特征。 下一节我们将重点讨论规律性或其缺失,这是另一个特征。

规律与不规则

时间序列在测量间隔方面可以是规律的或不规律的。

规律时间序列的数值预期会按固定时间间隔出现,比如每分钟、每小时、每月等。 这通常是生成连续值的源系统的情况,随后按固定间隔进行测量。 这种规律性是预期的,但不能保证,因为这些时间序列可能存在间隙或零值,原因可能是数据点缺失或测量值本身为零。 在这种情况下,它们仍被视为具有规律性。

不规则时间序列是指源数据并非按固定间隔生成的测量值。 这种情况通常发生在事件随机发生时,随后会针对这些事件测量某种类型的数值。 这些不规则间隔的数值可以通过重采样转换为较低频率的规则间隔——实际上就变成了规则时间序列。 例如,一个并非每分钟都发生的不规则事件,可能每小时都有发生的可能性,因此在每小时频率上可视为规则事件。

本书将主要关注规则时间序列。 在了解时间序列的规则性之后,下一节我们将讨论的另一个特征是平稳性。

平稳与非平稳

根据时间序列统计特性随时间的变化情况,可进一步分为平稳或非平稳时间序列。

平稳时间序列是指其均值、方差等统计特性不随时间变化的序列。

非平稳时间序列的统计特性会发生变化。 这类序列可通过方法组合转换为平稳序列: 例如通过一阶或多阶差分稳定均值,使用对数变换稳定方差。 这种区分很重要,它将决定可使用的分析方法。 举例来说,若分析方法基于序列平稳的假设,可先对非平稳数据进行上述转换。 您将在第 6 章探索性数据分析中学习识别平稳性的方法。

将非平稳时间序列转换为平稳序列会去除趋势和季节性成分,但如果我们想要分析这些成分 ,这可能并非我们所期望的。

本节对于理解时间序列的基本特性至关重要,这是识别本书后续部分应使用的正确分析方法的先决条件。 图 1.2 总结了可用的时间序列类型及其转换操作。

 

图1.2:时间序列类型

至此, 本章的理论部分已全部结束。 下一节我们将首次进行实践操作,并在此过程中搭建编码环境。 本章我们将从时间序列的可视化与分解开始。 我们将在下一章深入探讨不同类型的时间序列分析及其适用场景。

实践操作:加载与可视化时间序列数据

让我们开始动手实践,加载一个时间序列数据集并进行可视化。 我们将尝试创建已在图 1.1 中看到的可视化效果。.

开发环境

要运行代码,您需要一个可以安装 Apache Spark 和其他必要库的 Python 开发环境。 具体所需的库及其安装说明将在对应章节中详细说明。

PaaS

一个简单的方法是使用免费的 Databricks Community Edition 来满足这些需求。 它提供了基于笔记本的开发界面,以及预装了 Spark 和一些其他库的计算环境。

注册 Databricks Community Edition 的说明可以在此处找到:

Databricks Free Edition | Databricks Documentation

社区版作为免费的云端 PaaS 服务,其计算规模有所限制。 您也可以注册 Databricks 的 14 天免费试用,根据所选注册选项,可能需要先拥有云服务提供商账户。 部分云服务提供商在初始阶段会提供包含免费额度的促销活动。 这将使您在限时内获得比社区版更多的资源访问权限。

注册 即可免费试用 Databricks,请访问以下网址:Try Databricks for Free | Databricks

Databricks 的团队是 Apache Spark 的原始创造者,因此在那里您将处于一个有利的位置。

早期章节的示例将使用 Community Edition 和 Apache Spark 的开源版本。 我们将在第 8 章和第 10 章中使用完整的 Databricks 平台.

自定义

或者,您可以构建自己的环境,例如在 Docker 容器中设置完整的堆栈。 这将在第 3 章 ,Apache Spark 简介中介绍.

 

数据集

一旦选定了开发和运行时环境,另一个需要考虑的因素就是数据集。 我们将使用的是毛里求斯观测到的年平均地表气温数据,该数据可在气候变化知识门户网站上获取,网址为 Mauritius - Summary | Climate Change Knowledge Portal.

数据集副本(文件名为 ts-spark_ch1_ds1.csv)可在 ch1 GitHub 文件夹中找到。 可使用前文提到的代码进行下载。

接下来,您将在 Databricks Community Edition 工作区中操作,这将是您专属的独立环境。

分步指南:加载并可视化时间序列数据

现在所有准备工作已完成,让我们开始第一个编码练习。 首先登录 Databricks Community Edition 导入代码,创建集群,最后运行代码:

  1. 登录 Databricks Community Edition(如图 1.3 所示),使用您注册时设置的凭证。 通过以下网址访问登录页面:Databricks - Sign In

    请参阅开发环境部分了解如何注册,如果您尚未完成此操作。

 

图 1.3:登录 Databricks 社区版

  1. 进入工作区后, 点击创建笔记本 。 参见图 1.4.

 

图1.4:创建笔记本

  1. 从这里开始,我们将进入代码部分,首先导入 GitHub 上为第 1 章提供的 ts-spark_ch1_1.dbc 笔记本文件,具体操作如图 1.5 所示.

 

图1.5:导入笔记本

  1. 请注意, 您可以选择从 GitHub URL 下载第 1 章的文件到本地计算机后导入,该 URL 已在技术需求部分提供;或者按照图 1.6 所示,直接指定以下原始文件 URL 进行导入:https://github.com/PacktPublishing/Time-Series-Analysis-with-Spark/raw/main/ch1/ts-spark_ch1_1.dbc

 

图 1.6:从文件或 URL 导入笔记本

  1. 现在我们进入实际的代码部分。 此时您的笔记本中应该已经包含了图 1.7 所示的代码.

 

图1.7:包含代码的笔记本

  1. 最后,让我们运行代码。 按照全部运行按钮,如图 1.8 所示.

 

图1.8:运行笔记本中的所有代码

  1. 如果您尚未启动集群,则需要创建并启动一个新集群。 请注意,在 Databricks Community Edition 中,集群在闲置时会自动终止,此时您将看到附加集群已终止的提示信息(如图 1.9 所示),您需要选择其他资源。

 

图1.9:附加集群已终止

  1. 从此处开始,您可以选择附加到另一个活动集群(非终止状态的集群),或者按照图 1.10 所示创建新资源.

图1.10:计算 - 创建新资源

  1. 接下来,您需要为集群指定名称,并选择要使用的 Spark 版本,如图 1.11 所示。 此处建议使用最新版本,除非出于代码需要在其他环境中运行的兼容性考虑, 才选择较早版本。

 

图1.11:计算 - 创建、附加与运行

  1. 集群创建并启动后(在这个免费环境中可能需要几分钟时间),代码将运行,您会看到本章开头处图 1.1 中显示的图表作为输出。 用于创建和显示图表的图形库提供了交互式界面,例如允许您放大查看特定的时间段。
  2. 由于这是第一个实践环节,我们详细讲解了每个步骤。 在后续的实践章节中,我们将重点介绍特定数据集和代码,因为其余部分会非常相似。 当出现不同情况时,我们会提供额外说明。

现在我们已经执行了代码,接下来让我们回顾主要的部分。 在这个入门章节中,我们将保持高层次概述,待后续章节介绍完 Apache Spark 概念后, 再深入探讨细节:

  1. 这些 import 语句引入了用于日期格式转换和绘制图表的库:
    import pyspark.pandas as psimport plotly.express as px

    我们使用的是 pandas,这是一个开源 Python 数据操作库——更具体地说,是经过优化的 PySpark 版本, 专为 Spark 设计。

    Plotly 是一个支持交互式可视化的绘图库,它能将数据点转换为图表。

  2. 接着我们使用 spark.read 将 CSV 数据文件读取到表格中:
    df1 = spark.read.format(\"csv\") \\ .option(\"header\", \"true\") \\ .load(\"file:///\" + SparkFiles.get(DATASET_FILE))df1.createOrReplaceTempView(\"temperatures\")
  3. 该 spark.sql 语句根据名为 Category 的年份列从源数据集中选择子集:
    df2 = spark.sql(\"select to_date(Category) as year, float(`Annual Mean`) as annual_mean from temperatures where Category > \'1950\'\")
  4. 最后,我们绘制了时间序列以及基于普通最小二乘法 OLS)回归的趋势线,如图 1.1 所示:
    fig = px.scatter( df2_pd, x=\"year\", y=\"annual_mean\", trendline=\"ols\", title=\'Average Temperature - Mauritius (from 1950)\')
  5. 所使用的绘图库 plotly 支持用户界面交互功能,例如数据点的鼠标悬停信息以及缩放操作。

从现在开始, 您可以自由尝试代码和 Databricks Community Edition 环境,本书前几章的大部分内容都将使用该环境。

本节通过一个简单练习,您首次接触了时间序列和编程环境。 下一节我们将详细讨论目前介绍的一些概念,并将时间序列分解为其组成部分。

 

将时间序列分解为其组成部分

本节旨在通过分析时间序列的组成要素并详细说明目前已介绍的若干术语, 帮助您深入理解时间序列。 这将为后续章节奠定基础,使您能根据所分析时间序列的特性选用恰当方法。

时间序列模型可分解为三个主要组成部分:趋势、季节性和残差:

本书中的数学表达将采用简化的英文符号表示法,以便更广泛的读者理解。 关于时间序列的数学公式表述,请参考以下优秀资源:《预测:原理与实践》:Forecasting: Principles and Practice (3rd ed).

正如您将在接下来的实践部分看到的,这种分解为各组成部分的方法源自于对时间序列数据拟合的模型。 对于大多数现实数据集而言,这种分解只是模型对现实的近似。 因此,每个模型都会产生自己对各组成部分的识别和近似。 整个理念在于找到最适合该时间序列的模型。 这正是我们将在第 7 章关于构建和测试模型的内容中逐步展开讨论的。

让我们逐一讲解这些组件,定义它们的含义,并基于示例数据集进行可视化展示,如图 1.12 所示.

图1.12:时间序列分解

系统性和非系统性组件

水平、趋势、季节性和周期性被称为系统性成分。 它们代表了时间序列的基本结构,这种结构可以被建模从而进行预测。

除了系统性成分外,还存在一个非系统性部分,这部分无法建模,被称为残差、噪声或误差。 时间序列建模的目标是找到与系统性成分最匹配的模型,同时最小化残差。

接下来我们将详细探讨系统性和非系统性部分的每个细节。

水平值

水平值 ,也被称为基准水平,是序列的平均值,作为其他成分效应叠加的基准线。 有时,它会作为额外成分明确添加到前述公式中。 然而,水平值并不总是显现在公式里,因为它可能不是分析的主要焦点,或者分解方法可能已将其隐含在其他成分中。

趋势

趋势是表示时间序列值在一段时间内总体走向的组成部分:上升、下降或持平。 这种变化可以是线性的,如图 1.1 和图 1.12 所示,也可以是非线性的。 趋势本身可能在不同时间点发生变化,这些点我们称之为趋势转折点。 更广泛地说,转折点指的是时间线上时间序列统计特性发生变化的点。 这可能对模型参数甚至我们用于分析时间序列的模型产生重大影响。

季节性与周期性

季节性是指时间序列在固定时间间隔内发生的变化。这通常由季节性日历事件引起。 以温度为例,如图 1.12 所示,每年夏季月份温度会比其他月份升高,而冬季月份则会下降。 同理,礼品销售的时间序列在其季节性模式中,每年圣诞节期间的销售额通常都会呈现上升趋势。

多重季节性(周期和振幅)可以在同一时间序列中产生复合效应,如图 1.13 所示。 以温度为例,除了夏季和冬季的起伏变化外,温度还会在白天上升, 夜晚下降。

 

图1.13:多重重叠季节性(合成数据)

周期是指间隔发生的变动,类似于季节性变化,但区别在于其间隔并不规律。 时间序列中的周期反映了影响该序列的外部周期性因素。 例如经济衰退每隔若干年就会出现,并对经济指标产生影响。 我们无法提前预知其具体发生时间,这与圣诞节这类季节性事件不同——后者可准确预测,每年 12 月 25 日必定如期而至。

余数或残差

残差剩余量是指当模型已经解释了趋势、季节性和周期性后剩余的部分。 残差可以通过自回归 (AR)或移动平均 (MA)方法进行建模。 此时仍未被解释的剩余部分(也称为噪声或误差)具有随机性,是无法被建模的部分。 您可以在图 1.12 最上方的图表中,通过数据点与模型拟合线之间的距离来观察残差。 我们将探讨在第 6 章关于探索性数据分析中检验残差的方法。

虽然残差只是时间序列的一个随机组成部分,但整个序列可能完全随机,也可能是一个随机游走。 完全随机序列不会依赖于早期的时间值,而对于随机游走,时间点 t 的值则依赖于 t-1 时刻的值(加上一定的漂移和随机成分)。

加法或乘法

时间序列可以是加法 (前述公式)或乘法的。 在第一种情况下, 季节性和残差成分不依赖于趋势。 在第二种情况下,它们随趋势变化,可视为季节性成分的振幅变化——例如,更高的波峰和更低的波谷。

既然我们已经了解了时间序列的各个组成部分,现在让我们通过代码将其付诸实践。

实战演练:时间序列分解

为演示时间序列分解 ,我们将通过代码创建数据可视化图表,见图 1.12。 本节代码位于笔记本文件 ts-spark_ch1_2fp.dbc 中.

文件位置 URL 如下:https://github.com/PacktPublishing/Time-Series-Analysis-with-Spark/raw/main/ch1/ts-spark_ch1_2fp.dbc

我们将使用的数据集是 1981 至 1990 年澳大利亚墨尔本的日最低气温数据,原始数据来自澳大利亚气象局,可通过以下 Kaggle 链接获取:Daily Minimum Temperatures in Melbourne | Kaggle

数据集副本已提供在 GitHub 文件夹中,文件名为 ts-spark_ch1_ds2.csv.

本章我们将保持高层次概述,摘录部分笔记内容,待后续章节介绍更多预测模型概念后, 再深入探讨细节:

  1. 这些 import 语句导入了用于预测模型和绘制图表的库:
    from prophet import Prophetfrom prophet.plot import plot_plotly, plot_components_plotly

    使用的预测库是 Prophet,这是 Facebook 开源的库。 它兼顾专业与非专业用户,为时间序列数据提供自动预测功能。

  2. 接着我们使用 spark.read 将 CSV 数据文件读取到表格中:
    df1 = spark.read.format(\"csv\") \\ .option(\"header\", \"true\") \\ .load(\"file:///\" + SparkFiles.get(DATASET_FILE))df1.createOrReplaceTempView(\"temperatures\")
  3. spark.sql 语句将 date 和 daily_min_temperature 列转换为正确的格式和列名,这是 Prophet 所要求的:
    df2 = spark.sql(\"select to_date(date) as ds, float(daily_min_temperature) as y from temperatures sort by ds asc\")
  4. 随后,我们使用 Prophet 库基于 12 个月的季节性周期创建预测模型,并将其拟合到数据中:
    model = Prophet( n_changepoints=20, yearly_seasonality=True, changepoint_prior_scale=0.001)model.fit(df2_pd)
  5. 随后使用该模型预测未来日期的温度:
    future_dates = model.make_future_dataframe( periods=365, freq=\'D\')forecast = model.predict(future_dates)
  6. 最后,我们绘制出模型识别出的时间序列各分量, 如图 1.12 所示:
    plot_components_plotly(model, forecast)

    在初步讨论了组件和预测之后,现在让我们来探讨重叠季节性的情况。

多重重叠季节性

我们将通过代码创建图 1.13 中的数据可视化。 本节代码位于笔记本文件 ts-spark_ch1_3.dbc 中.

文件位置 URL 如下:https://github.com/PacktPublishing/Time-Series-Analysis-with-Spark/raw/main/ch1/ts-spark_ch1_3.dbc

该数据集是合成的,由三条不同的正弦曲线生成,代表三种重叠的季节性模式。

以下代码摘录自笔记本。 让我们从宏观层面来看:

  1. import 语句引入了用于数值计算和绘制图表的库:
    import numpy as npfrom plotly.subplots import make_subplots

    NumPy 是一个开源的 Python 科学计算库,在计算效率和内存使用上远优于标准 Python。 我们将在此使用它的数学函数。

  2. 我们随后生成多条正弦曲线,使用 np.sin 来表示不同的季节性特征,并将它们叠加起来:
    (amp, freq) = (3, 0.33)seasonality1 = amp * np.sin(2 * np.pi * freq * time_period)(amp, freq) = (2, 1)seasonality2 = amp * np.sin(2 * np.pi * freq * time_period)(amp, freq) = (1, 4)seasonality3 = amp * np.sin(2 * np.pi * freq * time_period)combined = seasonality1 + seasonality2 + seasonality3
  3. 最后,我们按照图 1.13 所示,分别绘制各个季节性分量及其组合结果。:
    fig = make_subplots(rows=4, cols=1, shared_xaxes=True)fig.add_scatter( x=time_period, y=seasonality1, row=1, col=1, name=f\"seasonality 1\")fig.add_scatter( x=time_period, y=seasonality2, row=2, col=1, name=f\"seasonality 2\")fig.add_scatter( x=time_period, y=seasonality3, row=3, col=1, name=f\"seasonality 3\")fig.add_scatter( x=time_period, y=combined, row=4, col=1, name=f\"combined\")fig.show()

    从这里开始,您可以随意在 notebooks 中试验完整代码。

在本节中,我们开启了时间序列分析的探索之旅,剖析其底层结构,并根据数据特性选择最合适的方法为后续分析铺路。 下一节将探讨需要纳入分析旅程的几个关键考量与挑战。

 

时间序列分析的额外考量因素

本节可能是本书前半部分最重要的章节。 在引言部分,我们提及了时间序列的一些关键特性,如时序顺序的保持、规律性及平稳性。 在此,我们将系统梳理现实项目中进行时间序列分析时面临的核心挑战与补充考量。 通过这种方式,您可以结合本书相关章节的指导以及延伸阅读资料,有针对性地规划学习与实践。

根据 《机器学习系统中的隐藏技术债务》 这篇 2015 年发表的知名论文所述,在高级分析项目中,只有一小部分精力是用于代码开发的。 其余时间主要花费在数据准备等基础设施相关工作上。

这些挑战的解决方案与您的具体情境密切相关。 本章旨在让您了解这些要点, 如图 1.14 所示 。

 

图1.14:时间序列分析的考量因素与挑战

尽管这些考量因素大多与非时间序列分析(如机器学习)相通,但时间序列分析往往是高级分析方法中最具挑战性的。 我们将在本书后续章节详细探讨这些挑战的解决方案。

应对数据挑战

与所有数据科学和机器学习项目一样,数据是关键。 您运行的分析和构建的模型质量完全取决于数据质量。 数据挑战多种多样,且高度依赖于您的具体应用场景和数据集。

我们将在此列出一些常见的示例:

  • 数据访问可能是所有工作的起点。 本书将使用多个可自由获取的数据集,因此这不会成为问题。 在实际项目中,你所需数据集的归属权可能属于组织的其他部门,甚至完全属于另一个组织。 这种情况下,你必须经历获取数据集的过程,可能需要支付费用,并以可接受的速度和时效性进行可靠传输。 传输管道本身需要构建成本,同时也会产生传输费用。 传输机制必须达到生产级标准以满足运营需求:健壮、可恢复、可监控等等。

    最初,您的数据访问需求将用于探索性数据分析和模型训练。 批量转储可能就足够了。 进入生产环境后,您可能需要实时或近实时地访问数据。 此时需要考虑的因素将大不相同。

数据一旦被摄取,下一个需求就是以安全且可用的方式存储它。 使用专门的时间序列数据库是一种针对性能优化的选择,不过在大多数情况下,通用存储就已足够:

  • 数据敏感性是另一个关键因素。 同样地,开发环境和生产环境对此往往会有不同要求。 不过在许多情况下,开发测试环节会使用生产数据的子集。 某些包含个人身份信息 PII)的字段需要进行脱敏或加密处理,以符合欧盟《通用数据保护条例》等法规要求。 在高度敏感的场景中,可能需要对整个数据集进行加密。 这对大规模数据处理构成挑战,因为每次数据访问都可能需要解密和重新加密。 这将产生一定的处理开销 。

    总之,端到端安全性和数据治理将成为您需求清单上的重中之重,且需从第一天就开始实施。 您需要避免开发等各阶段的安全与合规风险,处理敏感数据时更应如此。

  • 实时或近实时的高数据量与高频率数据流传输,需要合适的平台来实现无数据丢失的快速处理。 由于预生产环境规模较小,这一问题初期可能并不明显。 但当转入生产环境扩大规模时,性能和可靠性问题往往会滞后显现。 我们将在介绍 Apache Spark 后讨论扩展与流处理,这将帮助您规避此类问题。
  • 数据质量是我们早期就会面临的挑战,一旦解决了数据访问问题,在探索阶段和开发过程中开始处理数据时就会显现。 挑战包括数据缺失、数据损坏、数据噪声,对于时间序列数据而言更突出的是延迟和乱序问题。 如前一节所述,保持时间序列数据的时序性至关重要。 我们将在讨论数据准备时进一步探讨如何解决数据质量问题。

在克服数据挑战之后, 下一个重点领域是针对需要解决的问题选择合适的方法和模型。

选择合适的模型

这对时间序列分析的新手来说可能更具挑战性。 正如我们目前所见,时间序列具有不同的统计特性。 某些分析和建模方法是基于对时间序列统计特性的假设而创建的,其中平稳性是一个常见假设。 如果用于错误类型的时间序列,所采用的方法将无法按预期工作或导致误导性结果。 处理多重重叠季节性(假设您已首先识别出它们)对某些方法来说也可能是个挑战。 图 1.14 总结了时间序列类型与分析模型。 模型选择将在第 7 章 《 构建与测试模型》 中进一步讨论。.

选择合适的模型很大程度上取决于我们想要实现的结果,无论是预测未来一个或多个时间步长,还是同时分析一个(单变量)或多个(多变量)序列。 对于某些领域(如受监管行业),通常还需要模型具备可解释性,这对某些模型(如黑盒模型)来说可能较为困难。 我们将在下一章深入探讨时间序列分析的结果和模型选择,包括异常检测、模式识别以及预测建模等内容, 并阐述时间序列的重要性。

保持空间与时间层次结构

需注意另一个关键因素是数据收集与分析所遵循的层次结构。 不同层级之间需要保持一致性。 为说明这一点,我们以某连锁零售商对不同产品销量进行时间序列预测为例。 此处的空间层次可能涉及产品与产品类别层面,以及具体门店与区域层面。 时间层次则对应每小时、每日、每季度等维度的销售数据。 此案例的挑战在于确保单个产品与产品类别的预测一致性,以及确保(例如)日预测的汇总结果与季度预测保持协调。

最终,合适的模型取决于数据量,正如我们将在后续章节关于模型构建的讨论中所见。

应对可扩展性

影响可扩展性的主要因素有两个:数据量和处理复杂度。 之前我们已经将数据量作为数据挑战进行了讨论。 现在让我们重点探讨处理复杂度。 复杂度可能源自数据使用前所需的转换程度,以及需要管理的模型数量、层级结构和规模:

  • 模型数量庞大且层级复杂 :在实际项目中,您经常需要在较短时间内并行运行数十甚至数千个模型——例如,如果您在商店工作,需要预测店内销售的数千种商品次日的销量和库存水平。 这种并行需求正是使用 Apache Spark 的关键原因之一,我们将在本书后续内容中详细探讨。
  • 模型规模 :可扩展性的另一个要求来自模型本身的大小,如果我们使用具有多层和节点的深度学习技术,模型可能会非常庞大且计算要求很高。

我们将在本书后续章节中专门用一整章来讨论扩展性问题。

接近实时

此前,我们已指出高频数据是一项重大数据挑战。 要实现准实时处理, 不仅需要数据层面的调整,还需构建能够满足此类需求的处理流水线。 通常,模型会基于历史收集的批量数据进行训练,然后部署用于预测或异常检测等任务——这些场景中实时处理至关重要。 以欺诈交易检测为例,必须尽可能在事件发生时即时识别异常。Apache Spark 结构化流处理是实现近即时数据处理的可行方案,我们将在本书后续讨论 Apache Spark 时深入探讨。

生产环境管理

上述考量同样适用于生产环境。 此外,将开发完成的解决方案迁移至生产环境还需满足多项特定要求。 若处理不当, 这些要求可能引发挑战。

一旦训练出合适的模型并准备就绪,下一步就是将其与所需的 API 封装层、数据管道以及模型消费应用程序代码打包在一起。 这涉及一个贯穿 DataOps、ModelOps 和 DevOps 的端到端流程。 我们将在第 9 章详细探讨这些内容,届时我们将讨论生产环境部署。

 

监控与处理模型漂移

当模型投入使用后,随时间推移会产生变化,导致模型不再适用。 这些变化主要分为以下几类:

  • 数据集本质的变化( 数据漂移 
  • 输入与输出之间关系的变化( 概念漂移 
  • 诸如新冠疫情等意外事件,或建模过程中遗漏的重大事件( 突发性漂移 ,属于概念漂移的一种)

这些漂移现象会影响模型性能,因此需要持续监控。 通常的解决方案是基于新数据重新训练模型,或寻找在更新后的数据集上表现更好的新模型。

本节概述了处理时间序列数据时的注意事项与挑战。 虽然与其他数据集存在诸多共性,但这里的指导原则在更广泛场景中同样适用。 不过正如引言部分所述,时间序列数据具有其独特的考量维度。

概述

时间序列无处不在,本章介绍了它们的概念、组成要素以及处理过程中面临的挑战。 我们从一些简单的代码入手探索时间序列,为后续章节的实践打下基础。 首章讨论的这些概念将作为基石,最终引导我们在本书结束时实现大规模时间序列分析。

既然您已经了解了时间序列的\"是什么\",在下一章中,我们将探讨\"为什么\",这将为各个领域的应用铺平道路。