1. 从信号到图信号:为什么我们需要新的“尺子”?
如果你玩过音乐软件里的均衡器,或者用Photoshop调过照片的明暗和色彩,那你其实已经接触过“信号处理”了。传统的信号处理,比如处理一段音频或者一张图片,它们的数据点(声音的采样值、图片的像素)是规规矩矩排成一列或者一个网格的。这种规整的结构,让数学家们发明了像傅里叶变换、小波变换这样的“尺子”,可以轻松地测量信号里不同频率的成分,或者在不同精细程度上观察信号的细节。
但现实世界里的很多数据,长得一点都不“规矩”。想想你的微信好友关系网:你是中心节点,你的朋友们是其他节点,你们之间的连线构成了一个复杂的网络。这个网络里,数据(比如每个人的活跃度、兴趣标签)是挂在每个“人”这个节点上的。数据点之间的连接关系,不再是简单的“前后邻居”或者“上下左右像素”,而是由社交关系决定的复杂拓扑结构。这种挂在“图”这种不规则结构上的数据,就是我们今天要聊的“图信号”。
当我想分析这个社交网络里,哪些小圈子(社区)的讨论最活跃,或者突然发现某个平时很安静的用户突然异常活跃(异常点检测),传统的那套规整的“尺子”就不好使了。因为傅里叶变换默认所有数据点都是平等、均匀连接的,它没法理解“张三是李四的好友,但和王五不熟”这种复杂的局部关系。这时候,我们就需要为“图”这种数据结构量身定制新的分析工具,也就是图信号处理。
图信号处理的核心目标没变:还是想看清数据的全貌和细节,理解其内在模式。但难点在于,我们必须把“图的连接关系”这个至关重要的信息,融入到我们的“尺子”设计里。这就引出了我们今天要深入探讨的两把核心“尺子”:图傅里叶变换和图小波变换。它们一个擅长从全局视角把握整体“基调”,一个擅长从多尺度捕捉局部“细节”,理解了它们,你就能在面对社交网络、蛋白质相互作用网络、交通网络这些复杂数据时,手里有更趁手的工具。
2. 图傅里叶变换:给复杂网络定调
2.1 核心思想:从“琴弦振动”到“网络振荡”
理解图傅里叶变换,我们可以从一个经典的物理实验联想:一根两端固定的琴弦。当你拨动它时,琴弦会以某种频率振动,产生一个基音。同时,它还会以整数倍于基频的频率振动,产生一系列泛音。傅里叶变换的伟大之处在于,它告诉我们,任何复杂的振动波形,都可以分解为这些不同频率的简单正弦波的叠加。
现在,把“琴弦”换成我们的一张“图”。图傅里叶变换想做的事情类似:它试图找到这张图本身“固有”的振动模式。这里的“振动”,指的是定义在每个节点上的信号值以一种协调的方式起伏变化。什么样的变化模式最“自然”呢?GFT认为,应该由图的连接结构来决定。连接紧密的节点,它们的信号值倾向于一起高、一起低,变化平滑;连接松散或没有连接的节点,它们的信号值可以独立变化。
那么,如何数学化地定义这种“平滑”或“振荡剧烈”的程度呢?这就引入了图信号处理中最重要的算子之一——图拉普拉斯矩阵。你可以把它想象成图上的一个“平滑度测量仪”。一个信号在图上的“平滑度”,可以通过这个矩阵计算出来:信号越平滑,这个值就越小;信号在连接紧密的节点间变化越剧烈,这个值就越大。
图拉普拉斯矩阵的特征向量,就扮演了那根“琴弦”上不同频率振动模式的角色。特征值最小的特征向量(对应频率为0),代表最平滑的振动模式——通常整个图上所有节点的信号值都相同或缓慢变化,这可以理解为图的“直流分量”。特征值越大的特征向量,代表的振动模式就越“崎岖不平”,信号值在相邻节点间快速变化,对应着图的“高频分量”。所有这些特征向量共同构成了一组正交基,就像一套标准的坐标轴。
图傅里叶变换,本质上就是把我们观测到的、定义在每个节点上的原始图信号(比如社交网络中每个用户的活跃度),投影到这套由拉普拉斯矩阵特征向量构成的“坐标轴”上。投影后得到的系数,就是图信号的“频谱”。系数绝对值大的位置,就说明原始信号中含有该频率振动模式的成分多。
2.2 动手实践:用Python感受图的“频率”
理论说得再多,不如亲手算一遍来得实在。我们用一个简单的“链状图”(就像一队手拉手的人)来演示。这个图结构简单,但其频谱已经能揭示很多特性。
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
from scipy.linalg import eigh
# 1. 创建一个简单的无向图:5个节点连成一条线
G = nx.path_graph(5) # 节点0-1-2-3-4
# 为了方便,我们使用一个更常见的拉普拉斯矩阵定义:L = D - A
# 其中D是度矩阵,A是邻接矩阵
L = nx.laplacian_matrix(G).toarray() # 返回的是组合拉普拉斯矩阵
# 2. 计算拉普拉斯矩阵的特征值和特征向量
# 注意:eigh返回的特征值按升序排列,特征向量是列向量
eigenvalues, eigenvectors = eigh(L)
print("图拉普拉斯矩阵的特征值(频率):", eigenvalues)
print("特征值0对应的特征向量(直流分量):", eigenvectors[:, 0])
# 3. 定义一个简单的图信号:两端低,中间高
signal = np.array([0.2, 0.5, 1.0, 0.5, 0.2])
# 4. 执行图傅里叶变换:将信号投影到特征向量上
# 由于特征向量是标准正交基,变换就是做内积:GFT_coeff


392

被折叠的 条评论
为什么被折叠?



