Python实现时间序列数据的特征工程:滑动窗口、傅里叶变换与小波分析

好的,没问题。下面是关于Python时间序列数据特征工程的讲座内容:

Python时间序列数据的特征工程:滑动窗口、傅里叶变换与小波分析

大家好!今天我们来聊聊时间序列数据的特征工程,重点是滑动窗口、傅里叶变换和小波分析这三个强大的技术。特征工程在机器学习中扮演着至关重要的角色,对于时间序列数据更是如此。精心设计的特征可以显著提升模型的预测能力和泛化能力。

一、时间序列特征工程的重要性

时间序列数据是按照时间顺序排列的一系列数据点,广泛存在于金融、气象、医疗等领域。直接使用原始的时间序列数据通常无法取得好的模型效果,原因在于:

  • 数据噪声: 原始数据可能包含大量的噪声,这些噪声会干扰模型的学习。
  • 非平稳性: 许多时间序列数据是非平稳的,即其统计特性(如均值、方差)随时间变化。非平稳性会影响模型的预测精度。
  • 隐藏模式: 时间序列数据中可能隐藏着一些复杂的模式,例如季节性、趋势性和周期性。这些模式难以直接从原始数据中提取。

特征工程的目标就是从原始数据中提取有用的信息,去除噪声,使数据更适合机器学习模型的训练。通过合理的特征工程,我们可以更好地捕捉时间序列数据的内在规律,从而提高模型的预测准确性和鲁棒性。

二、滑动窗口(Rolling Window)

滑动窗口是一种简单而有效的特征工程技术,它通过在一个固定大小的窗口内对时间序列数据进行统计计算,从而生成新的特征。

2.1 原理

滑动窗口沿着时间序列移动,每次移动一个或多个时间步长。在每个窗口内,我们可以计算各种统计量,例如均值、标准差、最大值、最小值等。这些统计量可以作为新的特征,反映时间序列在局部窗口内的变化情况。

2.2 代码实现 (Python + Pandas)

import pandas as pd
import numpy as np

# 创建一个示例时间序列
data = pd.Series(np.random.randn(100))

# 设置窗口大小
window_size = 10

# 计算滑动窗口均值
rolling_mean = data.rolling(window=window_size).mean()

# 计算滑动窗口标准差
rolling_std = data.rolling(window=window_size).std()

# 计算滑动窗口最大值
rolling_max = data.rolling(window=window_size).max()

# 计算滑动窗口最小值
rolling_min = data.rolling(window=window_size).min()

# 将结果合并成一个DataFrame
features = pd.DataFrame({
    'rolling_mean': rolling_mean,
    'rolling_std': rolling_std,
    'rolling_max': rolling_max,
    'rolling_min': rolling_min
})

# 打印前几行数据
print(features.head())

2.3 参数说明

  • window_size: 窗口大小,决定了每次计算统计量时使用的数据点数量。
  • min_periods: 窗口内所需的最少数据点数量。如果窗口内的数据点数量小于 min_periods,则计算结果为 NaN
  • center: 是否将窗口中心对齐当前时间点。如果为 True,则窗口中心对齐当前时间点;如果为 False,则窗口起始位置对齐当前时间点。
  • axis: 沿哪个轴进行滑动窗口计算。对于一维时间序列,axis 默认为 0。

2.4 应用场景

  • 趋势分析: 滑动窗口均值可以用来平滑时间序列,从而更清晰地观察趋势。
  • 波动性分析: 滑动窗口标准差可以用来衡量时间序列的波动性。
  • 异常检测: 通过比较当前值与滑动窗口的统计量,可以检测异常值。

2.5 示例:趋势识别与波动性分析

假设我们有一段股票价格的时间序列数据,我们可以使用滑动窗口来分析其趋势和波动性。

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

# 创建一个示例股票价格时间序列
np.random.seed(42) # 设置随机种子,保证结果可重复
dates = pd.date_range(start='2023-01-01', periods=200, freq='D')
prices = np.cumsum(np.random.randn(200) + 0.05)  # 模拟股票价格,总体向上趋势
data = pd.Series(prices, index=dates)

