使用递归图分析时间序列的有效性与应用

本文介绍了递归图的概念及其在时间序列分析中的应用,强调其可视化和公共数据分析的优势。

原文标题:使用递归图 recurrence plot 表征时间序列

原文作者:数据派THU

冷月清谈:

本文介绍了递归图(Recurrence Plots)的概念及其在时间序列分析中的应用,特别是如何通过Python代码生成不同类型时间序列的递归图。文章通过模拟白噪声、随机游走、SARIMA模型、混沌模型和标准普尔500指数数据,展示了如何可视化时间序列并发掘其中的重复模式和结构。递归图的核心在于测量时间序列中各点之间的相似性,通过适当的阈值设置,可以有效揭示时间序列中的周期性和复杂性。此外,文章还强调了递归图在多个研究领域中的重要性,如金融分析、振动分析等,提供了研究者深入理解时间序列的工具。

怜星夜思:

1、递归图在时间序列分析中有什么潜在的缺陷吗?
2、除了时间序列,递归图还可以应用于哪些领域?
3、如何选择合适的阈值对于递归图分析来讲尤为重要,我们应该注意哪些因素?

原文内容

图片
来源:DeepHub IMBA

本文约2200字,建议阅读5分钟

本文将展示如何使用递归图 Recurrence Plots 来描述不同类型的时间序列。


在本文中,我将展示如何使用递归图 Recurrence Plots 来描述不同类型的时间序列。我们将查看具有500个数据点的各种模拟时间序列。我们可以通过可视化时间序列的递归图并将其与其他已知的不同时间序列的递归图进行比较,从而直观地表征时间序列。


递归图


Recurrence  Plots(RP)是一种用于可视化和分析时间序列或动态系统的方法。它将时间序列转化为图形化的表示形式,以便分析时间序列中的重复模式和结构。


Recurrence Plots 是非常有用的,尤其是在时间序列数据中存在周期性、重复事件或关联结构时。


Recurrence Plots 的基本原理是测量时间序列中各点之间的相似性。如果两个时间点之间的距离小于某个给定的阈值,就会在 Recurrence Plot 中绘制一个点,表示这两个时间点之间存在重复性。这些点在二维平面上组成了一种图像。


import numpy as np
import matplotlib.pyplot as plt

def recurrence_plot(data, threshold=0.1):
“”"
Generate a recurrence plot from a time series.

:param data: Time series data
:param threshold: Threshold to determine recurrence
:return: Recurrence plot
“”"

Calculate the distance matrix

N = len(data)
distance_matrix = np.zeros((N, N))
for i in range(N):
for j in range(N):
distance_matrix[i, j] = np.abs(data[i] - data[j])

Create the recurrence plot

recurrence_plot = np.where(distance_matrix <= threshold, 1, 0)

return recurrence_plot

上面的代码创建了一个二进制距离矩阵,如果时间序列i和j的值相差在0.1以内(阈值),则它们的值为1,否则为0。得到的矩阵可以看作是一幅图像。


白噪声


接下来我们将可视化白噪声。首先,我们需要创建一系列模拟的白噪声:


# Set a seed for reproducibility
np.random.seed(0)

Generate 500 data points of white noise

white_noise = np.random.normal(size=500)

Plot the white noise time series

plt.figure(figsize=(10, 6))
plt.plot(white_noise, label=‘White Noise’)
plt.title(‘White Noise Time Series’)
plt.xlabel(‘Time’)
plt.ylabel(‘Value’)
plt.legend()
plt.grid(True)
plt.show()



递归图为这种白噪声提供了有趣的可视化效果。对于任何一种白噪声,图看起来都是一样的:


# Generate and plot the recurrence plot
recurrence = recurrence_plot(white_noise, threshold=0.1)

plt.figure(figsize=(8, 8))
plt.imshow(recurrence, cmap=‘binary’, origin=‘lower’)
plt.title(‘Recurrence Plot’)
plt.xlabel(‘Time’)
plt.ylabel(‘Time’)
plt.colorbar(label=‘Recurrence’)
plt.show()



可以直观地看到一个嘈杂的过程。可以看到图中对角线总是黑色的。


随机游走


接下来让我们看看随机游走(Random Walk)是什么样子的:


# Generate 500 data points of a random walk
steps = np.random.choice([-1, 1], size=500) # Generate random steps: -1 or 1
random_walk = np.cumsum(steps) # Cumulative sum to generate the random walk

Plot the random walk time series

plt.figure(figsize=(10, 6))
plt.plot(random_walk, label=‘Random Walk’)
plt.title(‘Random Walk Time Series’)
plt.xlabel(‘Time’)
plt.ylabel(‘Value’)
plt.legend()
plt.grid(True)
plt.show()


# Generate and plot the recurrence plot
recurrence = recurrence_plot(random_walk, threshold=0.1)

plt.figure(figsize=(8, 8))
plt.imshow(recurrence, cmap=‘binary’, origin=‘lower’)
plt.title(‘Recurrence Plot’)
plt.xlabel(‘Time’)
plt.ylabel(‘Time’)
plt.colorbar(label=‘Recurrence’)
plt.show()


SARIMA


SARIMA(4,1,4)(1,0,0,12)的模拟数据


from statsmodels.tsa.statespace.sarimax import SARIMAX

Define SARIMA parameters

p, d, q = 4, 1, 4 # Non-seasonal order
P, D, Q, s = 1, 0, 0, 12 # Seasonal order

