
OpenBCI-机器学习入门:从脑电信号到模式识别
文章目录
- OpenBCI-机器学习入门:从脑电信号到模式识别
-
- 引言
- 机器学习在BCI中的应用概述
- 机器学习基础概念
- BCI常用机器学习算法
-
- [1. 线性判别分析 (LDA)](#1. 线性判别分析 (LDA))
- [2. 支持向量机 (SVM)](#2. 支持向量机 (SVM))
- [3. 随机森林 (Random Forest)](#3. 随机森林 (Random Forest))
- [4. k近邻算法 (k-NN)](#4. k近邻算法 (k-NN))
- [5. 朴素贝叶斯 (Naive Bayes)](#5. 朴素贝叶斯 (Naive Bayes))
- 完整实战:脑电信号分类流程
- 交叉验证与超参数调优
- 实战案例:基于机器学习的注意力监测系统
- 常见问题与解决方案
- 总结与展望
- 思考与练习
引言
在前几篇文章中,我们已经学习了脑电信号的采集、预处理和特征提取技术。现在,我们进入BCI系统最核心的环节------机器学习与模式识别。通过机器学习算法,我们可以让计算机"理解"大脑发出的信号,实现意念控制等神奇功能。
本文将从零开始介绍机器学习在脑电信号处理中的应用,包括常用算法、完整的工作流程和实战代码。
机器学习在BCI中的应用概述
什么是机器学习?
机器学习是人工智能的一个分支,它使计算机能够从数据中学习并做出预测,而无需显式编程。在BCI领域,机器学习的目标是:
- 模式识别:从脑电信号中识别出特定的思维模式
- 分类决策:将脑电信号分类到不同的意图类别
- 预测控制:根据识别结果控制外部设备
BCI中的机器学习流程
#mermaid-svg-Hrf6zGabIPutrcnD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Hrf6zGabIPutrcnD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Hrf6zGabIPutrcnD .error-icon{fill:#552222;}#mermaid-svg-Hrf6zGabIPutrcnD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Hrf6zGabIPutrcnD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Hrf6zGabIPutrcnD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Hrf6zGabIPutrcnD .marker.cross{stroke:#333333;}#mermaid-svg-Hrf6zGabIPutrcnD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Hrf6zGabIPutrcnD p{margin:0;}#mermaid-svg-Hrf6zGabIPutrcnD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Hrf6zGabIPutrcnD .cluster-label text{fill:#333;}#mermaid-svg-Hrf6zGabIPutrcnD .cluster-label span{color:#333;}#mermaid-svg-Hrf6zGabIPutrcnD .cluster-label span p{background-color:transparent;}#mermaid-svg-Hrf6zGabIPutrcnD .label text,#mermaid-svg-Hrf6zGabIPutrcnD span{fill:#333;color:#333;}#mermaid-svg-Hrf6zGabIPutrcnD .node rect,#mermaid-svg-Hrf6zGabIPutrcnD .node circle,#mermaid-svg-Hrf6zGabIPutrcnD .node ellipse,#mermaid-svg-Hrf6zGabIPutrcnD .node polygon,#mermaid-svg-Hrf6zGabIPutrcnD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Hrf6zGabIPutrcnD .rough-node .label text,#mermaid-svg-Hrf6zGabIPutrcnD .node .label text,#mermaid-svg-Hrf6zGabIPutrcnD .image-shape .label,#mermaid-svg-Hrf6zGabIPutrcnD .icon-shape .label{text-anchor:middle;}#mermaid-svg-Hrf6zGabIPutrcnD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Hrf6zGabIPutrcnD .rough-node .label,#mermaid-svg-Hrf6zGabIPutrcnD .node .label,#mermaid-svg-Hrf6zGabIPutrcnD .image-shape .label,#mermaid-svg-Hrf6zGabIPutrcnD .icon-shape .label{text-align:center;}#mermaid-svg-Hrf6zGabIPutrcnD .node.clickable{cursor:pointer;}#mermaid-svg-Hrf6zGabIPutrcnD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Hrf6zGabIPutrcnD .arrowheadPath{fill:#333333;}#mermaid-svg-Hrf6zGabIPutrcnD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Hrf6zGabIPutrcnD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Hrf6zGabIPutrcnD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Hrf6zGabIPutrcnD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Hrf6zGabIPutrcnD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Hrf6zGabIPutrcnD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Hrf6zGabIPutrcnD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Hrf6zGabIPutrcnD .cluster text{fill:#333;}#mermaid-svg-Hrf6zGabIPutrcnD .cluster span{color:#333;}#mermaid-svg-Hrf6zGabIPutrcnD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Hrf6zGabIPutrcnD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Hrf6zGabIPutrcnD rect.text{fill:none;stroke-width:0;}#mermaid-svg-Hrf6zGabIPutrcnD .icon-shape,#mermaid-svg-Hrf6zGabIPutrcnD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Hrf6zGabIPutrcnD .icon-shape p,#mermaid-svg-Hrf6zGabIPutrcnD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Hrf6zGabIPutrcnD .icon-shape .label rect,#mermaid-svg-Hrf6zGabIPutrcnD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Hrf6zGabIPutrcnD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Hrf6zGabIPutrcnD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Hrf6zGabIPutrcnD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
脑电数据采集
数据预处理
特征提取
特征选择
数据集划分
模型训练
模型评估
评估结果满意?
模型部署
调整参数/更换算法
典型BCI机器学习应用场景
| 应用场景 | 输入信号 | 输出目标 | 典型算法 |
|---|---|---|---|
| 运动想象 | EEG信号 | 左/右手运动意图 | SVM、LDA、CNN |
| 情绪识别 | EEG信号 | 喜/怒/哀/乐 | RF、MLP、Transformer |
| 注意力监测 | EEG信号 | 高/低注意力 | SVM、随机森林 |
| P300拼写器 | EEG信号 | 字符选择 | LDA、SVM |
| SSVEP识别 | EEG信号 | 频率识别 | CCA、LDA |
机器学习基础概念
监督学习与无监督学习
在BCI中,我们主要使用监督学习:
#mermaid-svg-7I5PxmDP6kFap6p5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7I5PxmDP6kFap6p5 .error-icon{fill:#552222;}#mermaid-svg-7I5PxmDP6kFap6p5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7I5PxmDP6kFap6p5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7I5PxmDP6kFap6p5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7I5PxmDP6kFap6p5 .marker.cross{stroke:#333333;}#mermaid-svg-7I5PxmDP6kFap6p5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7I5PxmDP6kFap6p5 p{margin:0;}#mermaid-svg-7I5PxmDP6kFap6p5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 .cluster-label text{fill:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 .cluster-label span{color:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 .cluster-label span p{background-color:transparent;}#mermaid-svg-7I5PxmDP6kFap6p5 .label text,#mermaid-svg-7I5PxmDP6kFap6p5 span{fill:#333;color:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 .node rect,#mermaid-svg-7I5PxmDP6kFap6p5 .node circle,#mermaid-svg-7I5PxmDP6kFap6p5 .node ellipse,#mermaid-svg-7I5PxmDP6kFap6p5 .node polygon,#mermaid-svg-7I5PxmDP6kFap6p5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7I5PxmDP6kFap6p5 .rough-node .label text,#mermaid-svg-7I5PxmDP6kFap6p5 .node .label text,#mermaid-svg-7I5PxmDP6kFap6p5 .image-shape .label,#mermaid-svg-7I5PxmDP6kFap6p5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-7I5PxmDP6kFap6p5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7I5PxmDP6kFap6p5 .rough-node .label,#mermaid-svg-7I5PxmDP6kFap6p5 .node .label,#mermaid-svg-7I5PxmDP6kFap6p5 .image-shape .label,#mermaid-svg-7I5PxmDP6kFap6p5 .icon-shape .label{text-align:center;}#mermaid-svg-7I5PxmDP6kFap6p5 .node.clickable{cursor:pointer;}#mermaid-svg-7I5PxmDP6kFap6p5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7I5PxmDP6kFap6p5 .arrowheadPath{fill:#333333;}#mermaid-svg-7I5PxmDP6kFap6p5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7I5PxmDP6kFap6p5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7I5PxmDP6kFap6p5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7I5PxmDP6kFap6p5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7I5PxmDP6kFap6p5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7I5PxmDP6kFap6p5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7I5PxmDP6kFap6p5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7I5PxmDP6kFap6p5 .cluster text{fill:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 .cluster span{color:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7I5PxmDP6kFap6p5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7I5PxmDP6kFap6p5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-7I5PxmDP6kFap6p5 .icon-shape,#mermaid-svg-7I5PxmDP6kFap6p5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7I5PxmDP6kFap6p5 .icon-shape p,#mermaid-svg-7I5PxmDP6kFap6p5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7I5PxmDP6kFap6p5 .icon-shape .label rect,#mermaid-svg-7I5PxmDP6kFap6p5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7I5PxmDP6kFap6p5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7I5PxmDP6kFap6p5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7I5PxmDP6kFap6p5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 监督学习
有标签数据
特征X + 标签Y
训练模型 f: X->Y
无监督学习
无标签数据
特征X
发现数据结构
数据集划分
#mermaid-svg-7yWWWbMdvokWX5BI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7yWWWbMdvokWX5BI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7yWWWbMdvokWX5BI .error-icon{fill:#552222;}#mermaid-svg-7yWWWbMdvokWX5BI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7yWWWbMdvokWX5BI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7yWWWbMdvokWX5BI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7yWWWbMdvokWX5BI .marker.cross{stroke:#333333;}#mermaid-svg-7yWWWbMdvokWX5BI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7yWWWbMdvokWX5BI p{margin:0;}#mermaid-svg-7yWWWbMdvokWX5BI .pieCircle{stroke:#000000;stroke-width:2px;opacity:0.7;}#mermaid-svg-7yWWWbMdvokWX5BI .pieOuterCircle{stroke:#000000;stroke-width:1px;fill:none;}#mermaid-svg-7yWWWbMdvokWX5BI .pieTitleText{text-anchor:middle;font-size:25px;fill:#000000;font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-7yWWWbMdvokWX5BI .slice{font-family:"trebuchet ms",verdana,arial,sans-serif;fill:#000000;font-size:17px;}#mermaid-svg-7yWWWbMdvokWX5BI .legend text{fill:#000000;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:17px;}#mermaid-svg-7yWWWbMdvokWX5BI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 70% 15% 15% 数据集划分比例 训练集 70% 验证集 15% 测试集 15%
评估指标
常用的评估指标包括:
| 指标 | 计算公式 | 含义 |
|---|---|---|
| 准确率 | (TP+TN)/(TP+TN+FP+FN) | 整体预测正确的比例 |
| 精确率 | TP/(TP+FP) | 预测为正例的样本中实际为正例的比例 |
| 召回率 | TP/(TP+FN) | 实际为正例的样本中被正确预测的比例 |
| F1分数 | 2精确率召回率/(精确率+召回率) | 精确率和召回率的调和平均 |
#mermaid-svg-Hnn8fX7O9Q59gJto{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Hnn8fX7O9Q59gJto .error-icon{fill:#552222;}#mermaid-svg-Hnn8fX7O9Q59gJto .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Hnn8fX7O9Q59gJto .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Hnn8fX7O9Q59gJto .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Hnn8fX7O9Q59gJto .marker.cross{stroke:#333333;}#mermaid-svg-Hnn8fX7O9Q59gJto svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Hnn8fX7O9Q59gJto p{margin:0;}#mermaid-svg-Hnn8fX7O9Q59gJto .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto .cluster-label text{fill:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto .cluster-label span{color:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto .cluster-label span p{background-color:transparent;}#mermaid-svg-Hnn8fX7O9Q59gJto .label text,#mermaid-svg-Hnn8fX7O9Q59gJto span{fill:#333;color:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto .node rect,#mermaid-svg-Hnn8fX7O9Q59gJto .node circle,#mermaid-svg-Hnn8fX7O9Q59gJto .node ellipse,#mermaid-svg-Hnn8fX7O9Q59gJto .node polygon,#mermaid-svg-Hnn8fX7O9Q59gJto .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Hnn8fX7O9Q59gJto .rough-node .label text,#mermaid-svg-Hnn8fX7O9Q59gJto .node .label text,#mermaid-svg-Hnn8fX7O9Q59gJto .image-shape .label,#mermaid-svg-Hnn8fX7O9Q59gJto .icon-shape .label{text-anchor:middle;}#mermaid-svg-Hnn8fX7O9Q59gJto .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Hnn8fX7O9Q59gJto .rough-node .label,#mermaid-svg-Hnn8fX7O9Q59gJto .node .label,#mermaid-svg-Hnn8fX7O9Q59gJto .image-shape .label,#mermaid-svg-Hnn8fX7O9Q59gJto .icon-shape .label{text-align:center;}#mermaid-svg-Hnn8fX7O9Q59gJto .node.clickable{cursor:pointer;}#mermaid-svg-Hnn8fX7O9Q59gJto .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Hnn8fX7O9Q59gJto .arrowheadPath{fill:#333333;}#mermaid-svg-Hnn8fX7O9Q59gJto .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Hnn8fX7O9Q59gJto .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Hnn8fX7O9Q59gJto .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Hnn8fX7O9Q59gJto .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Hnn8fX7O9Q59gJto .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Hnn8fX7O9Q59gJto .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Hnn8fX7O9Q59gJto .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Hnn8fX7O9Q59gJto .cluster text{fill:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto .cluster span{color:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Hnn8fX7O9Q59gJto .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Hnn8fX7O9Q59gJto rect.text{fill:none;stroke-width:0;}#mermaid-svg-Hnn8fX7O9Q59gJto .icon-shape,#mermaid-svg-Hnn8fX7O9Q59gJto .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Hnn8fX7O9Q59gJto .icon-shape p,#mermaid-svg-Hnn8fX7O9Q59gJto .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Hnn8fX7O9Q59gJto .icon-shape .label rect,#mermaid-svg-Hnn8fX7O9Q59gJto .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Hnn8fX7O9Q59gJto .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Hnn8fX7O9Q59gJto .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Hnn8fX7O9Q59gJto :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 正例
正例
负例
负例
正例
负例
预测结果
实际类别
预测类别
TP: 真正例
FN: 假负例
预测类别
FP: 假正例
TN: 真负例
BCI常用机器学习算法
1. 线性判别分析 (LDA)
原理:寻找一条直线,使不同类别的数据在这条直线上的投影尽可能分开。
特点:
- 简单快速
- 计算量小
- 在小样本数据集上表现良好
适用场景:P300、SSVEP识别
python
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
# 创建LDA分类器
lda = LinearDiscriminantAnalysis()
# 训练模型
lda.fit(X_train, y_train)
# 预测
y_pred = lda.predict(X_test)
# 评估
accuracy = lda.score(X_test, y_test)
print(f"LDA准确率: {accuracy:.2f}")
2. 支持向量机 (SVM)
原理:寻找最优超平面,使不同类别的数据点到超平面的距离最大。
特点:
- 在高维空间表现优秀
- 适合小样本数据集
- 有多种核函数可选
适用场景:运动想象、情绪识别
#mermaid-svg-0OpROQs9nsrt3bI3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0OpROQs9nsrt3bI3 .error-icon{fill:#552222;}#mermaid-svg-0OpROQs9nsrt3bI3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0OpROQs9nsrt3bI3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0OpROQs9nsrt3bI3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0OpROQs9nsrt3bI3 .marker.cross{stroke:#333333;}#mermaid-svg-0OpROQs9nsrt3bI3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0OpROQs9nsrt3bI3 p{margin:0;}#mermaid-svg-0OpROQs9nsrt3bI3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 .cluster-label text{fill:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 .cluster-label span{color:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 .cluster-label span p{background-color:transparent;}#mermaid-svg-0OpROQs9nsrt3bI3 .label text,#mermaid-svg-0OpROQs9nsrt3bI3 span{fill:#333;color:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 .node rect,#mermaid-svg-0OpROQs9nsrt3bI3 .node circle,#mermaid-svg-0OpROQs9nsrt3bI3 .node ellipse,#mermaid-svg-0OpROQs9nsrt3bI3 .node polygon,#mermaid-svg-0OpROQs9nsrt3bI3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0OpROQs9nsrt3bI3 .rough-node .label text,#mermaid-svg-0OpROQs9nsrt3bI3 .node .label text,#mermaid-svg-0OpROQs9nsrt3bI3 .image-shape .label,#mermaid-svg-0OpROQs9nsrt3bI3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-0OpROQs9nsrt3bI3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0OpROQs9nsrt3bI3 .rough-node .label,#mermaid-svg-0OpROQs9nsrt3bI3 .node .label,#mermaid-svg-0OpROQs9nsrt3bI3 .image-shape .label,#mermaid-svg-0OpROQs9nsrt3bI3 .icon-shape .label{text-align:center;}#mermaid-svg-0OpROQs9nsrt3bI3 .node.clickable{cursor:pointer;}#mermaid-svg-0OpROQs9nsrt3bI3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0OpROQs9nsrt3bI3 .arrowheadPath{fill:#333333;}#mermaid-svg-0OpROQs9nsrt3bI3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0OpROQs9nsrt3bI3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0OpROQs9nsrt3bI3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0OpROQs9nsrt3bI3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0OpROQs9nsrt3bI3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0OpROQs9nsrt3bI3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0OpROQs9nsrt3bI3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0OpROQs9nsrt3bI3 .cluster text{fill:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 .cluster span{color:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0OpROQs9nsrt3bI3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0OpROQs9nsrt3bI3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-0OpROQs9nsrt3bI3 .icon-shape,#mermaid-svg-0OpROQs9nsrt3bI3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0OpROQs9nsrt3bI3 .icon-shape p,#mermaid-svg-0OpROQs9nsrt3bI3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0OpROQs9nsrt3bI3 .icon-shape .label rect,#mermaid-svg-0OpROQs9nsrt3bI3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0OpROQs9nsrt3bI3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0OpROQs9nsrt3bI3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0OpROQs9nsrt3bI3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 投影
数据点
超平面
支持向量
python
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
# 数据标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 创建SVM分类器,使用RBF核
svm = SVC(kernel='rbf', C=1.0, gamma='scale')
# 训练
svm.fit(X_train_scaled, y_train)
# 预测
y_pred = svm.predict(X_test_scaled)
# 评估
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print(f"SVM准确率: {accuracy:.2f}")
3. 随机森林 (Random Forest)
原理:集成多个决策树,通过投票机制得到最终预测结果。
特点:
- 抗过拟合能力强
- 可以处理高维数据
- 可以评估特征重要性
适用场景:情绪识别、注意力监测
python
from sklearn.ensemble import RandomForestClassifier
# 创建随机森林分类器
rf = RandomForestClassifier(
n_estimators=100, # 决策树数量
max_depth=10, # 树最大深度
random_state=42
)
# 训练
rf.fit(X_train, y_train)
# 预测
y_pred = rf.predict(X_test)
# 特征重要性
importances = rf.feature_importances_
print("特征重要性:", importances)
4. k近邻算法 (k-NN)
原理:根据最近的k个邻居的类别来判断当前样本的类别。
特点:
- 简单直观
- 无需训练过程
- 对数据尺度敏感
适用场景:简单的分类任务
python
from sklearn.neighbors import KNeighborsClassifier
# 创建k-NN分类器
knn = KNeighborsClassifier(n_neighbors=5)
# 训练(实际上是存储数据)
knn.fit(X_train, y_train)
# 预测
y_pred = knn.predict(X_test)
5. 朴素贝叶斯 (Naive Bayes)
原理:基于贝叶斯定理和特征独立假设进行分类。
特点:
- 计算速度快
- 适合高维数据
- 假设特征独立
适用场景:文本分类、简单EEG分类
python
from sklearn.naive_bayes import GaussianNB
# 创建朴素贝叶斯分类器
nb = GaussianNB()
# 训练
nb.fit(X_train, y_train)
# 预测
y_pred = nb.predict(X_test)
完整实战:脑电信号分类流程
数据准备
首先,我们需要准备用于训练的脑电数据。这里使用一个模拟的EEG数据集:
python
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# 生成模拟EEG数据
np.random.seed(42)
n_samples = 1000
n_features = 64 # 64个特征
# 类别0:放松状态(alpha波较多)
class0 = np.random.normal(loc=5, scale=2, size=(n_samples//2, n_features))
# 类别1:专注状态(beta波较多)
class1 = np.random.normal(loc=8, scale=2, size=(n_samples//2, n_features))
# 合并数据
X = np.vstack([class0, class1])
y = np.array([0]* (n_samples//2) + [1]*(n_samples//2))
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 数据标准化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
print(f"训练集形状: {X_train.shape}")
print(f"测试集形状: {X_test.shape}")
print(f"类别分布: 训练集 {np.bincount(y_train)}, 测试集 {np.bincount(y_test)}")
模型训练与比较
python
from sklearn.metrics import accuracy_score, f1_score, classification_report
# 定义要测试的模型
models = {
'LDA': LinearDiscriminantAnalysis(),
'SVM': SVC(kernel='rbf', C=1.0, gamma='scale'),
'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
'k-NN': KNeighborsClassifier(n_neighbors=5),
'Naive Bayes': GaussianNB()
}
# 训练并评估所有模型
results = {}
for name, model in models.items():
# 训练
model.fit(X_train_scaled, y_train)
# 预测
y_pred = model.predict(X_test_scaled)
# 评估
accuracy = accuracy_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)
results[name] = {'accuracy': accuracy, 'f1': f1}
print(f"=== {name} ===")
print(classification_report(y_test, y_pred))
print()
结果可视化
python
import matplotlib.pyplot as plt
# 绘制模型对比图
names = list(results.keys())
accuracies = [results[name]['accuracy'] for name in names]
f1_scores = [results[name]['f1'] for name in names]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
ax1.bar(names, accuracies, color='skyblue')
ax1.set_title('模型准确率对比')
ax1.set_ylabel('准确率')
ax1.set_ylim(0.8, 1.0)
ax2.bar(names, f1_scores, color='salmon')
ax2.set_title('模型F1分数对比')
ax2.set_ylabel('F1分数')
ax2.set_ylim(0.8, 1.0)
plt.tight_layout()
plt.show()
模型选择流程图
#mermaid-svg-JHI2W5mR4qj2VYvL{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JHI2W5mR4qj2VYvL .error-icon{fill:#552222;}#mermaid-svg-JHI2W5mR4qj2VYvL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JHI2W5mR4qj2VYvL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JHI2W5mR4qj2VYvL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JHI2W5mR4qj2VYvL .marker.cross{stroke:#333333;}#mermaid-svg-JHI2W5mR4qj2VYvL svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JHI2W5mR4qj2VYvL p{margin:0;}#mermaid-svg-JHI2W5mR4qj2VYvL .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL .cluster-label text{fill:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL .cluster-label span{color:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL .cluster-label span p{background-color:transparent;}#mermaid-svg-JHI2W5mR4qj2VYvL .label text,#mermaid-svg-JHI2W5mR4qj2VYvL span{fill:#333;color:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL .node rect,#mermaid-svg-JHI2W5mR4qj2VYvL .node circle,#mermaid-svg-JHI2W5mR4qj2VYvL .node ellipse,#mermaid-svg-JHI2W5mR4qj2VYvL .node polygon,#mermaid-svg-JHI2W5mR4qj2VYvL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JHI2W5mR4qj2VYvL .rough-node .label text,#mermaid-svg-JHI2W5mR4qj2VYvL .node .label text,#mermaid-svg-JHI2W5mR4qj2VYvL .image-shape .label,#mermaid-svg-JHI2W5mR4qj2VYvL .icon-shape .label{text-anchor:middle;}#mermaid-svg-JHI2W5mR4qj2VYvL .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JHI2W5mR4qj2VYvL .rough-node .label,#mermaid-svg-JHI2W5mR4qj2VYvL .node .label,#mermaid-svg-JHI2W5mR4qj2VYvL .image-shape .label,#mermaid-svg-JHI2W5mR4qj2VYvL .icon-shape .label{text-align:center;}#mermaid-svg-JHI2W5mR4qj2VYvL .node.clickable{cursor:pointer;}#mermaid-svg-JHI2W5mR4qj2VYvL .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JHI2W5mR4qj2VYvL .arrowheadPath{fill:#333333;}#mermaid-svg-JHI2W5mR4qj2VYvL .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JHI2W5mR4qj2VYvL .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JHI2W5mR4qj2VYvL .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JHI2W5mR4qj2VYvL .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JHI2W5mR4qj2VYvL .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JHI2W5mR4qj2VYvL .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JHI2W5mR4qj2VYvL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JHI2W5mR4qj2VYvL .cluster text{fill:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL .cluster span{color:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JHI2W5mR4qj2VYvL .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JHI2W5mR4qj2VYvL rect.text{fill:none;stroke-width:0;}#mermaid-svg-JHI2W5mR4qj2VYvL .icon-shape,#mermaid-svg-JHI2W5mR4qj2VYvL .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JHI2W5mR4qj2VYvL .icon-shape p,#mermaid-svg-JHI2W5mR4qj2VYvL .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JHI2W5mR4qj2VYvL .icon-shape .label rect,#mermaid-svg-JHI2W5mR4qj2VYvL .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JHI2W5mR4qj2VYvL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JHI2W5mR4qj2VYvL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JHI2W5mR4qj2VYvL :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 低维 < 50
高维 >= 50
小样本 < 100
大样本 >= 100
有标注
无标注
数据特征
特征维度
样本量
是否有标注
使用LDA或SVM
使用随机森林
使用SVM或深度学习
使用聚类算法
评估模型性能
选择最优模型
交叉验证与超参数调优
k折交叉验证
python
from sklearn.model_selection import cross_val_score
# 使用5折交叉验证评估SVM
svm = SVC(kernel='rbf', C=1.0, gamma='scale')
scores = cross_val_score(svm, X_train_scaled, y_train, cv=5, scoring='accuracy')
print(f"5折交叉验证分数: {scores}")
print(f"平均准确率: {np.mean(scores):.2f} (+/- {np.std(scores)*2:.2f})")
网格搜索调优
python
from sklearn.model_selection import GridSearchCV
# 定义参数网格
param_grid = {
'C': [0.1, 1, 10, 100],
'gamma': ['scale', 'auto', 0.001, 0.01, 0.1],
'kernel': ['linear', 'rbf', 'poly']
}
# 创建网格搜索对象
grid_search = GridSearchCV(SVC(), param_grid, cv=5, scoring='accuracy', n_jobs=-1)
# 执行搜索
grid_search.fit(X_train_scaled, y_train)
print(f"最佳参数: {grid_search.best_params_}")
print(f"最佳交叉验证准确率: {grid_search.best_score_:.2f}")
# 使用最佳模型
best_model = grid_search.best_estimator_
test_accuracy = best_model.score(X_test_scaled, y_test)
print(f"测试集准确率: {test_accuracy:.2f}")
学习曲线分析
python
from sklearn.model_selection import learning_curve
def plot_learning_curve(estimator, title, X, y, cv=5, n_jobs=-1):
train_sizes, train_scores, test_scores = learning_curve(
estimator, X, y, cv=cv, n_jobs=n_jobs,
train_sizes=np.linspace(0.1, 1.0, 10)
)
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)
plt.figure(figsize=(10, 6))
plt.title(title)
plt.xlabel("训练样本数")
plt.ylabel("分数")
plt.grid()
plt.fill_between(train_sizes, train_mean - train_std,
train_mean + train_std, alpha=0.1, color="r")
plt.fill_between(train_sizes, test_mean - test_std,
test_mean + test_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_mean, 'o-', color="r", label="训练分数")
plt.plot(train_sizes, test_mean, 'o-', color="g", label="交叉验证分数")
plt.legend(loc="best")
return plt
# 绘制学习曲线
plot_learning_curve(SVC(kernel='rbf'), 'SVM学习曲线', X_train_scaled, y_train)
plt.show()
实战案例:基于机器学习的注意力监测系统
系统架构
#mermaid-svg-nJBmre9Kd8IoqKFE{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nJBmre9Kd8IoqKFE .error-icon{fill:#552222;}#mermaid-svg-nJBmre9Kd8IoqKFE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nJBmre9Kd8IoqKFE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nJBmre9Kd8IoqKFE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nJBmre9Kd8IoqKFE .marker.cross{stroke:#333333;}#mermaid-svg-nJBmre9Kd8IoqKFE svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nJBmre9Kd8IoqKFE p{margin:0;}#mermaid-svg-nJBmre9Kd8IoqKFE .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE .cluster-label text{fill:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE .cluster-label span{color:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE .cluster-label span p{background-color:transparent;}#mermaid-svg-nJBmre9Kd8IoqKFE .label text,#mermaid-svg-nJBmre9Kd8IoqKFE span{fill:#333;color:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE .node rect,#mermaid-svg-nJBmre9Kd8IoqKFE .node circle,#mermaid-svg-nJBmre9Kd8IoqKFE .node ellipse,#mermaid-svg-nJBmre9Kd8IoqKFE .node polygon,#mermaid-svg-nJBmre9Kd8IoqKFE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nJBmre9Kd8IoqKFE .rough-node .label text,#mermaid-svg-nJBmre9Kd8IoqKFE .node .label text,#mermaid-svg-nJBmre9Kd8IoqKFE .image-shape .label,#mermaid-svg-nJBmre9Kd8IoqKFE .icon-shape .label{text-anchor:middle;}#mermaid-svg-nJBmre9Kd8IoqKFE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nJBmre9Kd8IoqKFE .rough-node .label,#mermaid-svg-nJBmre9Kd8IoqKFE .node .label,#mermaid-svg-nJBmre9Kd8IoqKFE .image-shape .label,#mermaid-svg-nJBmre9Kd8IoqKFE .icon-shape .label{text-align:center;}#mermaid-svg-nJBmre9Kd8IoqKFE .node.clickable{cursor:pointer;}#mermaid-svg-nJBmre9Kd8IoqKFE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nJBmre9Kd8IoqKFE .arrowheadPath{fill:#333333;}#mermaid-svg-nJBmre9Kd8IoqKFE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nJBmre9Kd8IoqKFE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nJBmre9Kd8IoqKFE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nJBmre9Kd8IoqKFE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nJBmre9Kd8IoqKFE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nJBmre9Kd8IoqKFE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nJBmre9Kd8IoqKFE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nJBmre9Kd8IoqKFE .cluster text{fill:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE .cluster span{color:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nJBmre9Kd8IoqKFE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nJBmre9Kd8IoqKFE rect.text{fill:none;stroke-width:0;}#mermaid-svg-nJBmre9Kd8IoqKFE .icon-shape,#mermaid-svg-nJBmre9Kd8IoqKFE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nJBmre9Kd8IoqKFE .icon-shape p,#mermaid-svg-nJBmre9Kd8IoqKFE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nJBmre9Kd8IoqKFE .icon-shape .label rect,#mermaid-svg-nJBmre9Kd8IoqKFE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nJBmre9Kd8IoqKFE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nJBmre9Kd8IoqKFE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nJBmre9Kd8IoqKFE :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} EEG采集设备
数据预处理
特征提取
特征选择
机器学习模型
注意力预测
反馈输出
可视化界面
历史数据存储
完整代码实现
python
import numpy as np
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
import joblib
class AttentionMonitor:
def __init__(self):
self.scaler = StandardScaler()
self.model = SVC(kernel='rbf', C=10, gamma='scale')
self.is_trained = False
def train(self, X, y):
"""训练模型"""
X_scaled = self.scaler.fit_transform(X)
self.model.fit(X_scaled, y)
self.is_trained = True
print("模型训练完成")
def predict(self, eeg_data):
"""预测注意力水平"""
if not self.is_trained:
raise Exception("模型尚未训练")
# 确保输入数据形状正确
if len(eeg_data.shape) == 1:
eeg_data = eeg_data.reshape(1, -1)
X_scaled = self.scaler.transform(eeg_data)
prediction = self.model.predict(X_scaled)
probability = self.model.predict_proba(X_scaled)
return prediction[0], probability[0]
def save_model(self, filepath):
"""保存模型"""
joblib.dump({'model': self.model, 'scaler': self.scaler}, filepath)
print(f"模型已保存到 {filepath}")
def load_model(self, filepath):
"""加载模型"""
data = joblib.load(filepath)
self.model = data['model']
self.scaler = data['scaler']
self.is_trained = True
print(f"模型已从 {filepath} 加载")
# 模拟训练数据
np.random.seed(42)
n_samples = 500
n_channels = 8
n_features = n_channels * 10 # 每个通道提取10个特征
# 低注意力数据
low_attention = np.random.normal(loc=4, scale=1.5, size=(n_samples//2, n_features))
# 高注意力数据
high_attention = np.random.normal(loc=7, scale=1.5, size=(n_samples//2, n_features))
X_train = np.vstack([low_attention, high_attention])
y_train = np.array([0]*(n_samples//2) + [1]*(n_samples//2))
# 创建并训练注意力监测器
monitor = AttentionMonitor()
monitor.train(X_train, y_train)
# 测试预测
test_data = np.random.normal(loc=6, scale=1.5, size=(1, n_features))
attention_level, prob = monitor.predict(test_data)
print(f"预测注意力水平: {'高' if attention_level == 1 else '低'}")
print(f"预测概率: 低注意力={prob[0]:.4f}, 高注意力={prob[1]:.4f}")
# 保存模型
monitor.save_model('attention_model.pkl')
常见问题与解决方案
问题1:数据不平衡
现象:某一类样本数量远多于另一类
解决方案:
- 过采样:增加少数类样本
- 欠采样:减少多数类样本
- 使用加权损失函数
python
from imblearn.over_sampling import SMOTE
# 使用SMOTE进行过采样
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)
print(f"重采样后类别分布: {np.bincount(y_resampled)}")
问题2:过拟合
现象:训练集表现很好,但测试集表现很差
解决方案:
- 增加训练数据
- 使用正则化
- 减少模型复杂度
- 使用交叉验证
python
# 使用带正则化的SVM
svm = SVC(kernel='rbf', C=0.1, gamma='scale') # 较小的C值表示更强的正则化
问题3:特征选择
现象:特征维度太高,计算量大且容易过拟合
解决方案:
- 使用特征重要性分析
- 使用PCA降维
- 使用互信息选择
python
from sklearn.decomposition import PCA
# 使用PCA降维到20个特征
pca = PCA(n_components=20)
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = pca.transform(X_test_scaled)
print(f"降维后特征数: {X_train_pca.shape[1]}")
总结与展望
本章重点
- 机器学习流程:数据采集→预处理→特征提取→模型训练→评估→部署
- 常用算法:LDA、SVM、随机森林、k-NN、朴素贝叶斯
- 评估指标:准确率、精确率、召回率、F1分数
- 调优方法:交叉验证、网格搜索、学习曲线
下一步学习计划
下一章我们将进入实战环节,学习如何使用脑电信号控制LED灯,这是一个非常有趣的入门项目!
思考与练习
- 思考:为什么在BCI中SVM比神经网络更常用?
- 练习:使用真实的EEG数据集(如BCI Competition数据集)进行分类实验
- 练习:尝试不同的特征组合和模型参数,比较它们的性能差异
系列文章导航:
- 第1篇:什么是脑机接口(BCI)?OpenBCI入门指南
- 第2篇:OpenBCI硬件选型:Cyton vs Ganglion对比分析
- 第3篇:搭建你的第一个脑电采集系统
- 第4篇:OpenBCI GUI使用指南:从安装到数据采集
- 第5篇:脑电信号基础:EEG波形解读与频段分析
- 第6篇:BrainFlow SDK完全指南:统一API实现多设备兼容
- 第7篇:Python与OpenBCI:实时脑电信号采集实战
- 第8篇:信号预处理:滤波、去噪与伪迹去除
- 第9篇:特征提取技术:频域分析与时频分析
- 第10篇:机器学习入门:从脑电信号到模式识别(当前)
- 第11篇:实战一:脑波控制LED灯(基础)
声明:本文仅供学习交流,文中涉及的硬件设备和软件工具请从官方渠道获取。脑机接口技术涉及生物医学领域,实际应用请遵循相关法律法规和伦理规范。
