将一维序列数据转化为二维图像数据的方法汇总 详细 全面

  • 一、背景
  • 二、方法介绍
    • 格拉米角场 GAFs
      • 原理
      • 实现步骤
      • 调用示例
    • 马尔可夫变迁场 MTF
      • 原理
      • 实现步骤
      • 调用示例
    • 递归图 Recurrence Plot
      • 原理
      • 调用示例
    • 短时傅里叶变换 STFT
    • 原理
    • 实现步骤
    • 调用示例
  • References
  • 总结

一、背景

虽然深度学习方法(1D CNN, RNN, LSTM 等)可以直接处理一维数据,但是当前的深度学习方法主要还是处理二维结构数据的,特别是在计算机视觉CV以及自然语言处理NLP领域,各种各样的方法层出不穷。因此,如果能够将一维序列数据转化为二维(图像)数据, 则可以直接结合CV以及NLP领域的方法,是不是很有趣!

二、方法介绍

格拉米角场 GAFs

原理

缩放后的1D序列数据从直角坐标系统转换到极坐标系统,然后通过考虑不同点之间的角度和/差以识别不同时间点的时间相关性。取决于是做角度和还是角度差,有两种实现方法:GASF(对应做角度和), GADF(对应做角度差)。

实现步骤

Step 1:缩放,将数据范围缩放到[-1,1]或者[0, 1], 公式如下:

Step 2: 将缩放后的序列数据转换到极坐标系统,即将数值看作夹角余弦值,时间戳看作半径,公式如下:

: 若数据缩放范围为[-1, 1],则转换后的角度范围为[0, π pi π];若缩放范围为[0, 1],则转换后的角度范围为[0, π pi π/2]。
Step 3:

可以看到,最终GASF和GADF的计算转化到直角坐标系下变成了“类似”内积的操作。

效率问题:对于长度为n的序列数据,转换后的GAFs尺寸为[n, n]的矩阵,可以采用PAA(分段聚合近似)先将序列长度减小,然后在转换。 所谓的PAA就是:将序列分段,然后通过平均将每个段内的子序列压缩为一个数值, 简单吧!

调用示例

Python工具包pytl中已经提供了API,另外,笔者自行实现代码, 想要查看实现细节以及获取更多测试用例,可从我的 链接获取。

'''
EnvironmentPython 3.6,  pyts: 0.11.0, Pandas: 1.0.3
'''
from mpl_toolkits.axes_grid1 import make_axes_locatable
from pyts.datasets import load_gunpoint
from pyts.image import GramianAngularField
# call API
X, _, _, _ = load_gunpoint(return_X_y=True)
gasf = GramianAngularField(method='summation')
X_gasf = gasf.transform(X)
gadf = GramianAngularField(method='difference')
X_gadf = gadf.transform(X)plt.figure()
plt.suptitle('gunpoint_index_' + str(0))
ax1 = plt.subplot(121)
ax1.plot(np.arange(len(rescale(X[k][:]))), rescale(X[k][:]))
plt.title('rescaled time series')
ax2 = plt.subplot(122, polar=True)
r = np.array(range(1, len(X[k]) + 1)) / 150
theta = np.arccos(np.array(rescale(X[k][:]))) * 2 * np.pi  # radian -> Angleax2.plot(theta, r, color='r', linewidth=3)
plt.title('polar system')
plt.show()plt.figure()
plt.suptitle('gunpoint_index_' + str(0))
ax1 = plt.subplot(121)
plt.imshow(X_gasf[k])
plt.title('GASF')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=0.2) # Create an axes at the given *position*=right with the same height (or width) of the main axes
plt.colorbar(cax=cax)ax2 = plt.subplot(122)
plt.imshow(X_gadf[k])
plt.title('GASF')
divider = make_axes_locatable(ax2)
cax = divider.append_axes("right", size="5%",pad=0.2)  # Create an axes at the given *position*=right with the same height (or width) of the main axes
plt.colorbar(cax=cax)
plt.show()

