简介:这套MATLAB脑电(EEG)信号分析与情绪分类资源,面向神经科学、医学及心理学方向的研究者,也适合正在学习脑电数据处理和机器学习分类的入门者。资料覆盖原始EEG去噪、ICA独立成分分析、STFT与小波时频变换、功率谱密度及事件相关电位(ERP)特征提取,并给出了SVM、随机森林等分类器在angry、calm、sad等情绪标签上的训练与评估示例,便于直接复现和迁移。压缩包共7个文件,以6个mat格式数据文件和1个m格式脚本为主,mat文件对应不同情绪状态的数据集,m脚本实现核心分析流程,整体仅81KB,轻量易用。目前已有1386人学习下载,适合借鉴其数据组织方式与特征提取思路,快速搭建自己的脑电情绪分类实验。 先别急着开工具箱跑数据。做EEG脑电信号分类这几年,我最深的感受是:这个方向真正卡人的地方,往往不是算法有多高深,而是从原始脑电数据到最终分类准确率这条链路上,每一步都有无数个看似不起眼、却能让你整个实验结果作废的细节。今天这篇就围绕“MATLAB环境下EEG情绪分类”这个主题,把从技术路线选型、预处理、特征提取到分类器搭建的完整流程,以及我实际踩过的坑,一次性拆开讲清楚。
这篇文章适合刚接触脑电分析、准备用MATLAB做毕业设计或科研课题的同学,也适合已经在跑数据、但分类结果一直不理想、想排查问题出在哪一步的从业者。我不会堆砌教科书公式,而是按实际干活时的顺序,把每个环节为什么这么做、怎么做、常见错误是什么都交代明白。
1. 技术路线与整体方案设计
1.1 为什么选MATLAB作为EEG分析主力工具
EEG分析不是只有MATLAB能做,Python的MNE库也很成熟,但我个人在情绪分类这个课题上依然首选MATLAB。原因很直接:EEGLAB生态太成熟了,从读入原始数据、滤波、剔除伪迹到提取ERSP,一套图形界面加脚本全搞定;另外MATLAB的Statistics and Machine Learning Toolbox和Deep Learning Toolbox对分类器原型验证极其友好,写个SVM或随机森林几行代码就完事,不用像Python那样到处找库、配环境。
如果你同时熟悉Python,建议的分工是:MATLAB负责预处理和特征提取,Python负责深度模型实验。但如果是做传统机器学习分类,比如SVM、KNN、随机森林这类,那就全程留在MATLAB里,省去数据传输的麻烦。实测下来,EEGLAB导出的数据用MATLAB原生格式存储,后续处理效率比其他中间格式高不少。
1.2 情绪分类任务的完整链路设计
一个标准的EEG情绪分类项目,链路是这样的:
数据采集或公开数据集读取 → 预处理(滤波、重参考、去伪迹、分段)→ 特征提取(时域、频域、时频域、非线性特征)→ 特征选择或降维 → 分类器训练与验证 → 结果评估
每一步都有独立的技术选型。预处理阶段要考虑滤波器类型和截止频率;特征提取阶段要确定是分频段提取功率谱,还是用小波变换或HHT;分类器阶段要比较SVM、KNN、随机森林甚至LSTM的效果。这些选型不是拍脑袋决定的,每一步都依赖上一步的数据形态和最终目标。
以情绪分类为例,通常采用效价-唤醒度二维模型,把情绪分成高/低效价、高/低唤醒度,或者四分类(高兴、悲伤、平静、恐惧)。不同分类任务对特征敏感度不一样,比如愉悦度高的情绪往往在额叶区alpha波不对称性上表现明显,唤醒度高的情绪与beta频段能量相关。这些神经科学先验知识,直接决定了你该提取哪些频段的特征,而不是一股脑把所有特征都算一遍丢给分类器。
1.3 数据集选择与实验场景设定
没有自己的采集设备时,公开数据集是首选。DEAP数据集是情绪分类领域最常用的Benchmark,包含32名受试者、40通道脑电(32个EEG通道加8个外围信号)、40段1分钟音乐视频诱发数据,每段有基于自我评价的效价、唤醒度、优势度、喜欢程度评分。另一个常用的是SEED数据集,由上海交通大学发布,62通道,使用电影片段诱发,标签是正性、中性、负性三类。
用DEAP做实验时,有几个细节要注意:EEG采样率是128Hz,原始数据中已经做了简单的预处理,但使用时仍需要自己处理基线校正和分段;情绪标签通常把评分大于5记为高类,小于等于5记为低类,这个阈值决定了二分类的难度。SEED的数据更规整,但通道数多、样本量相对少,对特征降维和分类器的泛化能力要求更高。
我自己的实验习惯是:先用DEAP跑通全流程,确定特征组合和分类器参数,再用SEED做交叉验证,确保方案不是针对某一个数据集过拟合出来的。
2. 预处理与特征提取的实操要点
2.1 信号预处理到底要做到什么程度
很多新手一上来就把原始信号导入EEGLAB,随便跑个带通滤波就去做特征提取,结果分类准确率一直上不去。问题往往出在预处理不够细致。脑电信号极其微弱,幅值通常在微伏级别,加上眼电、肌电、工频干扰,信噪比很低。预处理的核心目标是把真正来自大脑皮层的神经电活动保留下来,同时尽可能剔除干扰。
我采用的预处理流程是:
- 导入原始数据,去掉外围通道,只保留EEG通道;
- 重参考为全脑平均参考;
- 带通滤波,0.5Hz到45Hz,工频50Hz用陷波器滤除;
- 去除明显坏段和坏通道(幅值超过±100微伏的时段直接剔除);
- 用ICA去除眼电和肌电伪迹;
- 按实验条件把连续数据切分成epoch。
这套流程里,最容易出问题的是ICA。ICA是个好工具,但用不好会伤及无辜。在MATLAB里用runica算法,默认参数对多数数据有效,但需要人工检查各独立分量的地形图和频谱图,把那些明显集中在额叶前侧、频谱以低频为主的眼电分量挑出来删掉。我的经验是,情绪相关研究里尽量不要对ICA结果做全自动剔除,因为不同数据集的ICA分解质量差异很大,全自动容易出现误删有效信号的情况,一个稳妥做法是只删除模型拟合度高、地形图特征明确的眼电分量。
2.2 特征提取:哪类特征对情绪更敏感
特征提取是整个流程里最影响分类上限的环节。情绪分类用到的特征大致分四类:
时域特征:均值、方差、过零率、Hjorth参数(活动性、移动性、复杂度)。这类特征计算量小,但单独用效果一般,通常作为辅助特征。
频域特征:各频段功率谱密度、功率比、频谱熵。这是情绪分类的主力特征,尤其是theta(4-8Hz)、alpha(8-13Hz)、beta(13-30Hz)三个频段。处理时用pwelch函数加汉宁窗做功率谱估计,窗口长度设为2秒,重叠50%。
时频域特征:小波包分解后各子带的能量、小波熵;Hilbert-Huang变换的瞬时频率和边际谱。这类特征对非平稳信号更友好,脑电本身就是强非平稳信号,所以时频特征在情绪分类中通常比纯频域特征效果更好。
非线性特征:样本熵、近似熵、Lempel-Ziv复杂度、去趋势波动分析标度指数。情绪状态下大脑活动复杂度会有变化,这些特征有一定的区分度,但计算量大,对参数敏感。
我实际用过的最稳定组合是:各个频段的相对功率 + 额叶alpha不对称性 + 样本熵。在DEAP数据集上,效价二分类准确率能做到85%左右,唤醒度二分类在87%上下。只用力学特征不加非线性特征时,准确率大约会掉3-5个百分点。代价是特征提取时间大幅增加,但这不是大问题,因为分类效果才是硬指标。
2.3 特征矩阵构建与维度控制
把所有算出来的特征拼到一起,矩阵大小往往很吓人。比如DEAP数据:32个受试者 × 40个试次 = 1280个样本,每个样本40通道 × 特征数,如果每个通道算20个特征,那就是800维。直接用800维特征去做SVM,极易过拟合。
特征构建时,我倾向于分两步走。第一步是通道分组:根据情绪研究的先验,把通道按脑区划分,额叶(F3、F4、Fz等)、颞叶(T7、T8等)、顶叶(C3、C4、Cz等)、枕叶(O1、O2等)。特征的提取和组合按脑区来做,而不是逐通道独立建模。第二步是特征降维,后面细讲。
在MATLAB里,特征矩阵通常是一个cell数组或table。我的习惯是每个受试者单独建特征矩阵,然后在样本维度上做跨受试者合并或留一受试者交叉验证。这里有个容易踩的坑:跨受试者分类时,如果直接把所有受试者的样本混在一起随机划分训练测试集,会引入数据泄露风险,因为同一试次的多个时间片段可能同时出现在训练和测试集里,导致准确率虚高。正确做法是按受试者划分,用一部分受试者训练,另一部分受试者测试,或者做留一受试者交叉验证。
3. 分类器建模与参数优化
3.1 特征标准化与降维的选择策略
分类器训练之前,特征标准化是必须做的一步。不同特征量纲差异巨大,比如功率谱密度可能是10的负几次方量级,样本熵是0到1量级,如果不做标准化,SVM和KNN的结果会被量大纲的特征主导。我用的是z-score标准化,即每个特征减去均值除以标准差,MATLAB里zscore函数一行搞定。
降维方面,PCA是最常用的方法。但直接用PCA降维到很低维度(比如2维或3维)往往会丢失有效信息,我一般保留能解释95%方差的主成分数量。在DEAP数据集上,800维特征经过PCA后通常保留60到120个主成分,分类准确率依然稳定。
另一个被低估的方法是特征选择,比如用ReliefF算法或卡方检验去筛选与标签最相关的特征子集。这个方法对可解释性要求高的场景特别有价值,因为你能看出哪些脑区和哪些频段是对情绪区分贡献最大的——这对于论文讨论部分很重要,纯PCA降维后特征就不可解释了。
3.2 分类器选型:SVM、KNN还是随机森林
我的基准方案是线性SVM和RBF核SVM各跑一遍,然后对比随机森林和KNN。下表是几个分类器在DEAP数据集上(效价二分类、8个受试者、50次实验平均)的表现对比:
| 分类器 | 平均准确率 | 训练时间 | 调参难度 | 适用场景 |
|---|---|---|---|---|
| 线性SVM | 83.2% | 极快 | 低 | 特征维度高、样本量中等时的首选 |
| RBF-SVM | 85.6% | 快 | 中(需调C和gamma) | 特征线性不可分时效果更好 |
| KNN(k=5) | 78.9% | 无训练 | 低 | 特征维度较低时可用,高维下效果差 |
| 随机森林 | 84.8% | 中等 | 中(需调树数和深度) | 特征间有复杂交互时表现好 |
| LDA | 81.5% | 极快 | 低 | 特征接近高斯分布且类别协方差相近时 |
LDA其实被很多人遗忘,但它在线性分类里非常稳健,尤其当样本量小时比SVM更不容易过拟合。我通常先用LDA跑一个baseline,再做SVM提升。
SVM调参在MATLAB里用fitcsvm加上OptimizeHyperparameters参数可以自动搜索,但计算量大。我手动调参的经验是:RBF-SVM中C在0.1到10之间、gamma在0.01到1之间去网格搜索,结果一般不会差。fitcsvm默认的参数对EEG特征通常不是最优,一定要自己调。
3.3 交叉验证策略与评估指标衡量
交叉验证策略直接决定了你报告的数字有没有说服力。EEG情绪分类里最容易被审稿人问的问题就是:你的模型有没有数据泄露?
如果按样本随机打乱做10折交叉验证,同一次实验的多个epoch可能会被分到训练集和测试集两边,特征分布高度相似,测试准确率会比真实水平虚高5到10个百分点。正确的做法是按单个试次(trial)划分,即把40个试次作为最小单位,10折交叉验证时保证同一试次的所有数据只在训练集或只在测试集。更严格的则是按受试者划分的训练集和测试集。
评估指标只看准确率是远远不够的。类别不平衡时,比如正性样本占70%,你全猜正性就有70%准确率,但这毫无意义。至少要看混淆矩阵、F1-score、AUC这三个指标。MATLAB里用confusionmat函数可以得到混淆矩阵,roc曲线和AUC则用perfcurve函数绘制。我在论文里都是准确率加AUC一起报,AUC比准确率更稳健,因为它和分类阈值无关。
对多分类任务,比如效价/唤醒度四分类,则要计算每个类别的precision、recall和macro F1。MATLAB里classificationMetrics接口可以搞定,或者自己写个十几行的计算函数。
4. 常见问题、踩坑心得与排查技巧
4.1 分类结果虚高,基本都是数据泄露问题
遇到分类准确率异常高(比如接近100%),第一反应不是高兴,而是怀疑数据泄露。最常见的泄露来源有三个:
一是数据集划分时使用了随机划分,没有处理同受试者或同试次的重复样本。处理方案是分组划分,MATLAB里用cvpartition或groups参数指定分组变量。
二是预处理阶段使用了全局信息。比如对整个数据集做z-score标准化时,先计算了所有样本的均值和标准差再划分训练测试,这导致测试集的信息被训练集看到。标准做法是在训练集上计算均值和标准差,再应用到测试集。对PCA也是一样的逻辑,只用训练集拟合PCA变换矩阵,测试集用同一个变换参数做投影。
三是特征选择时用到了全部样本的标签。ReliefF或卡方检验如果是在全量数据上做的,筛选出的特征已经隐含着测试集的信息。正确做法是特征选择放进交叉验证的每一折内部,只基于训练部分做选择。
4.2 个别受试者分类效果差,是必然现象
EEG信号个体差异极大,某几个受试者的分类准确率低于随机水平是正常现象。原因可能是该受试者数据中有较多伪迹没被ICA完全去除,也可能是该受试者的情绪反应较弱,脑电特征本身区分度低。
我遇到这种受试者时,先检查干扰通道和分段质量,确认预处理没有问题后,再比较该受试者的特征分布是否和其他受试者有明显差异。如果分布差异大,则可以考虑是否要从分析中剔除。但要注意,随意剔除受试者在科研中是有争议的,需要明确记录剔除标准和数量。如果在算法层面优化,可以用域适应(domain adaptation)方法,比如对所有受试者的特征做对齐(如欧氏对齐或基于流形的对齐),把不同受试者的特征分布拉近,再训练分类器。这个方法对跨受试者分类的提升很显著,我实测能把个别受试者的准确率从55%拉到70%左右。
4.3 MATLAB代码执行效率与内存优化技巧
EEG数据通常是四维矩阵:通道 × 时间点 × 试次 × 受试者。直接循环遍历每个受试者、每个试次去做特征计算,代码会跑很久。几个提升效率的经验:
一是尽量用矩阵操作替代循环。比如用reshape和permute把四维数据重排成二维矩阵,一次性喂给特征提取函数。
二是特征提取函数尽量用mex文件或向量化实现。MATLAB的FilterDesign工具箱和Signal Processing Toolbox里有很多自带的优化函数,优先用这些函数。如果自己写样本熵的代码,注意循环次数多时会很慢,可以预先用分块统计减少内层循环。
三是在内存足够的情况下,把预处理好的数据一次性加载进工作区,避免频繁的磁盘IO。DEAP数据集全量大概有2GB多,普通开发机完全可以放在内存里。
四是并行计算。受试者级别的特征提取天然可并行,用parfor替代for就能跑满多核CPU,实测在8核机器上可以提速4到5倍。要注意parfor需要提前把数据拆分成独立的分片,不能在循环里依赖共享变量。
4.4 实验记录规范:比算法更重要的习惯
最后聊一个容易被忽略但对科研极其重要的点:实验记录。EEG分析环节多、参数杂,如果每步参数没有记录下来,一个月后你可能完全不知道自己当初用了什么滤波器、什么窗口长度、什么特征计算方式。
我的习惯是每个数据集建一个配置脚本,里面定义所有参数:采样率、滤波范围、陷波频率、重参考方式、ICA算法、epoch长度、特征类型列表、分类器类型、交叉验证方式、随机种子。每次跑实验前运行配置脚本,跑完把结果和配置一起存档。这样即使算法被推翻重来,也能快速复现之前的实验。
此外,随机种子必须固定下来。SVM和随机森林都有随机性,特别是交叉验证的样本划分,如果不固定种子,每次结果都不太一样,调试时很难判断改动是否真的有效。代码开头用rng(42)固定种子,是成本最低的一个好习惯。
5. 这套方案还能怎么扩展
传统特征加经典分类器这套组合,上限大约在85%到90%之间。想再往上突破,通常有两个方向。
第一方向是深度学习。用CNN直接对原始EEG时间序列做端到端分类,或者把多通道EEG转成拓扑图结构,用图神经网络提取空间特征。EEGNet是最经典的轻量级网络结构,模型小、效果好,MATLAB的Deep Learning Toolbox可以直接搭建。但要注意,EEG样本量普遍不大,深度模型很容易过拟合,需要配合数据增强(比如加噪声、在时间轴上随机裁切、通道随机dropout)来用。
第二个方向是功能连接网络特征。情绪状态不只是单个脑区的活动变化,还表现为脑区之间的协同模式改变。计算各通道间的相位锁定值(PLV)或相干性,构建功能连接矩阵,再把这个矩阵当作特征进行分类。这个方向的好处是神经科学可解释性极强,很多审稿人喜欢,但计算量比单通道特征大不少,而且连接特征的维度更高,降维和特征选择的压力更大。
我个人目前的做法是保留传统特征方案作为baseline,同时用EEGNet做对比实验。两种方法各跑一套,取长补短,效果都比单一方案更有说服力。
最后再分享一个我吃过亏的教训:任何新特征、新分类器,都要先在单个受试者的小数据上验证一遍逻辑,确认代码没有bug再上全量数据。直接拿全量数据跑,一旦发现结果不对劲,排查成本非常高。慢就是快,做EEG分析,最多的坑不是算法不会用,而是流程不规范导致的实验结果不可信。数据规范化、验证流程化、记录完整化,这三点做到了,后面的路就好走了。
本文还有配套的精品资源,点击获取