# 设置窗口大小
window_size = 30

# 计算滑动窗口均值 (趋势)
rolling_mean = data.rolling(window=window_size).mean()

# 计算滑动窗口标准差 (波动性)
rolling_std = data.rolling(window=window_size).std()

# 绘制原始数据、滑动窗口均值和滑动窗口标准差
plt.figure(figsize=(12, 6))
plt.plot(data, label='Original Prices')
plt.plot(rolling_mean, label=f'Rolling Mean (Window = {window_size})', color='red')
plt.plot(rolling_std, label=f'Rolling Std (Window = {window_size})', color='green')
plt.title('Stock Price Trend and Volatility Analysis')
plt.xlabel('Date')
plt.ylabel('Price / Standard Deviation')
plt.legend()
plt.grid(True)
plt.show()

这段代码会生成一个图表,其中包含原始股票价格、滑动窗口均值和滑动窗口标准差。通过观察滑动窗口均值,我们可以清晰地看到股票价格的总体趋势。通过观察滑动窗口标准差,我们可以了解股票价格的波动性。波动性越高,风险越大。

三、傅里叶变换(Fourier Transform)

傅里叶变换是一种将时间序列从时域转换到频域的技术。在频域中,我们可以分析时间序列的频率成分,提取周期性特征。

3.1 原理

傅里叶变换将一个时间序列分解成一系列不同频率的正弦和余弦函数的组合。每个频率分量都有一个振幅和一个相位。振幅表示该频率分量在时间序列中的强度,相位表示该频率分量的起始位置。

3.2 代码实现 (Python + NumPy)

import numpy as np
import matplotlib.pyplot as plt

# 创建一个示例时间序列 (包含周期性)
time = np.arange(0, 100, 0.1)
signal = np.sin(2 * np.pi * 0.05 * time) + np.cos(2 * np.pi * 0.1 * time) + np.random.randn(len(time)) * 0.1

# 进行傅里叶变换
fft = np.fft.fft(signal)

# 计算频率
frequencies = np.fft.fftfreq(signal.size, d=0.1) # d 是采样间隔

# 计算振幅谱
amplitudes = np.abs(fft)

# 绘制原始信号和振幅谱
plt.figure(figsize=(12, 6))

plt.subplot(2, 1, 1)
plt.plot(time, signal)
plt.title('Original Signal')
plt.xlabel('Time')
plt.ylabel('Amplitude')

plt.subplot(2, 1, 2)
plt.plot(frequencies, amplitudes)
plt.title('Amplitude Spectrum')
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.xlim(0, 0.5)  # 限制频率范围,方便观察
plt.grid(True)

plt.tight_layout()
plt.show()

3.3 参数说明

  • np.fft.fft(signal): 对时间序列 signal 进行傅里叶变换。
  • np.fft.fftfreq(signal.size, d=0.1): 计算傅里叶变换的频率。 signal.size 是时间序列的长度,d 是采样间隔。
  • np.abs(fft): 计算傅里叶变换结果的振幅。

3.4 应用场景

  • 周期性分析: 傅里叶变换可以用来检测时间序列中的周期性模式。例如,我们可以使用傅里叶变换来分析股票价格的季节性波动。
  • 异常检测: 异常值可能会导致频谱发生变化,因此我们可以使用傅里叶变换来检测异常值。
  • 信号滤波: 我们可以通过在频域中过滤掉某些频率分量来去除噪声。

3.5 示例:识别时间序列的周期

import numpy as np
import matplotlib.pyplot as plt

# 创建一个示例时间序列 (包含周期性)
time = np.arange(0, 200)
period = 50  # 周期
signal = np.sin(2 * np.pi * time / period) + np.random.randn(len(time)) * 0.2

# 进行傅里叶变换
fft = np.fft.fft(signal)
frequencies = np.fft.fftfreq(signal.size)
amplitudes = np.abs(fft)