结果如下图所示
缩放后的序列数据以及在极坐标系统的表示:

转换后的GASF和GADF:


马尔可夫变迁场 MTF

原理

基于1阶马尔可夫链,由于马尔科夫转移矩阵对序列的时间依赖并不敏感,因此作者考虑了时间位置关系提出了所谓的MTF。

实现步骤

Step 1: 首先将序列数据(长度为n)按照其取值范围划分为Q个bins (类似于分位数), 每个数据点 i 属于一个唯一的qi ( ∈ in ∈ {1,2, …, Q}).
Step 2: 构建马尔科夫转移矩阵W,矩阵尺寸为:[Q, Q], 其中W[i,j]由qi中的数据被qj中的数据紧邻的频率决定,其计算公式如下:
w i , j = ∑ x ∈ q i , y ∈ q j , x + 1 = y 1 / ∑ j = 1 Q w i , j w_{i,j}=sum_{ orall x in q_{i}, y in q_{j},x+1=y}1/sum_{j=1}^{Q}w_{i,j} wi,j=∑x∈qi,y∈qj,x+1=y1/∑j=1Qwi,j
Step 3:构建马尔科夫变迁场M, 矩阵尺寸为:[n, n], M[i,j]的值为W[qi, qj]

效率问题:原因与GAFs类似,为了提高效率,设法减小M的尺寸,思路与PAA类似,将M网格化,然后每个网格中的子图用其平均值替代。

调用示例

Python工具包pytl中已经提供了API,API接口参考:https://pyts.readthedocs.io/en/latest/generated/pyts.image.MarkovTransitionField.html。另外,笔者自行实现代码, 想要查看实现细节以及获取更多测试用例,可从我的 github 链接获取。

'''
EnvironmentPython 3.6,  pyts: 0.11.0, Pandas: 1.0.3
'''
from mpl_toolkits.axes_grid1 import make_axes_locatable
from pyts.datasets import load_gunpoint
from pyts.image import MarkovTransitionField
## call API
X, _, _, _ = load_gunpoint(return_X_y=True)
mtf = MarkovTransitionField()
fullimage = mtf.transform(X)# downscale MTF of the time series (without paa) through mean operation
batch = int(len(X[0]) / s)
patch = []
for p in range(s):for q in range(s):patch.append(np.mean(fullimage[0][p * batch:(p + 1) * batch, q * batch:(q + 1) * batch]))
# reshape
patchimage = np.array(patch).reshape(s, s)plt.figure()
plt.suptitle('gunpoint_index_' + str(k))
ax1 = plt.subplot(121)
plt.imshow(fullimage[k])
plt.title('full image')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=0.2)
plt.colorbar(cax=cax)ax2 = plt.subplot(122)
plt.imshow(patchimage)
plt.title('MTF with patch average')
divider = make_axes_locatable(ax2)
cax = divider.append_axes("right", size="5%", pad=0.2)
plt.colorbar(cax=cax)
plt.show()

结果如图所示:


递归图 Recurrence Plot

递归图(recurrence plot,RP)是分析时间序列周期性、混沌性以及非平稳性的一个重要方法,用它可以揭示时间序列的内部结构,给出有关相似性、信息量和预测性的先验知识,递归图特别适合短时间序列数据,可以检验时间序列的平稳性、内在相似性。

原理

