1. 静息态EEG微状态分析到底在做什么
静息态脑电微状态分析,说白了就是把一段连续记录的自发脑电,切成一个个几十到上百毫秒的“稳定地形图片段”,再把这些片段归纳成几个反复出现的经典模板。它回答的问题很朴素:人在闭眼放松、什么都不做的时候,大脑的电场地形是不是在几个固定状态之间来回跳?每个状态停留多久、出现多频繁、切换多快?这些指标后来被大量用于研究注意、意识状态、精神疾病等方向。
我最早接触微状态是在做一组静息态数据时,当时用别的工具跑出来结果总是不稳定,后来换成Cartool做组水平聚类,才把流程理顺。Cartool是日内瓦那边开发的一款免费工具,专门做EEG微状态和地形图分析,它的强项在于全局场强(GFP)峰值提取、层次聚类和模板匹配这一整套链路都内置了,不用自己从零写代码。但它也有个特点:界面偏老派,参数藏得深,新手第一次打开很容易懵。
这篇文章面向的是已经能完成基本EEG预处理(滤波、去伪迹、坏导插值、重参考)的读者,我会把从GFP峰值提取、组水平聚类、聚类数选择,到模板匹配、结果导出这一整条路走一遍。重点讲清楚每一步为什么这么做、参数怎么定、哪里容易翻车。你不需要会写代码,但需要理解聚类的基本逻辑,否则选K值的时候只能瞎猜。
提示:微状态分析对预处理质量极其敏感。如果原始数据里还有明显的眼动、肌电、坏导,聚类出来的模板会非常脏,后面所有指标都不可信。这一步没有捷径。
2. 分析前的数据准备与Cartool工程搭建
2.1 输入数据的格式与预处理底线
Cartool原生支持的是.dat/.ep这类自有格式,但实际工作中我们的数据多半来自其他采集系统。常见做法是先把预处理好的数据导出为ASCII文本或EDF,再导入Cartool。我一般推荐导出为文本格式,因为Cartool对文本的容错性更好,导进去之后可以立刻在2D/3D地形图上检查通道位置对不对。
预处理底线我列几条硬指标,达不到就别急着做微状态:
- 采样率统一到250Hz到500Hz之间。太高没必要,微状态的时间尺度在毫秒级,250Hz足够;太低会丢失地形细节。
- 带通滤波建议1Hz到40Hz(或0.5Hz到45Hz),目的是去掉慢漂移和高频肌电。
- 重参考用平均参考或CZ参考都行,但整组数据必须统一,不能一半平均参考一半别的。
- 坏导必须插值,且插值后要在Cartool里目视确认地形图没有明显畸变。
- 眼动伪迹用ICA或回归去掉后,记得回看一遍,确认没有把前额的真实活动一起削掉。
通道数量方面,微状态分析对通道数没有硬性下限,但64导以上做出来的地形图会明显更平滑、更稳定。如果是32导甚至更少,也能做,只是模板的空间分辨率会粗一些,解释时要谨慎。
2.2 在Cartool里建立组水平工程
Cartool做组水平分析的核心思路是:先把每个被试的数据单独读进来,提取各自的GFP峰值地形图,再把这些地形图汇总成一个大的“地形图池”,对这个池子做聚类。所以工程搭建的关键是统一坐标和通道顺序。
具体操作顺序我习惯这样:
- 打开Cartool,新建一个workspace,把所有被试的预处理文件拖进去。
- 逐个检查每个文件的通道标签和坐标。如果不同被试的通道顺序不一致,聚类会直接崩掉。Cartool里可以用
Tools > Electrodes查看和编辑坐标。 - 确认所有文件的采样率、时长、参考方式一致。
- 对每个被试单独跑一次GFP计算,先看看GFP曲线是否正常——正常的静息态GFP应该有明显的峰谷交替,如果曲线很平或者全是尖刺,说明预处理有问题。
这里有个容易忽略的点:被试之间的数据时长最好接近。如果一个人记录5分钟、另一个人记录20分钟,长的那位会在聚类池里占更大权重,导致模板偏向他的数据。常见做法是每个被试截取相同长度的干净片段,比如都取2分钟。
注意:Cartool的工程文件不会自动帮你对齐通道,通道顺序错了它不会报错,只会默默给你一个错误结果。这一步一定要人工核对。
3. GFP峰值提取:微状态分析的起点
3.1 为什么是GFP而不是原始波形
全局场强GFP,是把某一时刻所有电极的电压值做空间标准差得到的。它衡量的是“这一刻整个头皮电场的强度有多强”。GFP的局部极大值,代表电场地形最清晰、最稳定的时刻。微状态分析就建立在这个假设上:在GFP峰值附近,地形图是稳定的,可以代表一个微状态。
用GFP而不是原始波形,好处是它跟参考电极无关(因为标准差对整体偏移不敏感),而且能自动把那些地形模糊、处于过渡态的时间点排除掉。这也是为什么微状态模板通常看起来都很“干净”——它们是从最清晰的地形里挑出来的。
3.2 在Cartool里提取GFP峰值地形图
操作路径大致是Tools > GFP > Extract peaks。关键参数有两个:
- GFP峰值的最小间隔:默认可能给的是几十毫秒。这个参数决定两个峰之间至少隔多久才算独立。设太小会把噪声当峰,设太大又会漏掉真实状态。我的经验是设在10ms到20ms之间比较稳,具体看采样率。
- 是否只保留局部极大值:一定要勾选,否则会把上升沿上的点也当峰。
提取完成后,Cartool会生成一个包含所有峰值地形图的文件。这时候你可以先做个快速检查:把所有峰值地形图按时间顺序浏览一遍,看看有没有明显异常的(比如某个通道爆掉、地形图半边黑半边白)。异常的峰值地形图要手动剔除,否则会污染聚类池。
3.3 峰值数量与后续聚类的规模
峰值数量直接决定聚类池的大小。一个被试2分钟的静息态数据,通常能提取出几百到上千个峰值地形图。如果一组有20个被试,聚类池可能就有上万个地形图。这个规模对Cartool的层次聚类来说是可以接受的,但计算时间会比较长。
如果峰值数量异常少(比如一个被试只有几十个),通常说明GFP曲线太平,可能是滤波太狠或者数据本身质量差。这时候要回头查预处理,而不是硬着头皮往下做。
4. 组水平聚类:K值怎么选、层次聚类怎么跑
4.1 层次聚类的基本逻辑
Cartool默认用的是层次聚类,具体是凝聚式(agglomerative):一开始每个地形图自成一类,然后不断把最相似的两类合并,直到只剩一类。相似度用空间相关性或欧氏距离衡量。整个过程会生成一棵树(树状图),你在这棵树上切一刀,就得到K个聚类。
这里要澄清一个常见误解:微状态分析里的“聚类”不是K-means那种需要预先指定K并迭代的算法,而是层次聚类。K-means在微状态里也有应用,但Cartool的主流程是层次聚类。热词里出现的“kmeans聚类算法用什么软件”“k值聚类”其实反映了很多人的困惑——K值到底怎么定。
4.2 K值选择的几种主流做法
K值就是最终保留几个微状态模板。文献里最常见的答案是4个(经典的四模板:A、B、C、D),但这绝不是唯一正确答案。我实际用下来,K值选择有几种思路:
| 方法 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 文献惯例 | 直接取4 | 可比性好,省事 | 可能不符合你的数据 |
| 解释方差 | 看不同K下的交叉验证解释方差 | 有量化依据 | 曲线常常没有明显拐点 |
| 轮廓系数 | 计算聚类紧致度和分离度 | 客观 | 计算量大,Cartool不直接给 |
| 目视+先验 | 结合地形图可解释性 | 灵活 | 主观性强 |
我个人的做法是:先跑K=2到K=8,把每个K下的模板地形图都导出来看。如果K=4和K=5的模板几乎一样,那就取4;如果K=5多出来的那个模板有明确的生理意义(比如某个特定区域的活动),可以考虑取5。关键是不要为了凑4而强行取4。
4.3 在Cartool里执行组水平聚类
操作路径是Tools > Microstates > Group clustering。把之前提取的所有峰值地形图文件加载进来,选择聚类方法(通常选TAAHC,即Topographic Atomize and Agglomerate Hierarchical Clustering,这是Cartool推荐的变体,比传统层次聚类更稳定),然后设定K值范围。
跑完之后,Cartool会给出每个K值下的模板地形图、每个模板的解释方差、以及每个被试的模板匹配结果。这时候要重点看两样东西:
- 模板地形图是否可解释:有没有哪个模板看起来像噪声、或者跟另一个模板高度相似。
- 解释方差是否够高:一般K=4时能解释70%以上的方差算不错,如果只有50%多,说明K可能不够或者数据太乱。
提示:TAAHC比传统层次聚类慢,但结果更稳定,尤其是组水平数据。如果时间允许,优先用它。
4.4 聚类结果的稳定性检查
组水平聚类最怕的是“换个被试组合,模板就变了”。检查稳定性的一个土办法是留一法:每次去掉一个被试,重新聚类,看模板地形图是否基本一致。如果去掉某个被试后模板大变,说明这个被试的数据在主导聚类,要么他的数据有问题,要么样本量太小。
另一个办法是分半信度:把被试随机分成两半,各自聚类,然后比较两组的模板相关性。相关性高说明结果稳。这个操作在Cartool里要手动做两次,稍微麻烦,但对于要发文章的结果,值得花这个时间。
5. 模板匹配:把模板套回每个被试的时间序列
5.1 模板匹配在做什么
聚类得到的是“组水平模板”,但每个被试的每一时刻到底属于哪个微状态,需要靠模板匹配来判定。匹配的逻辑是:对每个时间点,计算它的地形图与每个模板的空间相关性,相关性最高的那个模板就是该时刻的标签。这样每个被试就得到一条微状态时间序列。
这一步在Cartool里是Tools > Microstates > Fitting。把组水平模板文件和每个被试的原始数据加载进去,选择匹配方法(通常用空间相关性),跑完就能得到每个被试的标签序列。
5.2 匹配时的几个关键参数
- 是否允许一个时间点匹配多个模板:一般不允许,取最高相关即可。
- 是否设置相关性阈值:有些流程会设一个最低相关性,低于阈值的点标为“未匹配”。我一般不设阈值,因为静息态里本来就有过渡态,强行剔除会丢失信息。
- 是否平滑标签序列:Cartool有个选项可以对标签序列做时间平滑,减少频繁跳变。这个要谨慎,平滑太狠会把真实的快速切换抹掉。我通常不平滑,或者只做很小的平滑窗口。
5.3 从标签序列到微状态指标
匹配完成后,每个被试的标签序列可以算出几个核心指标:
- 持续时间(Duration):每个微状态每次出现的平均时长,单位毫秒。
- 出现频率(Occurrence):每秒出现多少次。
- 覆盖率(Coverage):该微状态占总时间的比例。
- 转换概率(Transition probability):从一个微状态切换到另一个的概率矩阵。
这些指标在Cartool里可以直接导出,也可以导出标签序列后用别的工具算。我习惯导出标签序列,因为后面做统计的时候更灵活。
6. 常见问题与排查技巧实录
6.1 聚类模板看起来像噪声怎么办
这是新手最常遇到的问题。模板地形图如果看起来杂乱、没有明显的正负区域,通常是这几个原因:
- 预处理没做干净:肌电、眼动残留会直接污染地形图。回去查原始数据。
- 峰值提取参数太松:把太多过渡态地形图也提进来了。把最小间隔调大一点。
- 通道坐标不对:地形图插值依赖坐标,坐标错了地形图就乱了。检查电极坐标。
- 被试太少:组水平聚类需要一定样本量,5个被试以下做出来的模板往往不稳。
6.2 K值到底选几个才“对”
这个问题没有标准答案,但有几个判断原则:
- 如果K=4和K=5的模板高度相似,选4。
- 如果某个K下出现一个只占很小比例的模板(比如覆盖率不到5%),考虑减K。
- 如果解释方差在某个K之后提升很小,说明再加K意义不大。
- 最终要结合你的研究问题和文献可比性来定。
6.3 匹配结果里某个微状态几乎不出现
如果匹配后发现某个模板的覆盖率极低(比如1%),可能是:
- 这个模板本身就是聚类时产生的“边角料”,可以考虑减K。
- 匹配方法或参数有问题,导致这个模板总是匹配不上。
- 数据本身确实缺少这个状态,这在某些临床群体里是真实存在的现象。
6.4 不同被试的指标差异很大
静息态微状态指标本身个体差异就大,但如果某个被试的指标明显偏离,先查他的数据质量,再查他的匹配标签序列有没有异常跳变。有时候一个被试的坏导没处理好,会导致他的地形图整体偏移,匹配结果全乱。
6.5 常见问题速查表
| 问题 | 可能原因 | 排查方向 |
|---|---|---|
| 模板像噪声 | 预处理差、峰值太松、坐标错 | 查原始数据、调峰值参数、核对坐标 |
| K值难定 | 数据本身模糊 | 跑多个K对比、看解释方差 |
| 某模板覆盖率极低 | 边角料模板或匹配问题 | 减K、检查匹配参数 |
| 被试间差异大 | 个体差异或数据质量 | 查坏导、查标签序列 |
| 聚类结果不稳 | 样本量小或被试主导 | 留一法、分半信度 |
提示:微状态分析里,预处理和峰值提取的质量决定了上限,聚类和匹配只是在下限里做文章。花在预处理上的时间永远不亏。
7. 结果导出与后续统计的衔接
Cartool能直接导出每个被试的微状态指标表格,格式是文本,可以直接拖进SPSS或R做统计。我一般会导出这几样:
- 每个被试的模板匹配标签序列(用于自定义分析)。
- 每个被试的四个核心指标(持续时间、频率、覆盖率、转换概率)。
- 组水平模板地形图(用于画图)。
导出标签序列后,如果要做组间比较,通常用混合线性模型或重复测量方差分析,把微状态类型作为被试内因素。转换概率矩阵则常用卡方检验或置换检验来比较组间差异。
如果后续想用Python做更灵活的分析,可以把标签序列读进numpy,自己算指标。热词里提到的“层次聚类python”其实也可以用scipy.cluster.hierarchy复现Cartool的聚类逻辑,但要注意Cartool的TAAHC有自己的细节,直接复现不一定完全一致。
8. 我踩过的几个坑和一点个人体会
第一个坑是通道顺序。有次偷懒没核对,结果两个被试的通道顺序反了,聚类出来的模板怎么看怎么别扭,查了一整天才发现。从那以后我每次都在Cartool里逐个核对通道标签。
第二个坑是K值执念。刚开始总想着凑4个模板,结果有个数据集明明K=5更合理,硬取4导致两个模板被强行合并,解释方差掉了一大截。后来想通了,K值是服务于数据的,不是数据服务于K值。
第三个坑是忽略过渡态。早期我会设相关性阈值把低相关的点剔除,后来发现静息态里过渡态占比不小,剔掉之后指标全偏了。现在我不设阈值,保留完整序列。
一点个人体会:微状态分析看起来流程固定,但每一步都有很多小决策,这些决策累积起来会显著影响结果。Cartool把这些决策都暴露给你,好处是透明,坏处是容易选错。我的建议是,每做一个关键决策,都记下来为什么这么选,这样后面写方法部分或者复现的时候不会抓瞎。
最后分享一个小技巧:如果组水平聚类跑得慢,可以先把每个被试的峰值地形图数量控制在一个合理范围(比如每个被试随机抽200个),先跑一遍看模板大致长什么样,确认方向对了再跑全量。这样能省不少等待时间。