# 找到振幅最大的频率 (排除频率为0的成分)
peak_frequency_index = np.argmax(amplitudes[1:]) + 1 # +1 是因为我们排除了第一个元素(频率为0)
peak_frequency = frequencies[peak_frequency_index]

# 计算周期
estimated_period = 1 / abs(peak_frequency)

# 绘制原始信号和振幅谱
plt.figure(figsize=(12, 6))

plt.subplot(2, 1, 1)
plt.plot(time, signal)
plt.title('Original Signal')
plt.xlabel('Time')
plt.ylabel('Amplitude')

plt.subplot(2, 1, 2)
plt.plot(frequencies, amplitudes)
plt.title('Amplitude Spectrum')
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.xlim(0, 0.2)
plt.grid(True)

plt.tight_layout()
plt.show()

print(f"Estimated Period: {estimated_period}")
print(f"True Period: {period}")

这段代码首先创建一个包含周期性信号的时间序列。然后,我们使用傅里叶变换计算振幅谱,并找到振幅最大的频率。最后,我们根据该频率计算出估计的周期。

四、小波分析(Wavelet Analysis)

小波分析是一种比傅里叶变换更高级的信号处理技术。它可以在时域和频域上同时分析时间序列数据,提取局部时频特征。

4.1 原理

与傅里叶变换使用正弦和余弦函数作为基函数不同,小波分析使用小波函数作为基函数。小波函数是一种具有有限持续时间的波形。通过对小波函数进行伸缩和平移,我们可以得到一系列不同尺度和位置的小波。

小波分析将时间序列分解成不同尺度的小波系数。每个尺度的小波系数反映了时间序列在该尺度下的局部特征。小波分析可以捕捉时间序列中的瞬时变化和非平稳性。

4.2 代码实现 (Python + PyWavelets)

import pywt
import numpy as np
import matplotlib.pyplot as plt

# 创建一个示例时间序列
time = np.arange(0, 100, 0.1)
signal = np.sin(2 * np.pi * 0.05 * time) + np.cos(2 * np.pi * 0.1 * time) + np.random.randn(len(time)) * 0.1

# 进行小波分解
wavelet = 'haar'  # 选择小波基函数
coeffs = pywt.wavedec(signal, wavelet, level=3) # 分解到3层

# 绘制原始信号和分解系数
plt.figure(figsize=(12, 8))

plt.subplot(4, 1, 1)
plt.plot(time, signal)
plt.title('Original Signal')
plt.xlabel('Time')
plt.ylabel('Amplitude')

plt.subplot(4, 1, 2)
plt.plot(coeffs[0]) # Approximation Coefficients (低频)
plt.title('Approximation Coefficients (Level 3)')
plt.xlabel('Index')
plt.ylabel('Amplitude')

plt.subplot(4, 1, 3)
plt.plot(coeffs[1]) # Detail Coefficients (高频)
plt.title('Detail Coefficients (Level 3)')
plt.xlabel('Index')
plt.ylabel('Amplitude')

plt.subplot(4, 1, 4)
plt.plot(coeffs[2]) # Detail Coefficients (高频)
plt.title('Detail Coefficients (Level 2)')
plt.xlabel('Index')
plt.ylabel('Amplitude')

plt.tight_layout()
plt.show()

4.3 参数说明

  • pywt.wavedec(signal, wavelet, level): 对时间序列 signal 进行小波分解。 wavelet 是小波基函数的名称,level 是分解的层数。
  • coeffs: 小波分解系数。 coeffs[0] 是近似系数(低频成分),coeffs[1:] 是细节系数(高频成分)。

4.4 应用场景

  • 去噪: 小波分析可以用来去除时间序列中的噪声。通过将细节系数设置为零,我们可以去除高频噪声。
  • 特征提取: 小波系数可以作为时间序列的特征。不同尺度的小波系数反映了时间序列在不同尺度下的局部特征。
  • 异常检测: 异常值可能会导致小波系数发生变化,因此我们可以使用小波分析来检测异常值。