递归图是表示从原始时间序列提取的轨迹之间的距离的图像
给定时间序列数据: ( x 1 , … , x n ) (x_1, ldots, x_n) (x1,…,xn),提取到的轨迹为:
x i = ( x i , x i + τ , … , x i + ( m 1 ) τ ) , i ∈ { 1 , … , n ( m 1 ) τ } ec{x}_i = (x_i, x_{i + au}, ldots, x_{i + (m - 1) au}), quad orall i in {1, ldots, n - (m - 1) au } x i=(xi,xi+τ,…,xi+(m1)τ),i∈{1,…,n(m1)τ}
其中: m m m是轨迹的维数, τ au τ是时延。 递归图R是轨迹之间的成对距离,计算如下:
R i , j = Θ ( ε ∥ x i x j ∥ ) , i , j ∈ { 1 , … , n ( m 1 ) τ } R_{i, j} = Theta(arepsilon - | ec{x}_i - ec{x}_j |), quad orall i,j in {1, ldots, n - (m - 1) au } Ri,j=Θ(ε∥x ix j∥),i,j∈{1,…,n(m1)τ}
其中, Θ Theta Θ为Heaviside函数,而 ε arepsilon ε 是阈值。

调用示例

'''
EnvironmentPython 3.6,  pyts: 0.11.0, Pandas: 1.0.3
'''
from mpl_toolkits.axes_grid1 import make_axes_locatable
from pyts.datasets import load_gunpoint
from pyts.image import RecurrencePlotX, _, _, _ = load_gunpoint(return_X_y=True)
rp = RecurrencePlot(dimension=3, time_delay=3)
X_new = rp.transform(X)
rp2 = RecurrencePlot(dimension=3, time_delay=10)
X_new2 = rp2.transform(X)
plt.figure()
plt.suptitle('gunpoint_index_0')
ax1 = plt.subplot(121)
plt.imshow(X_new[0])
plt.title('Recurrence plot, dimension=3, time_delay=3')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=0.2)
plt.colorbar(cax=cax)ax1 = plt.subplot(122)
plt.imshow(X_new2[0])
plt.title('Recurrence plot, dimension=3, time_delay=10')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=0.2)
plt.colorbar(cax=cax)
plt.show()

结果如图:


短时傅里叶变换 STFT

STFT可看作一种量化非平稳信号的频率和相位含量随时间变化的方式。.

原理

通过添加窗函数(窗函数的长度是固定的),首先对时域信号加窗,通过滑动窗口的方式将原始时域信号分割为多个片段,然后对每一个片段进行FFT变换,从而得到信号的时频谱(保留了时域信息)。

实现步骤

假设序列的长度为 T T T, τ au τ为窗口窗口长度, s s s为滑动步长,W表示窗函数, 则STFT可以计算为:

S T F T ( τ , s ) ( X ) [ m , k ] = ∑ t = 1 T X [ t ] W ( t s m ) e x p { j 2 π k / τ ( t s m ) } STFT^{( au,s)}(X)_{[m,k]}=sum_{t=1}^{T}X_{[t]} cdot W(t-sm)cdot exp{-j2pi k / au cdot (t-sm)} STFT(τ,s)(X)[m,k]=∑t=1TX[t]W(tsm)exp{j2πk/τ(tsm)}

变换后的STFT尺寸为:[M, K], M代表时间维度,K代表频率幅值(复数形式),为方便起见,假设 s = τ s= au s=τ, 即窗口之间没有重叠,则
M = T / τ M=T/ au M=T/τ,
K = τ K =lfloor au floor K=τ/2 + 1

注:相比于DFT, STFT在某种程度上帮助我们恢复时间分辨率,然而在可达到的时间分辨率和频率之间会发生权衡,这就是所谓的不确定性原理。具体来说,窗口的宽度( τ au τ)越大,频域分辨率就越高,相应地,时域分辨率越低;窗口的宽度( τ au τ)越小,频域分辨率就越低,相应地,时域分辨率越高。

调用示例

python包 scipy提供STFT的API,具体官方文档介绍见:https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html

scipy.signal.stft(x,fs = 1.0,window =‘hann’,nperseg = 256,noverlap = None,nfft = None,detrend = False,return_oneside = True,boundary
=‘zeros’,padded = True,axis = -1 )

