查看原文
其他

使用 Ruptures 识别时间序列数据中的变化点

大邓 大邓和他的Python
2024-09-09

时间序列数据 在各个领域中都占据着重要地位,从金融市场到生产制造,都需要对时间序列数据进行分析和监测。其中一个关键任务是识别时间序列数据中的变化点,这些变化点可能代表了重要的事件或趋势转折点。例如之前分享过 金融研究 | 央行货币政策文本相似度计算与可视化 ,  仅仅构造了相似度时序数据, 但是如果要做让程序自动识别政策变化时间点, 还需要今日分享的内容。

为了解决这一问题,Ruptures 库是一个非常强大的工具,它提供了多种算法,可用于检测时间序列数据的变化点。本文将介绍如何使用 Ruptures 库来解决时间序列数据分析中的变化点检测问题。


一、问题场景

在各种应用场景中,需要识别时间序列数据中的变化点,例如:

  1. 金融市场:检测股票价格中的趋势转折点,以指导投资决策。
  2. 生产制造:监测生产线上的设备状态变化,及时发现问题并采取措施维护。
  3. 气象数据:发现天气数据中的异常变化,如风暴的到来或气温剧烈波动。
  4. 网络流量:检测网络流量中的异常行为,可能是网络攻击的迹象。

在这些场景下,Ruptures 库可以帮助我们识别变化点,从而更好地理解时间序列数据的特点。



二、Ruptures 库介绍

Ruptures 库是一个用于信号分割和变化点检测的 Python 库,它提供了多种算法和工具,可用于处理不同类型的时间序列数据。

以下是 Ruptures 库的一些关键特点:

  • 多种算法支持:Ruptures 提供了多种变化点检测算法,包括 Pelt、Binary Segmentation、Window-based Methods 等,适用于不同类型的时间序列数据和问题。
  • 简单易用:库的 API 设计简洁,容易上手,用户可以轻松地进行变化点检测任务。
  • 高性能:Ruptures 经过优化,能够处理大规模的时间序列数据集,同时具有较低的计算复杂度。

三、常用算法

下面是 Ruptures 库中常用的一些变化点检测算法:

  1. Pelt (Pruned Exact Linear Time):Pelt算法是一种基于动态规划的算法,适用于多个变化点的检测任务。它的优点在于其精确性和高效性,通常能够找到全局最优的变化点位置。Pelt算法通过将时间序列数据划分为多个分段,使得每个分段内的变化点数目最小化,从而找到最优的分段方式。
  2. Binary Segmentation (BS):Binary Segmentation算法是一种简单而有效的分割方法,通过迭代地将时间序列数据分为两个部分来检测变化点。该算法的计算复杂度较低,适用于中等规模的数据集。主要缺点是可能会导致分段的粒度过粗。
  3. Window-based Methods:这些方法使用滑动窗口的方式来检测时间序列数据中的变化点。窗口会在时间序列上滑动,对窗口内的数据进行分析,然后根据某种准则来确定窗口内是否存在变化点。优点是简单易懂,但需要调整窗口大小和准则参数。
  4. Bottom-Up Methods:Bottom-Up方法从小的分段开始,逐渐合并以检测变化点。它从最小的分段(每个数据点都是一个分段)开始,然后合并相邻的分段,直到满足某种准则为止。优点在于能够处理多个变化点,但计算复杂度较高。



四、实验

4.1 导入包

导入本文需要的包, 使得matplotlib支持中文,绘制高清图;

import matplotlib.pyplot as plt
import ruptures as rpt
import matplotlib

#绘制高清图
import matplotlib_inline
matplotlib_inline.backend_inline.set_matplotlib_formats('png''svg')

#支持中文
import platform
system = platform.system()  # 获取操作系统类型
if system == 'Windows':
    font = {'family''SimHei'}
elif system == 'Darwin':
    font = {'family''Arial Unicode MS'}
else:
    font = {'family''sans-serif'}
matplotlib.rc('font', **font)  # 设置全局字体

4.2 生成实验数据

# 生成示例时间序列数据
n_samples, dim, sigma = 100011
n_bkps = 4  # 假设有4个变化点
signal, bkps = rpt.pw_constant(n_samples, dim, n_bkps, noise_std=sigma)
print(signal.shape)
print(bkps)
signal

Run

(1000, 1)
[203, 408, 603, 789, 1000]

array([[-3.72701244],
       [-3.5992294 ],
       [-5.37957509],
       [-3.58538893],
       [-3.19651608],
       [-4.48293727],
       [-1.58468434],
       ...
       [11.66240607],
       [12.74493248],
       [12.54103519],
       [12.41838346],
       [13.94702808],
       [13.36888594],
       [12.20846486],
       [11.68636148]])

ruptures为我们生成的实验数据signal是一个长度为1000的array型数据。生成的变化点bkps的位置序列[203, 408, 603, 789, 1000]。数据不够直观,我们可视化一下


# 创建时间序列图
plt.figure(figsize=(126))
plt.plot(signal, lw=2, label='时间序列数据')
plt.legend()

#保存
plt.savefig('ts-data.png', dpi=200)

# 显示
plt.show()

从上图可以清楚的看到,ruptures为我们生成了1000个点,大致有4个变化点,将数据分成了五部分。现在我们使用ruptures为我们识别变化点


4.3 识别变化点

Pelt算法是Ruptures库中的一种高效而准确的变化点检测算法,它的全称是Pruned Exact Linear Time(修剪的线性时间精确算法)。它的性能取决于成本函数的选择和 pen参数的调整,pen 参数的全称是 Penalty,它代表了在检测到变化点时的成本或惩罚值。这里将 pen 设置为 10

# 使用 Ruptures 库进行变化点检测
algo = rpt.Pelt(model="rbf").fit(signal)
result = algo.predict(pen=10)

# 绘制结果
rpt.display(signal, bkps, result)
plt.title("变化点检测示例")

#保存图
plt.savefig('change-point.png', dpi=200)

#显示
plt.show()


4.4 关于pen

更具体地说,pen 参数的值越大,算法就会倾向于检测更少的变化点,而值越小,算法就会倾向于检测更多的变化点。

通常情况下,您可以根据自己的数据和问题来调整pen参数的值。以下是一些常见的情况和建议:

  1. 如果您希望检测到较少的变化点,以捕捉主要的趋势转折点,可以选择较大的pen值。
  2. 如果您希望检测到更多的变化点,以捕捉数据中的细微变化,可以选择较小的pen值。
  3. 如果您不确定要选择哪个pen值,可以尝试多个不同的值,然后根据结果的质量和实际需求来选择最合适的pen值。

在实践中,调整pen参数通常需要一些试验和经验,因为最佳的pen值取决于您的数据和分析目标。您可以尝试不同的pen值,然后根据检测结果和领域知识来选择最适合的参数值。


精选内容

LIST | 社科(经管)数据挖掘文献资料汇总

LIST | 文本分析代码资料汇总

LIST | 可供社科(经管)领域研究使用的数据集

代码 | 如何处理远超电脑内存的csv文件

使用3751w专利申请数据集按年份(按省份)训练词向量

以聚类为例 | 使用大语言模型LLM做文本分析

继续滑动看下一个
大邓和他的Python
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存