4.5 示例:使用小波分析进行去噪

import pywt
import numpy as np
import matplotlib.pyplot as plt

# 创建一个示例时间序列 (包含噪声)
time = np.arange(0, 100, 0.1)
signal = np.sin(2 * np.pi * 0.05 * time) + np.cos(2 * np.pi * 0.1 * time) + np.random.randn(len(time)) * 0.5

# 进行小波分解
wavelet = 'db4'  # Daubechies小波
coeffs = pywt.wavedec(signal, wavelet, level=4)

# 设置阈值,去除细节系数
threshold = np.std(coeffs[-1]) * 2 # 使用最后一层细节系数的标准差的两倍作为阈值
coeffs_thresholded = coeffs[:] # 复制一份系数
for i in range(1, len(coeffs_thresholded)):
    coeffs_thresholded[i] = pywt.threshold(coeffs[i], threshold, mode='soft') # 使用软阈值处理

# 重构信号
signal_denoised = pywt.waverec(coeffs_thresholded, wavelet)

# 绘制原始信号和去噪后的信号
plt.figure(figsize=(12, 6))
plt.plot(time, signal, label='Original Signal (Noisy)')
plt.plot(time[:len(signal_denoised)], signal_denoised, label='Denoised Signal', color='red')
plt.title('Wavelet Denoising')
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.legend()
plt.grid(True)
plt.show()

这段代码首先创建一个包含噪声的时间序列。然后,我们使用小波分析对时间序列进行分解,并设置一个阈值。我们将所有小于该阈值的细节系数设置为零,然后使用重构后的系数重构信号。最后,我们绘制原始信号和去噪后的信号。

五、总结性的观点

  • 滑动窗口适用于提取局部统计特征,如趋势和波动性。
  • 傅里叶变换适用于分析周期性模式,但对非平稳信号效果有限。
  • 小波分析适用于处理非平稳信号,可以同时提取时域和频域特征。

六、特征选择与模型构建

完成了特征工程之后,下一步就是特征选择和模型构建。

  • 特征选择: 并非所有提取的特征都对模型有帮助。我们需要选择那些与目标变量相关性高、且具有预测能力的特征。常用的特征选择方法包括:
    • 过滤法(Filter methods): 独立于模型的特征选择方法,例如方差选择、相关系数选择等。
    • 包装法(Wrapper methods): 将特征选择看作一个搜索问题,例如递归特征消除(RFE)。
    • 嵌入法(Embedded methods): 将特征选择嵌入到模型训练过程中,例如L1正则化。
  • 模型构建: 选择合适的机器学习模型,例如线性回归、支持向量机、决策树、随机森林、LSTM等。根据具体问题和数据特点选择最合适的模型。

七、特征工程的迭代优化

特征工程是一个迭代的过程。我们需要不断地尝试不同的特征组合,评估模型的性能,并根据评估结果调整特征工程策略。

  • 领域知识: 结合领域知识可以帮助我们更好地理解数据,并设计出更有效的特征。
  • 可视化: 可视化可以帮助我们发现数据中的模式和异常,并评估特征的质量。
  • 模型评估: 使用合适的评估指标来评估模型的性能,例如均方误差、均方根误差、平均绝对误差等。

特征工程是时间序列分析中至关重要的一环,它直接影响着模型的预测效果。希望通过今天的分享,大家能够掌握滑动窗口、傅里叶变换和小波分析这三种常用的特征工程技术,并在实际应用中灵活运用,提升时间序列分析的能力。谢谢大家!

小结:

  • 滑动窗口技术通过统计计算局部窗口内的数据,提取趋势和波动性特征。
  • 傅里叶变换将时域信号转换到频域,用于分析周期性模式和频率成分。
  • 小波分析是一种更高级的信号处理技术,能够捕捉非平稳信号的时频特征,常用于去噪和特征提取。

更多IT精英技术系列讲座,到智猿学院

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注