Simulate data

model = SARIMAX(np.random.randn(100), order=(p, d, q), seasonal_order=(P, D, Q, s), trend=‘ct’)
fit = model.fit(disp=False) # Fit the model to random data to get parameters
simulated_data = fit.simulate(nsimulations=500)

Plot the simulated time series

plt.figure(figsize=(10, 6))
plt.plot(simulated_data, label=f’SARIMA({p},{d},{q})({P},{D},{Q},{s})')
plt.title(‘Simulated Time Series from SARIMA Model’)
plt.xlabel(‘Time’)
plt.ylabel(‘Value’)
plt.legend()
plt.grid(True)
plt.show()


recurrence = recurrence_plot(simulated_data, threshold=0.1)

plt.figure(figsize=(8, 8))
plt.imshow(recurrence, cmap=‘binary’, origin=‘lower’)
plt.title(‘Recurrence Plot’)
plt.xlabel(‘Time’)
plt.ylabel(‘Time’)
plt.colorbar(label=‘Recurrence’)
plt.show()



混沌的数据


def logistic_map(x, r):
"""Logistic map function."""
return r * x * (1 - x)

Initialize parameters

N = 500 # Number of data points
r = 3.9 # Parameter r, set to a value that causes chaotic behavior
x0 = np.random.rand() # Initial value

Generate chaotic time series data

chaotic_data = [x0]
for _ in range(1, N):
x_next = logistic_map(chaotic_data[-1], r)
chaotic_data.append(x_next)

Plot the chaotic time series

plt.figure(figsize=(10, 6))
plt.plot(chaotic_data, label=f’Logistic Map (r={r})')
plt.title(‘Chaotic Time Series’)
plt.xlabel(‘Time’)
plt.ylabel(‘Value’)
plt.legend()
plt.grid(True)
plt.show()


recurrence = recurrence_plot(chaotic_data, threshold=0.1)

plt.figure(figsize=(8, 8))
plt.imshow(recurrence, cmap=‘binary’, origin=‘lower’)
plt.title(‘Recurrence Plot’)
plt.xlabel(‘Time’)
plt.ylabel(‘Time’)
plt.colorbar(label=‘Recurrence’)
plt.show()



标准普尔500指数


作为最后一个例子,让我们看看从2013年10月28日至2023年10月27日的标准普尔500指数真实数据:


import pandas as pd

df = pd.read_csv(‘standard_and_poors_500_idx.csv’, parse_dates=True)
df[‘Date’] = pd.to_datetime(df[‘Date’])
df.set_index(‘Date’, inplace = True)
df.drop(columns = [‘Open’, ‘High’, ‘Low’], inplace = True)

df.plot()
plt.title(‘S&P 500 Index - 10/28/2013 to 10/27/2023’)
plt.ylabel(‘S&P 500 Index’)
plt.xlabel(‘Date’);


图片


recurrence = recurrence_plot(df['Close/Last'], threshold=10)

plt.figure(figsize=(8, 8))
plt.imshow(recurrence, cmap=‘binary’, origin=‘lower’)
plt.title(‘Recurrence Plot’)
plt.xlabel(‘Time’)
plt.ylabel(‘Time’)
plt.colorbar(label=‘Recurrence’)
plt.show()



选择合适的相似性阈值是 递归图分析的一个关键步骤。较小的阈值会导致更多的重复模式,而较大的阈值会导致更少的重复模式。阈值的选择通常需要根据数据的特性和分析目标进行调整。


这里我们不得不调整阈值,最终确得到的结果为10,这样可以获得更大的对比度。上面的递归图看起来很像随机游走递归图和无规则的混沌数据的混合体。


总结


在本文中,我们介绍了递归图以及如何使用Python创建递归图。递归图给了我们一种直观表征时间序列图的方法。递归图是一种强大的工具,用于揭示时间序列中的结构和模式,特别适用于那些具有周期性、重复性或复杂结构的数据。通过可视化和特征提取,研究人员可以更好地理解时间序列数据并进行进一步的分析。


从递归图中可以提取各种特征,以用于进一步的分析。这些特征可以包括重复点的分布、Lempel-Ziv复杂度、最长对角线长度等。


递归图在多个领域中得到了广泛应用,包括时间序列分析、振动分析、地震学、生态学、金融分析、生物医学等。它可用于检测周期性、异常事件、相位同步等。


编辑:于腾凯
校对:林亦霖

其实在气象数据分析上也挺有用,它能帮助我们找出天气变化中的周期性模式。

可以考虑数据的分布特征,不同的数据分布可能需要不同的阈值设置。观察数据的历史背景也很重要。

我觉得递归图有时候对噪声比较敏感,可能会误导我们分析实际的趋势,尤其是在数据集比较大的时候。

潜在的缺陷是阈值选择的不当可能导致信息损失,或者隐藏重要的模式。如何选择合适的阈值确实是一门艺术。

也有可能是我们不能简单依赖一个工具进行全面分析,应该结合其他统计工具来交叉验证结果。

递归图在生态学和生物医学中也有应用,可以用来分析生态系统或疾病进展中的周期性现象。

当然还可以用于图像处理,测量图像特征之间的相似性,研究图像中的重复结构!

我觉得还应该注意分析的目的,比如如果要找周期性,可能就需要设置得更小一些,以找出更多的重复模式。

一些领域的专家建议,可以通过多次实验来验证,找出一个最优阈值的范围,然后缩小范围来测试。