资讯动态

基于EEG的脑电情绪分析系统:预处理、特征提取与分类模型实现

发布时间:2026/10/20 13:22:09 来源:尧图企业网站定制
简介基于EEG信号的脑电情绪分析系统源码是一套面向脑电信号处理与情绪识别研究者的完整工程涵盖数据预处理、特征提取、模型训练与预测、前端展示等核心环节可用于情绪监测、情感计算等场景。压缩包共49个文件、约11.51MB主要包含6个Python源文件、8个HTML界面文件、6个XML配置、4个PyTorch模型文件.pth、多个.pkl序列化模型以及JPG/PNG可视化图片后端基于Python实现前端提供直观交互。系统通过分析EEG信号捕捉情绪状态适合神经科学、人机交互等方向的科研人员与开发者学习、复用或二次开发。已有483人学习借助这份源码可快速搭建脑电情绪分析框架理解从原始信号采集、特征工程到模型推理的完整流程为相关课题提供可直接运行的参考实现。1. 基于EEG信号的脑电情绪分析系统先看数据再看模型源码才有意义拿到一份脑电情绪分析系统的源码很多人第一反应是直接跑模型、看准确率曲线。但实际训练几轮之后就会发现真正决定系统能不能用的从来不是分类器那几行调用而是数据预处理怎么洗、特征口径怎么统一、源码结构怎么组织——这三件事没理顺再好的模型也只会给你一个虚高的离线分数。本文从公开情绪脑电数据集出发把一条能落地的主线完整拆开原始EEG怎么清洗、情绪相关特征怎么提、分类模型怎么调、推理端代码怎么组织以及中间最容易翻车的地方在哪。适合正在做情感计算课题、或者想把情绪识别塞进原型设备的开发者按章节顺序跟着做能少走不少弯路。2. EEG预处理流水线滤波、去伪迹与分段的参数怎么设2.1 数据集格式先行通道数、采样率与标签协议做情绪脑电分析第一步不是写代码而是把数据集的物理参数弄清楚。常见公开情绪数据集的记录格式差别不大但细节不一致会直接让后续代码返工通道布局、采样率、电极位置、刺激时间戳和标签协议都需要提前对齐。我一般会先写一段读数据的脚本把原始数组的形状、通道名列表、采样率和事件标记打印出来确认再决定预处理参数。比如32通道、128Hz采样、每段实验记录约60秒、标签按效价和唤醒度打分的协议和64通道、512Hz采样、只给二分类标签的数据集处理方式完全不同。采样率影响滤波边界通道布局影响ICA和坏道检测标签协议影响分类任务的设定这三项没确认后面每一步都是黑匣子。2.2 带通滤波参数与陷波顺序先带宽后工频脑电有效成分集中在低频段工程上通常先做带通滤波加一个工频陷波。常见做法是带通范围设为0.5到45Hz使用四阶Butterworth滤波器如果采集环境里有明显50Hz干扰再加中心频率50Hz的陷波器。实现时我用filtfilt而不是lfilter因为lfilter是因果滤波会引入相位偏移导致后面做事件分段时波形位置错位filtfilt是做零相位双向滤波波形起始位置保持不变这对情绪分段里基线对齐很关键。滤波顺序上先带通再陷波和先陷波再带通结果差异不大但务必在滤波之前先剔除极端坏段和幅值跳变的片段否则一个幅值异常的通道会把滤波结果整体拉偏。滤波边界不是死的如果数据里肌电伪迹严重把上限收到40Hz能明显改善分类稳定度。2.3 去眼电伪迹与事件分段样本要对齐到情绪刺激眼电是情绪脑电里最典型的伪迹眨眼和眼动会产生大幅低频成分功率谱上会污染delta和theta频带。常见做法是先用独立成分分析ICA把多通道信号分解成若干独立成分再根据成分的拓扑分布和时域波形剔除眼电成分。ICA之前必须完成带通滤波和坏道剔除否则成分分解会被噪声带偏。分段时一般以情绪刺激呈现时刻为0点截取刺激后第3到第6秒作为分析窗口这段窗口能避开刺激刚出现时的视觉诱发电位又保留了足够长的稳态情绪响应。每个分段还要做基线校正用刺激前200毫秒的平均值作为基线减掉消除缓慢漂移。2.4 一套可复用的预处理实现下面这段代码把滤波到分段的过程串起来输入是连续记录的原始数据输出是可供特征提取使用的分段时间序列。代码里使用了scipy的滤波函数和sklearn的FastICA实现。import numpy as np from scipy import signal from sklearn.decomposition import FastICA def preprocess_raw(raw, sfreq128, event_idx(3, 6), baseline(-0.2, 0)): raw: (n_channels, n_samples) 连续脑电数据 event_idx: 刺激后取用的时间段单位秒 baseline: 基线校正窗口单位秒 # 0.5~45Hz 带通滤波零相位 b, a signal.butter(4, [0.5, 45], btypebandpass, fssfreq) filtered signal.filtfilt(b, a, raw, axis-1) # 50Hz 陷波 bn, an signal.iirnotch(50, 30, fssfreq) filtered signal.filtfilt(bn, an, filtered, axis-1) # ICA 去眼电保留 24 个成分 ica FastICA(n_components24, max_iter300, random_state0) ica.fit(filtered.T) components ica.fit_transform(filtered.T).T # 按眼电参考通道的相关性识别并剔除伪迹成分 eog_ch raw[0] # 第一通道为眼电参考时适用 corrs [abs(np.corrcoef(comp, eog_ch)[0, 1]) for comp in components] bad_idx np.argsort(corrs)[-2:] # 剔除相关性最高的2个成分 cleaned filtered - ica.mixing_[:, bad_idx] components[bad_idx] # 事件分段与基线校正 epochs [] for onset in event_onsets: start onset int(event_idx[0] * sfreq) end onset int(event_idx[1] * sfreq) base_s onset int(baseline[0] * sfreq) base_e onset int(baseline[1] * sfreq) ep cleaned[:, start:end] ep - ep[:, base_s:base_e].mean(axis1, keepdimsTrue) epochs.append(ep) return np.array(epochs) # (n_epochs, n_channels, n_samples)预处理里最关键的两个参数是带通边界和ICA成分数。带通边界决定了你保留哪些频率成分参与情绪分析过低会把漂移放进信号过高会引入肌电。ICA成分数一般取通道数的四分之三左右情绪数据里眼球运动较强的被试可以适当增加到接近通道数但成分越多计算越慢小样本下也更容易过拟合。眼电参考通道不是每个数据集都有没有参考通道时可以改为观察成分的波形眨眼成分通常呈现低频大幅度、波形上带有明显的一次性尖峰脉冲特征。提示如果某个被试的数据经过ICA后出现高频噪声放大检查该段数据是否存在电极松动造成的方波样伪迹这类伪迹ICA无法有效分离需要直接从样本里丢弃。3. 特征提取与建模频带能量、微分熵与分类器选型的落地写法3.1 手工特征为什么在情绪任务里仍是首选情绪脑电分类有一个很现实的情况样本量普遍不大一次实验几十段数据、几十个被试是常态。在这种规模下端到端深度模型的收益有限手工特征加传统分类器反而是最稳的路线。脑电情绪研究里最常用的是频带特征因为情绪状态的变化会体现在不同频带功率的增减上比如积极情绪常伴随额叶alpha不对称性变化消极情绪激活theta和beta频带的特定分布。手工特征的另一层好处是可解释训练完可以检查每个通道每个频带的重要性定位到具体脑区这对写分析报告和调试都很有帮助。深度学习模型在数据量充足时能自动学到空间和时间特征但样本不足时很容易过拟合到单个被试的个体模式上。3.2 Welch功率谱与微分熵的实现频带特征的计算路径一般是先估计功率谱密度再把各频带内的功率积分得到每个通道在每个频带的能量值。功率谱估计用Welch法足够稳定分段加窗后再做FFT能有效降低单次FFT的方差。微分熵是情绪脑电里另一个高频出现的特征本质是对每个频带的功率谱做对数变换它比单纯功率对幅值尺度更鲁棒换被试或换设备后数值分布更一致。计算时先求Welch功率谱然后按频带切片对带内功率求和后再取log2。频带边界采用经典划分法delta为0.5到4Hztheta为4到8Hzalpha为8到13Hzbeta为13到30Hzgamma为30到45Hz。import numpy as np from scipy import signal BANDS { delta: (0.5, 4), theta: (4, 8), alpha: (8, 13), beta: (13, 30), gamma: (30, 45) } def extract_features(epoch, sfreq128): epoch: (n_channels, n_samples) 单个分段 返回每个通道每个频带的功率和微分熵拼接的特征向量 freqs, psd signal.welch(epoch, fssfreq, npersegsfreq * 4, noverlapsfreq * 3, axis-1) feat [] for band, (lo, hi) in BANDS.items(): idx (freqs lo) (freqs hi) for ch in range(epoch.shape[0]): power psd[ch, idx].sum() feat.append(power) feat.append(np.log2(power 1e-12)) # 微分熵近似 return np.array(feat)这段代码里最值得调的是Welch的窗长和重叠率。nperseg取4秒noverlap取3秒等效每段功率谱用了多个窗平均方差很小适合128Hz采样率下的4秒分段。如果你的分段长度只有2秒窗长要缩到2秒以下否则频域分辨率不足时低频带计算会明显失真。微分熵那里的加1e-12是防止某通道某频带功率恰好为零时取对数报错实际数据里这种概率不高但换了采集设备后遇到过几次。特征向量长度是5个频带乘通道数再乘232通道时每段产生320个特征这个维度对SVM和随机森林都很友好不需要额外做特征选择。3.3 特征标准化与标签处理特征提取完成后标准化是必做的一步。不同被试的脑电总体幅值存在天然差异直接混在一起训练会让分类器主要学习个体差异而不是情绪差异。常见做法是用训练集的均值和标准差做z-score标准化然后把同样的参数应用到验证集和测试集。注意标准化参数必须只从训练集计算否则验证集信息泄漏离线准确率会虚高。标签处理上如果原始情绪量表是连续打分需要先转换为分类标签常见做法是把评分按中位数二分得到正负二分类也可以按高唤醒度低唤醒度切分。二分类是情绪系统最稳妥的起步任务多分类情绪识别在数据量不足时指标波动很大。3.4 什么情况值得切换端到端模型手工特征在数据量少于几千段时优势明显但如果你的数据规模足够大或者要把系统部署到多种采集设备上端到端卷积网络可以免去手工调整频带边界的工作模型会自动学习到跨设备的通用模式。切换到深度模型的信号是同一套手工特征在交叉验证里的准确率不再随特征增加而提升同时你有足够数据支撑训练。端到端模型的输入建议保留原始时间序列加通道维度避免先压缩成手工特征再喂网络那样退化为浅层模型没有发挥端到端的优势。4. 系统源码的组织与训练主流程从特征到可复用模型4.1 源码目录怎么分训练端、推理端、配置文件各司其职情绪分析系统最怕的是预处理、特征、训练、推理全部堆在一个文件里。换一个数据集、调一个参数就要全局翻代码改完不知道影响面在哪。我常用的目录结构是把数据、特征、模型、源码四个层次分开所有参数统一放进配置文件管理。预处理脚本负责原始数据到分段数组特征脚本负责分段数组到特征矩阵训练脚本负责特征矩阵到模型文件推理脚本负责加载模型做实时预测。这样每条数据链路都是单向依赖调试时能快速定位是哪个环节出了问题。4.2 训练主流程与关键参数搜索训练环节我一般先跑一个SVM基线。SVM在高维小样本场景下比随机森林更稳定RBF核能捕捉频带特征里的非线性关系。需要搜索的参数主要是惩罚系数C和RBF核的gammaC控制误分类惩罚力度gamma控制核函数的径向作用范围。搜索范围按指数网格铺开C取0.1到100gamma取0.001到1配合五折交叉验证找最优组合。除模型参数外还会固定一个随机种子保证每次跑的划分一致这是做对比实验的基本纪律。import numpy as np from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.model_selection import GridSearchCV import joblib # 加载特征和标签 X np.load(features.npy) # (n_epochs, n_features) y np.load(labels.npy) # (n_epochs,) # 标准化只 fit 训练集 scaler StandardScaler() X scaler.fit_transform(X) param_grid {C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1]} grid GridSearchCV( SVC(kernelrbf, class_weightbalanced, random_state42), param_grid, cv5, scoringaccuracy, n_jobs-1 ) grid.fit(X, y) print(best acc:, grid.best_score_, best params:, grid.best_params_) # 保存模型和标准化参数 joblib.dump(grid.best_estimator_, models/svm.joblib) joblib.dump(scaler, models/scaler.joblib)标准化和交叉验证的组合里有个容易踩的细节交叉验证在内部划分训练集和验证集时标准化参数是在整个X上提前算好的这会让每一折的验证集都参与过均值和方差的计算属于轻微的信息泄漏。严格做法是把StandardScaler放进Pipeline里再交给GridSearchCV让每一折重新fit标准化参数改动成本不高推荐直接按严格方式写。class_weightbalanced是处理情绪类别不均衡最简单的办法情绪评分做中位数二分后两边比例通常接近但也遇到过某个被试正负样本差出两倍的情况。4.3 从离线训练到在线推理的转换点训练好的模型文件包含标准化参数和SVM核参数推理端加载后要严格保持和训练端一致的序列先对原始信号做同样的带通滤波再提取同样的频带特征特征拼接顺序也必须一致最后标准化再预测。最容易出问题的是特征拼接顺序错位训练时频带在外层循环通道在内层推理时如果写成通道在外层模型还能跑但结果全错。建议把特征提取函数做成训练和推理共用的模块从源头上避免两套代码逻辑分叉。5. 情绪脑电解码避坑五个常见翻车点的现象与处理5.1 换被试后准确率跌回随机水平现象在开发集上准确率稳定在85%以上换一个新被试的数据测试准确率直接掉到50%上下。原因情绪脑电存在显著的被试间差异模型学到了每个被试的个体脑电模式而不是通用的情绪模式。解决评估时必须做按被试划分的交叉验证也就是留一被试法确保测试被试完全没参与过训练。如果留一被试验证准确率明显低于随机划分说明你的特征被个体差异主导了优先尝试对每个被试分别做标准化。5.2 ICA分解不收敛或去除后效果不升反降现象ICA迭代多次不收敛或者去除眼电成分后准确率反而下降。原因输入数据里有大幅值坏段或通道噪声使分解算法无法稳定估计混合矩阵另一个原因是人为剔除了过多成分把有效情绪信号也一起带走了。解决ICA前先做坏道剔除和坏段标记最简单的方法是计算每个通道的方差方差超过全通道中位数十倍以上的直接剔除去除成分数量的经验值是两到三个宁少勿多。5.3 情绪维度的混淆导致指标不可比现象论文里报告的准确率是90%自己复现只有70%反复检查代码找不到问题。原因任务定义不一致有的工作做的是效价二分类有的做唤醒度二分类有的做四分类标签切分阈值和维度不同准确率天然不可比。解决在源码里显式记录标签协议比如明确写入按效价中位数二分特征文件命名里带上标签定义混淆矩阵打印出来对照分析不要只盯着一个加权平均指标。5.4 实时推理延迟高到无法交互使用现象离线流程跑通后进行实时演示预测结果总是慢半拍交互体验很差。原因实时循环里每次采到新数据都对整段信号重新做滤波和特征提取窗口重叠过大、Welch窗长过长导致特征更新频率跟不上显示刷新。解决把分析和显示拆分到两个线程分析线程以固定周期处理缓冲区数据显示线程只读最新结果Welch窗长从4秒缩短到2秒重叠率从75%降到50%延迟会明显下降。5.5 坏道引发的特征分布漂移现象某个通道在某一时段突然数据异常特征矩阵里该通道的数值比其他通道高两个数量级训练出的模型几乎只看这一个通道。原因电极接触不良或移动导致接触阻抗变化信号出现大幅跳变或平直段。解决在每个分段提取特征前做一次通道级检查计算峰峰值和方差超出正常范围的通道用邻域通道均值替代并在特征向量里增加通道质量标记位质量不可靠的样本直接不参与训练。提示预处理参数改动会级联影响特征分布和分类结果建议把每次实验用到的滤波边界、ICA成分数、特征抽取参数固定到配置文件里模型文件名带上参数摘要避免过两周就忘了当时的训练口径。6. 实时验证技巧把离线精度换算成可用性离线准确率只能说明模型在静态分片上的分类能力真实系统更关心的是连续运行时的稳定性和延迟。我习惯在部署前做一次模拟实时回放把测试集里的分段时间序列按真实采样节奏喂给推理代码逐窗口记录输出标签、预测概率和处理耗时。回放验证能暴露很多离线测试看不到的问题比如某类情绪在连续帧间标签抖动剧烈或者某段信号处理耗时突然变长导致帧率不稳。回放脚本的核心是维护一个滑动缓冲区每次只更新最新的数据块特征计算只针对缓冲区整体而不是整段历史信号。实现上可以复用训练时的特征提取函数但要把窗口长度缩短到2秒叠加1秒的新数据形成每1秒刷新一次预测的节奏。验证结束后统计三个量平均单帧耗时、标签翻转频率、以及模拟实时预测和离线预测的吻合率。如果单帧平均耗时超过刷新周期的一半说明缓存队列会持续堆积必须优化特征计算或降低窗口重叠。除了延迟还要验证模型对信号质量恶化的鲁棒性。在回放脚本里引入模拟干扰随机把一个通道的数据替换成噪声看预测标签是否剧烈跳动。这一步往往是现实部署时决定系统口碑的关键用户不会保证电极贴合始终良好。经过几次回放测试我的习惯是把滑窗重叠率、缓冲区长度、类别输出阈值都做成命令行参数方便在不同采集环境下快速调整而不是每次改代码重新训练。实践里最深刻的教训是某次只改了滤波上限导致所有离线指标完全变样后来所有参数都归档到配置文件并同步备份这套习惯救了很多次后续的调试。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