参数解释
x: 时域信号;
fs: 信号的采样频率;
window: 窗函数;
nperseg: 窗函数长度;
noverlap: 相邻窗口的重叠长度,默认为50%;
nfft: FFT的长度,默认为nperseg。如大于nperseg会自动进行零填充;
return_oneside : True返回复数实部,None返回复数。
示例代码:

"""
@author: masterqkk, masterqkk@outlook.com
Environment:python: 3.6Pandas: 1.0.3matplotlib: 3.2.1
"""
import pickle
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as scisig
from mpl_toolkits.axes_grid1 import make_axes_locatable
from pyts.datasets import load_gunpointif __name__ == '__main__':X, _, _, _ = load_gunpoint(return_X_y=True)fs = 10e3  # sampling frequencyN = 1e5  # 10 s 1signalamp = 2 * np.sqrt(2)time = np.arange(N) / float(fs)mod = 500 * np.cos(2 * np.pi * 0.25 * time)carrier = amp * np.sin(2 * np.pi * 3e3 * time + mod)noise_power = 0.01 * fs / 2noise = np.random.normal(loc=0.0, scale=np.sqrt(noise_power), size=time.shape)noise *= np.exp(-time / 5)x = carrier + noise  # signal with noiseper_seg_length = 1000 # window lengthf, t, Zxx = scisig.stft(x, fs, nperseg=per_seg_length, noverlap=0, nfft=per_seg_length, padded=False)print('Zxx.shaope: {}'.format(Zxx.shape))  plt.figure()plt.suptitle('gunpoint_index_0')ax1 = plt.subplot(211)ax1.plot(x)plt.title('signal with noise')ax2 = plt.subplot(212)ax2.pcolormesh(t, f, np.abs(Zxx), vmin=0, vmax=amp)plt.title('STFT Magnitude')ax2.set_ylabel('Frequency [Hz]')ax2.set_xlabel('Time [sec]')plt.show()

运行结果
得到STFT结果尺寸为:
Zxx.shaope: (501, 101), 频率成分的数量为 1000 lfloor 1000 floor 1000/2 + 1 = 501, 窗口片段的长度为1e5/1000 + 1=101 (此处应该是进行了pad)

References

1.Imaging Time-Series to Improve Classification and Imputation
2.Encoding Time Series as Images for Visual Inspection and Classification Using Tiled Convolutional Neural Networks
3.J.-P Eckmann, S. Oliffson Kamphorst and D Ruelle, “Recurrence Plots of Dynamical Systems”. Europhysics Letters (1987)
4.Stoica, Petre, and Randolph Moses,Spectral Analysis of Signals, Prentice Hall, 2005
5.https://laszukdawid.com/tag/recurrence-plot/

总结

最后附上时间序列数据集下载链接:http://www.cs.ucr.edu/~eamonn/time_series_data/, 几乎包含了所有当前该领域的数据集。
希望能帮助到大家, 未完待续。欢迎交流:masterqkk@outlook.com

