基于Python 3.9版本演示
一、写在前面
之前我们介绍过时间序列的季节性分解。
最近又学到了好几种骚操作分解,且可以用这些分解优化时间序列预测性能。
首先,我们来学一学经验模态分解(Empirical Mode Decomposition,EMD)。
二、经验模态(EMD)分解
时间序列的经验模态分解(Empirical Mode Decomposition,EMD)是一种数据驱动的信号处理技术,用于分解非线性、非平稳信号。EMD技术由诺贝尔奖获得者黄锷(Norden E. Huang)和他的同事们在1998年提出,它特别适用于分析自然界中复杂的时间序列数据。
EMD的基本思想是将一个复杂的信号分解成若干个具有不同时间尺度的内禀模态函数(Intrinsic Mode Functions,IMFs)和一个残余信号。这些IMFs代表信号中的不同振荡模式,而残余信号则反映了信号的整体趋势。
(1)EMD的优点
1)自适应性:EMD是一种完全自适应的方法,不需要任何预设参数,能够处理非线性、非平稳信号。。
2)直观性:分解得到的IMFs通常具有物理意义,便于理解和解释信号中的不同成分。
3)广泛应用:EMD已在气象学、地震学、生物医学信号处理、机械故障诊断等领域得到了广泛应用。
(2)EMD的缺点
1)边界效应:由于边界处数据不足,包络线构建过程中可能出现误差,影响分解结果。
2)模式混叠:在某些情况下,分解得到的IMFs可能会包含多个不同频率的成分,导致模态混叠问题。
3)计算复杂度:EMD的计算过程较为复杂,尤其是对长时间序列数据,计算时间较长。
三、EMD代码Pyhton实现
下面,我使用的是之前分享过的肺结核的数据做演示:
Python代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import CubicSpline
# 读取数据
file_path = 'pone.0277314.s006.xlsx'
data = pd.read_excel(file_path)
# 提取时间和PTB病例数
time_series = data['Time']
ptb_cases = data['PTB cases']
# 将时间转换为数值形式
time_numeric = np.arange(len(time_series))
def get_envelope_mean(signal):
"""计算信号的上包络线和下包络线的均值"""
maxima = np.where(np.r_[True, signal[1:] > signal[:-1]] & np.r_[signal[:-1] > signal[1:], True])[0]
minima = np.where(np.r_[True, signal[1:] < signal[:-1]] & np.r_[signal[:-1] < signal[1:], True])[0]
if len(maxima) < 2 or len(minima) < 2:
return np.zeros_like(signal)
upper_env = CubicSpline(maxima, signal[maxima])(time_numeric)
lower_env = CubicSpline(minima, signal[minima])(time_numeric)
return (upper_env + lower_env) / 2
def sift(signal, max_iter=1000, tol=1e-6):
"""对信号进行sifting操作,提取IMF"""
h = signal
for _ in range(max_iter):
m = get_envelope_mean(h)
h1 = h - m
if np.mean(np.abs(h - h1)) < tol:
break
h = h1
return h
def emd(signal, max_imfs=10):
"""进行EMD分解"""
residual = signal
imfs = []
for _ in range(max_imfs):
imf = sift(residual)
imfs.append(imf)
residual = residual - imf
if np.all(np.abs(residual) < 1e-6):
break
return np.array(imfs), residual
# 执行EMD分解
imfs, residual = emd(ptb_cases.values)
# 绘制分解结果
num_imfs = imfs.shape[0]
plt.figure(figsize=(12, 9))
for i in range(num_imfs):
plt.subplot(num_imfs + 1, 1, i + 1)
plt.plot(time_series, imfs[i], label=f'IMF {i + 1}')
plt.legend()
# 绘制剩余信号
plt.subplot(num_imfs + 1, 1, num_imfs + 1)
plt.plot(time_series, residual, label='Residual')
plt.legend()
plt.tight_layout()
plt.show()
输出:
放原图方便对比:
GPT的解读:
输出的图像展示了时间序列数据(PTB病例数)的经验模态分解(EMD)结果,包括内禀模态函数(IMFs)和剩余信号(Residual)。以下是对每个部分的解释:
(1)IMF 1到IMF 7:
1)这些图分别表示分解得到的不同内禀模态函数(IMFs),每个IMF代表了原始信号中的不同频率成分。
2)IMF 1 通常包含最高频率的振荡成分,反映了数据中的快速变化或噪声。
3)IMF 2 至 IMF 7 依次表示频率逐渐降低的振荡成分。IMF 7 通常包含最低频率的成分,反映了数据中的长期趋势或变化。
(2)残余信号(Residual):
1)残余信号表示在所有IMFs提取后剩下的部分,通常反映了数据的长期趋势或整体趋势。
2)在这个图中,Residual接近于零,表明大部分信号成分已经被前面的IMFs提取。
通过EMD分解,我们可以将复杂的时间序列数据分解成不同频率成分的IMFs,并识别出数据中的各种变化模式和趋势。具体的解释如下:
1)高频成分(IMF 1-2):这些成分包含了数据中的快速波动,可能对应于季节性变化、短期扰动或噪声。
2)中频成分(IMF 3-5):这些成分反映了中期变化,如年度周期、经济周期等。
3)低频成分(IMF 6-7):这些成分代表了长期趋势,可能反映了数据的整体上升或下降趋势。
4)残余信号(Residual):如果残余信号接近于零,表示大部分信号已经通过IMFs提取出来。若残余信号非零且变化趋势明显,表示还有未被提取的长期趋势。
通过这种分解,可以更清楚地了解时间序列数据的各个成分,便于进一步的分析和建模。
五、关于结果的疑问
(1)“低频成分(IMF 6-7):这些成分代表了长期趋势。”为什么6和7的趋势都不一样?如何解释?
答曰:
1、IMF 6和IMF 7的不同趋势:
① IMF 6:这条线显示了较低频率的振荡和趋势。它可能代表的是一个中长期的变化,比如几年的周期性波动。这些波动可能是由某些周期性事件或变化引起的,例如政策变动、社会经济变化等。
② IMF 7:这条线显示了最低频率的振荡,通常被视为更长期的趋势。这些趋势可以反映数据的总体上升或下降趋势,可能是由于长期的结构性变化、整体发展趋势或其他长周期因素。
2、为何趋势不同:
① 不同IMF的趋势和频率内容不同,因为每个IMF捕捉信号中的不同振荡成分。虽然IMF 6和IMF 7都是低频成分,但它们对应不同的时间尺度。IMF 6可能捕捉到中期的趋势和波动,而IMF 7更关注长期的变化趋势。
② 这些不同的趋势说明数据中存在多个时间尺度的变化,反映了信号的多层次复杂性。
3、具体解释:
① IMF 6:可能反映了中期的波动,比如政策变动、社会经济变化等,这些变化可能在几年的时间内表现出来。
② IMF 7:可能反映了数据的长期趋势,比如技术进步、人口增长等,导致整体数据的上升或下降。
(2)“中频成分(IMF 3-5):这些成分反映了中期变化”,为什么3、4和5的趋势都不一样?如何解释?
答曰:
1、IMF 3、IMF 4和IMF 5的不同趋势:
① IMF 3:这条线显示了较高频率的中期振荡,可能代表的是较短时间尺度上的变化,比如几个月到一年的周期性波动。
② IMF 4:这条线显示了中等频率的振荡,可能代表的是中等时间尺度上的变化,比如一到三年的周期性波动。
③ IMF 5:这条线显示了较低频率的中期振荡,可能代表的是更长时间尺度上的变化,比如三到五年的周期性波动。
2、为何趋势不同:
① 频率和时间尺度的不同:虽然这些IMF都属于中频成分,但它们对应的频率不同,因此捕捉到的变化也不同。每个IMF反映了原始信号中不同频率范围的振荡成分。
② 多层次复杂性:信号中存在多个时间尺度的变化,反映了信号的多层次复杂性。IMF 3、IMF 4和IMF 5分别捕捉了不同层次的中期变化。
3、具体解释:
① IMF 3:可能反映了较短时间内的波动,比如季节性变化、短期市场波动等。
② IMF 4:可能反映了中等时间内的变化,比如年度周期、经济周期等。
③ IMF 5:可能反映了更长时间内的变化,比如政策变化、社会经济趋势等。
六、最后
那么,做这些分解有什么作用呢?有大佬基于这些分解出来的序列分别作预测,然后再次合并,达到提升预测性能的作用。
下一期,我们来测试一下这种策略的可行性,是否只是一个噱头。