使用Python 实现奇异谱分析SSA(Singular Spectrum Analysis)算法

本文深入解析了SSA算法在时序分析中的应用,包括数据预处理、SVD分解和重构过程,展示了如何使用Python处理带有噪声的时间序列并提取周期性和趋势成分。
摘要由CSDN通过智能技术生成

简介

SSA是一种近几年新兴的时序分析算法,通过对时间序列进行升维后做SVD,进而分组重构来实现对时间序列的成分分析,目前用于预测、插值补全以及去噪
具体步骤包括四个部分:
1.构建轨迹矩阵(Embedding)
2.轨迹矩阵SVD分解
3.分组
4.对角平均

1.准备工作

这里我们生成一组间隔带有噪声的序列,包含了周期项、趋势项和随机噪声

import numpy as np
import matplotlib.pyplot as plt
number = 30
days = 180
tend_sequence = np.linspace(2,-2,num=days)
time = np.linspace(0,2*np.pi*days/number,num=days)
sin_sequence = np.sin(time)
signal = sin_sequence+tend_sequence
noise = np.random.randn(days)
sequence = noise+sin_sequence+tend_sequence
plt.plot(tend_sequence,color='yellow',label='Tendency')
plt.plot(sin_sequence,color='blue',label='Periodicity')
plt.plot(noise,color='red',label='noise')
plt.legend()
plt.show()
plt.plot(sequence,color='red',label='with noise')
plt.plot(signal,color='blue',label='original')
plt.legend()
plt.show()

模拟数据的组成成分

模拟原信号和带有噪声的信号

2.SSA具体实现

在实际操作中,我们将从以下步骤进行计算:
1. 对于长度为 N N N 的时间序列,以 L L L 为滑动窗口,依次进行采样,获得大小为 L × K L×K L×K 的轨迹矩阵 X X X,其中 K = N − L + 1 K=N-L+1 K=NL+1
2. X X XSVD分解,文献中经常给出完整的计算方法(先计算 X X T XX^T XXT等),但是经过检验直接使用numpy.linalg.svd()是可行的。
分解后获得 U 、 Σ 、 V T U、\Sigma 、V^T UΣVT
3. 构建 X X X的基本矩阵(elementary matrices),这里 X i = σ i U i V i T X_i=\sigma_i U_i V_i^T Xi=σiUiViT,这里认为轨迹矩阵 X X X是由 L L L个这样的基本矩阵加和而成的。
4. 将基本矩阵 X i X_i Xi通过对角平均的操作,还原到长度为 N N N的时间序列,即为原序列的一个构成成分

对角平均示意图这一部分代码参考了

[机器学习] 奇异谱分析(SSA)原理及Python实现

windowlen = 45
serieslen = days
#1.嵌入
K = serieslen-windowlen+1
X = np.zeros((windowlen,K))
for i in range(windowlen):
    X[i,:] = sequence[i:i+K]
#2.SVD分解
U,sigma,VT = np.linalg.svd(X,full_matrices=False)
ZT = np.zeros((VT.shape))
for n in range(len(sigma)):
    ZT[n,:] = sigma[n]*VT[n,:]

#3.对每个Ui*ZTi所得到的Xi进行对角平均获得重构子序列,一般我们假设L<K
RC = np.zeros((windowlen,serieslen))
L = windowlen
for num in range(U.shape[1]):
    Xi = np.outer(U[:,num],ZT[num,:])
    for k in range(serieslen):
        sum=0
        if(k<=L-1):
            for p in range(k+1):
                sum+=Xi[p,k-p]
            RC[num,k] = sum/(k+1)
        elif(k<=K-1):
            for p in range(L):
                sum+=Xi[p,k-p]
            RC[num,k] = sum/L
        elif(k<=serieslen-1):
            for p in range(k-K+1,serieslen-K+1):
                sum+=Xi[p,k-p]
            RC[num,k] = sum/(serieslen-k)

3.结果分析

现在我们可以看到,所获得的RC是由 L L L个成分序列构成的矩阵,每一行对应原序列的一个成分

showN = 8
for m in range(showN):
    plt.subplot(showN,1,m+1)
    plt.plot(RC[m,:])
    plt.ylabel(('RC {}'.format(m)))
plt.show()

在这里插入图片描述

查看周期项分离效果

plt.plot(RC[1,:]+RC[2,:],color='blue',label = 'predicted')
plt.plot(sin_sequence,color='red',label = 'periodicity')
plt.legend()
plt.show()

在这里插入图片描述

查看趋势项分离效果

plt.plot(RC[0,:],color='blue',label = 'predicted')
plt.plot(tend_sequence,color='red',label = 'trend')
plt.legend()
plt.show()

在这里插入图片描述

查看整体去噪效果

选用RC0\1\2\3四项进行重组

plt.plot(RC[0,:]+RC[1,:]+RC[2,:]+RC[3,:],color='blue',label = 'predicted')
plt.plot(signal,color='red',label = 'original')
plt.legend()
plt.show()

在这里插入图片描述

目前所掌握的知识还不足以将SSA发展为一种通用的方法,原因是窗口长度 L L L 的长度确定具有较强的主观性,重现原序列时对各个成分的取舍也没有具体的标准,还需要进一步的学习。

博主不是信号处理及数学方面的专业人士,科研项目中用到了这一块,简单记录下学习过程,如果有不正确的地方麻烦指出,欢迎交流~

参考文献:
[1] GOLYANDINA N, ZHIGLJAVSKY A. Singular Spectrum Analysis for Time Series[M/OL]. 2013. DOI:10.1007/978-3-642-34913-3.

  • 41
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值