将一维数据(序列)转化为二维数据(图像)的方法汇总GAFS, MTF, Recurrence plot,STFT相关推荐

  1. 矢量切片_数据粒度均衡的二维矢量瓦片构建方法

    作 者 信 息 应 申1,2,王子豪1,杜志强3,丁火平4, 李翔翔4 (1. 武汉大学 资源与环境科学学院,湖北 武汉 430079:2. 自然资源部城市国土资源监测与仿真重点实验室,广东 深圳 5 ...

  2. Python一维二维数据的格式化和处理

    本章导言 什么是数据格式化 前言: -学完本章,看待数据会有一种规范/格式化的视角 -方法论:从Python角度理解文件和数据表示 -实践能力:学会编写带有文件输入输出的程序 1. 数据组织的维度 维 ...

  3. Python入门——一维数据、二维数据、多维数据、高维数据

    文章目录 一. 一维数据 1. 一维数据的表示 2. 一维数据的存储 2.1 空格分隔 2.2 逗号分隔 2.3 其他方式 3. 一维数据的处理 3.1 一维数据的读入处理.split() 3.2 一 ...

  4. python 一,二维数据的个数化和处理

    目录 数据的几种类型 数据的操作周期 一维数据 一维数据的表示 一维数据的存储 一维数据的处理 一维数据的读入处理 一维数据的写入处理 二维数据 二维数据的表示 CSV格式 二维数据的存储 二维数据的 ...

  5. 16 二维数据的格式化和处理

    一.二维数据的表示 1.使用列表类型 2.一二维数据的python表示 数据维度是数据组织的形式 二.CSV格式与二维数据存储 1.CSV数据存储格式   三.二维数据的处理 1.二维数据的读入处理 ...

  6. 如何将多个一维列表转化为二维列表_数据分析2_如何处理一维、二维数据

    吞一块大饼,还不如切成小块吃得香 常见的数据集,要么是数列,要么是表格: 因此,数据分析最首要的是,处理一维.二维数据. 主要知识点可参考如图. 如需要,可点击以下百度网盘链接下载数据分析基础知识图P ...

  7. oracle 一维数转二维数组,js将一维数组转化为二维数组

    遇到的问题: 后端返回的是一组一维数组,但是需要展示的格式是二维数组,常见的场景举例:后台返回10个长度的数组,需要分成3个一组展示在banner上. 例:[1,2,3,4,5,6,7,8,9,10] ...

  8. c语言一维数组转化为二维矩阵,js将一维数组转化为二维数组

    遇到的问题: 后端返回的是一组一维数组,但是需要展示的格式是二维数组,常见的场景举例:后台返回10个长度的数组,需要分成3个一组展示在banner上. 例:[1,2,3,4,5,6,7,8,9,10] ...

  9. 一维二维_Excel二维数据转一维,2种方法轻松搞定

    今天是2020年1月1日,祝各位小伙伴们新年快乐,开心每一天~ 如下所示,左边是二维交叉数据表,我们希望快速转换成右边的一维数据表 如果复制粘贴,效率太低了,今天分享两种方法,实现快速转换 1.pow ...

最新文章

  1. html页面加空的行,html-插入高度较小的空白表行
  2. 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)
  3. servlet中的几个路径有关的方法
  4. seo高手已经掌握的秒收教程
  5. VCS-bilibili教程篇1-Simulation Basics
  6. Ceph BlueFS
  7. C++用stack实现深度优先搜索DFS(附完整源码)
  8. zabbix-agent客户端安装
  9. php和apache协同,apache和php之间协同工作的配置经验分享
  10. 使用gdaldem生成山体阴影——thematicmapping.org译文(二)
  11. SQL Server数据库查询sql去掉小数后点后末尾的0
  12. python学习:猜数字游戏
  13. C语言 陶陶摘苹果 数组,陶陶摘苹果-题解(C++代码)
  14. cachecloud java_cachecloud安装部署
  15. ffmpeg中h264_mp4toannexb使用说明及注意事项
  16. https://download.csdn.net/download/dsj27/7105355
  17. VTK/OpenGL中球坐标转直角坐标
  18. 骨传导耳机哪个牌子好?哪些款式最值得入手?
  19. C++--数值的整数次方
  20. 新安装的office(已激活),出现新建没有Word

热门文章

  1. 你们是不是很缺大数据?
  2. Argo Workflow简单样例——dag-阿里云开发者社区
  3. mysql获取近7天每天数据_sql 获取最近7天的每日数据
  4. 打印机打印时长边翻转和短边翻转有什么区别?
  5. 【代码审计】任意文件读取漏洞实例
  6. 如何写好一份在线TOB的产品说明文档,这六点很重要
  7. java合并word文件
  8. GNU Guile 2.0.9 发布,Scheme 实现
  9. MIPI I3C简介
  10. Android 友盟的计数功能,友盟统计_U-App应用统计之自定义事件统计