格拉姆角场(Gramian Angular Field, GAF)详解
格拉姆角场(Gramian Angular Field, GAF)是一种于 2015 年被提出的时间序列可视化与特征编码技术。其核心思想是将一维时间序列转换为二维图像,并在此过程中保留原始序列的时间依赖关系与数值特征。目前,GAF 已在故障诊断、生物电信号分析、射频信号识别等多个领域得到广泛应用。
GAF 的实质是借助极坐标变换与格拉姆矩阵的结构,将一维序列中的'时间–数值'映射为图像中的像素关联信息。生成的图像矩阵的行列索引直接对应时间顺序,使其能够兼容主流图像识别模型(如 CNN),从而挖掘出时间序列中的深层特征。
一、GAF 的核心设计逻辑
传统的一维时间序列包含两类基本信息:数值大小(如振幅)和时间顺序(如信号随时间的变化趋势)。折线图等常规方法虽能展示趋势,却难以显式表达不同时刻之间的数值关联。GAF 通过以下三步逻辑实现信息的结构化编码:
- 数值归一化:将原始序列缩放至 [-1, 1] 区间,消除量纲与异常值影响,为极坐标变换提供基础;
- 极坐标转换:将时间索引映射为半径,数值大小映射为角度,建立时间与数值在极坐标系统中的对应关系;
- 格拉姆矩阵构建:基于极坐标角度,通过三角运算(如余弦和/差)构造 Gram 矩阵,将数值之间的时序关系转化为图像像素值。
二、GAF 的实现步骤(标准流程)
以任意 1 维时间序列 $X = [x_1, x_2, ..., x_N]$(N 为序列长度)为例。
步骤 1:数据归一化(Normalization)
将原始序列归一化至区间 [-1, 1]:
$$\tilde{x}_i = \frac{2(x_i - min(X))}{max(X) - min(X)} - 1$$
其中:
- $min(X)$、$max(X)$ 分别为原始序列的最小值和最大值;
- $\tilde{x}_i \in [-1, 1]$,归一化后不仅消除了量纲影响,还确保后续角度计算时 $arccos(\tilde{x}_i)$ 有实数解。
步骤 2:极坐标编码(Polar Coordinate Encoding)
将归一化后的序列 $\tilde{X} = [\tilde{x}_1, \tilde{x}_2, ..., \tilde{x}_N]$ 映射到极坐标系:
- 半径(表示时间索引): $$r_i = \frac{i}{N}, \quad i=1,2,3...,N$$ 时间越晚,半径越大,靠近单位圆边缘。
- 角度(表示数值大小): $$\theta_i = arccos(\tilde{x}_i), \quad \theta_i \in [0, \pi]$$ 每个角度对应归一化后的数值大小,负值对应大角度,正值对应小角度。
步骤 3:格拉姆矩阵构建(Gramian Matrix Construction)
有了极坐标下的 $(r_i, \theta_i)$,我们可以通过三角函数将时序关系编码进矩阵中。常用的有两种方式:
- 格拉姆角和场(GASF):利用余弦的和角公式,计算 $cos(\theta_i + \theta_j)$。
- 格拉姆角差场(GADF):利用余弦的差角公式,计算 $sin(\theta_i - \theta_j)$。
这两种方式生成的矩阵都是对称或反对称的,且保留了时间序列的自相关性。最终得到的矩阵可以视为一张灰度图,深色区域代表强相关,浅色区域代表弱相关。
三、Python 实战示例
理论讲完,我们直接看代码实现。这里用 NumPy 和 Matplotlib 快速生成一个 GAF 图像。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing MinMaxScaler
():
scaler = MinMaxScaler(feature_range=(-, ))
ts_norm = scaler.fit_transform(ts.reshape(-, )).flatten()
theta = np.arccos(ts_norm)
n = (theta)
r = np.linspace(, , n)
method == :
gf_matrix = np.cos(np.outer(theta, np.ones(n)) + np.outer(np.ones(n), theta))
:
gf_matrix = np.sin(np.outer(theta, np.ones(n)) - np.outer(np.ones(n), theta))
gf_matrix
time = np.linspace(, *np.pi, )
signal = np.sin(time)
image = gramian_field(signal, method=)
plt.imshow(image, cmap=, aspect=)
plt.title()
plt.colorbar()
plt.show()


