时间序列基础:从神经信号说起
各位同学,今天我们来聊聊时间序列。说实话,这个主题我讲了不下二十遍,但每次都有新感悟。尤其是做神经信号处理这些年,我越发觉得——时间序列不是数学概念,它是我们理解大脑的一把钥匙。
你想想看,脑电图、局部场电位、锋电位序列,哪个不是时间序列?说白了,神经科学家整天跟时间序列打交道。但很多人一上来就套模型,结果惨不忍睹。我见过太多这样的案例了。
什么是时间序列?
时间序列,就是按时间顺序排列的数据点。简单吧?但这里有个坑——顺序本身携带信息。
举个例子。我做过一个睡眠分期项目,采集了一整晚的EEG信号。如果我把这些数据点随机打乱,你还能看出深睡眠、浅睡眠、REM期的区别吗?不能。因为时间顺序丢失了,节律信息全没了。
所以,时间序列的核心特征是:
- 时间依赖性:当前值跟过去值有关
- 有序性:顺序不能乱
- 等间隔采样(通常情况):采样间隔固定
重要提醒:神经信号的时间序列,往往不是严格等间隔的。比如锋电位序列,它是事件触发的。处理这类数据时,千万别用常规的时间序列方法硬套。
采样定理:别让你的信号失真
采样定理,也叫奈奎斯特-香农定理。内容很简单:采样频率必须大于信号最高频率的两倍。
为什么?我用自己的血泪史来解释。有一次做高频振荡(80-200Hz)的检测,我偷懒用了250Hz采样。结果呢?80Hz以上的成分全混叠了,检测结果一塌糊涂。后来老板问我:「你采样率够吗?」我脸都红了。
所以,记住这个公式:
fs > 2 * f_max
其中 fs 是采样频率,f_max 是信号最高频率成分。
对于神经信号,我建议:
| 信号类型 | 典型频率范围 | 建议采样率 |
|---|---|---|
| EEG(头皮脑电) | 0.5-100 Hz | ≥ 250 Hz |
| ECoG(皮层脑电) | 0.5-500 Hz | ≥ 1000 Hz |
| LFP(局部场电位) | 0.5-300 Hz | ≥ 1000 Hz |
| Spike(锋电位) | 300-6000 Hz | ≥ 20000 Hz |
避坑指南:我曾经见过有人用100Hz采样率做高频振荡分析,结果把50Hz工频干扰的谐波当成了生理信号。这就是混叠的典型后果。记住:宁可采样率高一点,也别漏掉信息。
平稳性与非平稳性
平稳性,说白了就是统计特性不随时间变化。均值不变、方差不变、自相关结构不变。
但神经信号,几乎都是非平稳的。为什么?因为大脑状态在变啊!
我举个例子。你让被试者闭眼休息,EEG的alpha波(8-12Hz)会增强。然后你让他做数学题,alpha波立马减弱。这能平稳吗?不能。
所以,处理神经信号时,我们通常做分段平稳假设:
- 把长序列切成短段(比如2秒一段)
- 假设每段内是平稳的
- 段与段之间可以不同
我个人习惯用2秒的窗口,步长0.5秒。这样既有足够的数据点做分析,又能捕捉到状态变化。
小技巧:判断平稳性,可以用滚动统计量。如果滚动均值和滚动方差变化不大,那基本可以认为是平稳的。当然,更严谨的做法是用单位根检验(比如ADF检验)。
自相关与互相关
自相关,就是信号跟自己的过去做比较。互相关,是两个信号之间的比较。
这两个概念,在神经信号处理中太重要了。
自相关有什么用?
- 检测周期性:比如alpha节律,自相关函数会在8-12Hz对应的延迟处出现峰值
- 判断随机性:白噪声的自相关在延迟≠0时接近0
- 模型识别:AR模型的阶数可以通过自相关函数来估计
互相关有什么用?
- 功能连接:两个脑区之间的信号有没有相关性?
- 时延估计:一个脑区的活动是否滞后于另一个?
- 因果推断:虽然不能直接说因果,但互相关可以提供线索
我记得有一次做视觉诱发电位分析,用互相关找到了刺激 onset 和 V1 区响应之间的延迟,大约80ms。这个结果跟已知的神经传导速度吻合,说明方法是对的。
# Python代码示例:计算自相关和互相关
import numpy as np
def autocorrelation(x, max_lag=100):
"""计算自相关函数"""
n = len(x)
mean = np.mean(x)
x_centered = x - mean
result = np.zeros(max_lag + 1)
for lag in range(max_lag + 1):
result[lag] = np.sum(x_centered[:n-lag] * x_centered[lag:]) / n
return result / result[0] # 归一化
def cross_correlation(x, y, max_lag=100):
"""计算互相关函数"""
n = len(x)
x_centered = x - np.mean(x)
y_centered = y - np.mean(y)
result = np.zeros(2 * max_lag + 1)
for lag in range(-max_lag, max_lag + 1):
if lag < 0:
result[lag + max_lag] = np.sum(x_centered[:n+lag] * y_centered[-lag:]) / n
else:
result[lag + max_lag] = np.sum(x_centered[:n-lag] * y_centered[lag:]) / n
return result
注意:互相关不等于因果关系。两个脑区同步活动,可能是因为它们都受同一个上游脑区驱动。我见过太多人把互相关直接解释为「A驱动B」,这是危险的。
时间序列预测问题定义
预测,就是根据过去预测未来。数学上可以写成:
给定历史观测值 x₁, x₂, ..., xₜ,预测 xₜ₊₁, xₜ₊₂, ...
但神经信号的预测,跟股票预测、天气预测不太一样。为什么?
- 信噪比低:神经信号里噪声很大,预测难度高
- 非平稳性强:模型需要不断自适应
- 多尺度特性:毫秒级的锋电位,秒级的节律,分钟级的睡眠周期
我建议把预测问题分成两类:
- 短期预测:预测未来几个时间点,常用于实时解码
- 长期预测:预测未来较长时间段,常用于状态估计
短期预测,我常用自回归模型(AR)或LSTM。长期预测,则要考虑状态空间模型。
核心要点:预测不是目的,理解才是。我见过太多人追求预测精度,却忽略了模型的可解释性。在神经科学领域,我们更关心「为什么能预测」,而不是「预测得多准」。
本章知识体系
下面这张图,是我自己总结的时间序列基础框架。每次做项目前,我都会对照着检查一遍,看看有没有遗漏。
这张图把本章的核心内容串起来了。从时间序列的定义出发,到采样定理保证数据质量,再到平稳性分析判断数据特性,然后用相关分析探索信号间的关系,最后用预测模型实现应用。每一步都有坑,每一步也都有技巧。
好了,时间序列基础就讲到这里。记住:理论是死的,数据是活的。多动手,多踩坑,你才能真正理解这些概念。
公众号:蓝海资料掘金营,微信deep3321