☰
CHB-MIT数据集.rar处理全流程:从EDF读取到癫痫发作检测样本生成
2026/9/26 16:52:14 网站建设 项目流程

简介:CHB-MIT数据集是麻省理工学院与波士顿儿童医院联合发布的癫痫脑电研究资源,面向生物医学信号处理、机器学习与模式识别方向的研究者及学生,用于癫痫发作检测、分类与长期监测等课题。压缩包共145个文件,以141个.m脚本和4个.py文件为主,整体约159KB,其中MATLAB脚本多用于样本熵等特征计算,Python文件便于接入深度学习流程。已有827人学习下载,说明其在相关社区中具备一定参考热度。数据集涵盖23名受试者的多通道脑电记录,采用10-20国际系统标准采集19通道信号,并附有发作类型与起止时间戳等临床信息,可支撑复杂部分性、简单部分性及二次全面性发作的算法验证。借助这些脚本与数据,读者能够快速复现特征提取流程、搭建检测模型,并拓展至睡眠与认知功能等脑电研究场景。

1. CHB-MIT数据集.rar:从压缩包到可训练EEG样本的完整路径

如果你从公开渠道拿到一个名为 CHB-MIT数据集.rar 的压缩包,第一反应可能是先解压看看里面有什么。但真正做过癫痫脑电检测的人会告诉你,这个压缩包的价值不在于“有多少文件”,而在于它背后是一套被反复引用的长程头皮脑电(EEG)记录,包含多例儿科难治性癫痫患者的连续多导联信号。它常被用来做发作检测、发作预测、通道选择、伪迹抑制等任务。问题在于,原始数据是欧洲数据格式(EDF),采样率、通道命名、标注文件、发作起止时间都不统一,直接喂给模型会翻车。这篇笔记按我实际处理 CHB-MIT数据集.rar 的顺序,讲清怎么解压、怎么读 EDF、怎么对齐标注、怎么切窗、怎么避坑,最后给一个可复现的验证习惯。适合刚拿到数据的新手,也适合想核对参数的老手。

2. 解压后先别急着读:CHB-MIT的目录结构与EDF命名规则

2.1 压缩包解开后到底有什么

CHB-MIT数据集.rar 解压后通常得到一组以 chb01、chb02 等命名的子目录,每个子目录对应一名受试者。每个受试者目录下是若干 .edf 文件,命名类似 chb01_01.edf、chb01_02.edf,编号越大表示记录时间越靠后。此外还会有一个 summary 文件或若干 .txt 标注,记录每段记录的通道数、采样率、发作起止秒数。常见做法是先把所有 EDF 路径和对应标注读成一张表,再决定切窗策略。不要一上来就遍历所有文件做傅里叶变换,那样既慢又容易把坏段算进去。

我一般会先做三件事:确认受试者数量、确认每个 EDF 的通道列表、确认标注文件里发作段的时间单位是秒还是样本点。CHB-MIT 的标注通常以秒为单位,但不同整理版本可能混用,必须逐条核对。下面这段 Python 用 mne 读取一个 EDF 并打印基本信息,适合作为第一道检查。

import mne import os edf_path = "chb01/chb01_01.edf" raw = mne.io.read_raw_edf(edf_path, preload=False, verbose=False) print("通道数:", len(raw.ch_names)) print("采样率:", raw.info["sfreq"]) print("时长(秒):", raw.n_times / raw.info["sfreq"]) print("通道名:", raw.ch_names[:10])

逻辑说明:preload=False 避免一次性把长记录全部读进内存,适合先探查。参数说明:read_raw_edf 的 verbose=False 减少输出干扰;raw.n_times 是总采样点数,除以采样率得到秒数。如果通道名里出现 “-” 或 “.” 等符号,后续做通道选择时要先做名称规范化,否则按名字取通道会报错。

2.2 通道命名不统一时怎么对齐

CHB-MIT 常见通道包括 FP1-F7、F7-T7、T7-P7、P7-O1 等双极导联,不同受试者可能缺通道或顺序不同。做跨受试者训练时,不能假设所有 EDF 的通道顺序一致。我一般会定义一个目标通道列表,然后对每个 EDF 做重排和缺失检查。缺失通道要么丢弃该受试者,要么用零填充并加掩码,但零填充会引入伪迹,新手慎用。

target_chs = ["FP1-F7", "F7-T7", "T7-P7", "P7-O1", "FP1-F3", "F3-C3", "C3-P3", "P3-O1"] raw = mne.io.read_raw_edf(edf_path, preload=True, verbose=False) raw.pick_channels([ch for ch in target_chs if ch in raw.ch_names]) missing = [ch for ch in target_chs if ch not in raw.ch_names] print("缺失通道:", missing)

逻辑说明:pick_channels 只保留存在的目标通道,missing 用于记录缺失情况。参数说明:preload=True 在切窗阶段需要真正加载数据;如果缺失通道超过两个,建议直接跳过该受试者,否则模型学到的空间模式不可靠。

3. 从EDF到训练样本:切窗、标注对齐与标签生成

3.1 发作标注怎么读、怎么对齐到样本

CHB-MIT 的标注文件通常每行描述一段记录,包含发作开始秒数和结束秒数。常见格式是 “发作开始 发作结束” 两个数字,也可能带通道名。读取后要做的第一件事是:把秒数乘以采样率,得到样本点索引,再和 EDF 的总长度比较。如果结束秒数超过记录时长,说明标注和 EDF 不匹配,必须排查是不是拿错了受试者目录。

import numpy as np def parse_seizure_annotation(txt_path): seizures = [] with open(txt_path, "r", encoding="utf-8", errors="ignore") as f: for line in f: parts = line.strip().split() if len(parts) >= 2: try: start, end = float(parts[0]), float(parts[1]) seizures.append((start, end)) except ValueError: continue return seizures seizures = parse_seizure_annotation("chb01/chb01_01.txt") sfreq = raw.info["sfreq"] seizure_samples = [(int(s * sfreq), int(e * sfreq)) for s, e in seizures] print("发作段数:", len(seizure_samples))

逻辑说明:逐行解析,跳过无法转成浮点的行,避免表头或空行导致崩溃。参数说明:start 和 end 单位是秒;乘以 sfreq 后取整得到样本索引。如果标注文件里出现 “Seizure” 字样,说明格式不同,需要单独写解析分支。

3.2 切窗长度与重叠率怎么选

做发作检测时,常用窗长是 1 秒、2 秒或 4 秒,重叠率 0 到 50%。窗太长会模糊发作起始,窗太短则频域分辨率不够。我一般先用 2 秒窗、50% 重叠做基线,再根据验证集表现调整。切窗时要保证每个窗要么完全在发作内,要么完全在发作外,跨边界的窗容易引入标签噪声。下面这段代码按 2 秒窗、1 秒步长切窗并生成二分类标签。

def make_windows(raw_data, sfreq, seizure_samples, win_sec=2, step_sec=1): win_len = int(win_sec * sfreq) step_len = int(step_sec * sfreq) X, y = [], [] for start in range(0, raw_data.shape[1] - win_len, step_len): end = start + win_len label = 0 for s, e in seizure_samples: if start < e and end > s: label = 1 break X.append(raw_data[:, start:end]) y.append(label) return np.array(X), np.array(y) data = raw.get_data() X, y = make_windows(data, sfreq, seizure_samples) print("样本形状:", X.shape, "正样本比例:", y.mean())

逻辑说明:遍历所有起始点,判断窗与任一发作段是否有交集,有则标 1。参数说明:win_sec 和 step_sec 控制窗长和步长;raw_data 形状是通道乘样本点。正样本比例通常很低,如果低于 1%,需要做重采样或类别加权,否则模型会偏向全预测为 0。

3.3 训练集、验证集、测试集怎么分才不泄漏

CHB-MIT 的受试者之间差异大,随机切分会让同一受试者的相邻窗同时出现在训练和测试里,导致指标虚高。常见做法是按受试者划分:用 chb01 到 chb15 做训练,chb16 到 chb23 做测试。如果受试者数量少,至少按记录文件划分,不要把同一文件的窗拆到两边。我见过有人随机打乱后准确率 99%,换受试者后掉到 70%,这就是泄漏的血泪经验。

def split_by_subject(X, y, subject_ids, train_subjects): train_mask = np.isin(subject_ids, train_subjects) return X[train_mask], y[train_mask], X[~train_mask], y[~train_mask]

逻辑说明:subject_ids 是每个窗对应的受试者编号,train_subjects 是训练受试者列表。参数说明:np.isin 做集合判断,返回布尔掩码。这样划分能真实反映跨受试者泛化能力。

4. 避坑与排查:CHB-MIT处理中最容易翻车的5个点

4.1 现象:读取EDF时报通道数不一致

原因:不同受试者的 EDF 通道数不同,有的 23 通道,有的 18 通道,代码里写死了通道数。解决:先读一个文件打印 ch_names,再动态取交集或按目标列表选择,不要硬编码索引。

4.2 现象:标注时间对不上,发作段落在记录之外

原因:标注文件可能对应的是同一受试者的另一段记录,或者秒数单位被误当成毫秒。解决:逐条打印发作起止和记录时长,超过时长的直接丢弃并记录日志,不要强行截断。

4.3 现象:正负样本极度不平衡,模型全预测为负

原因:发作通常只占记录的一小部分,2 秒窗下正样本可能不到 1%。解决:用加权损失、重采样或先做发作预测(提前若干秒)而不是逐窗检测。我一般会先算一下正样本比例,再决定是否用 focal loss。

4.4 现象:频域特征计算后出现 NaN

原因:某些通道在某段时间内是常数或全零,做对数功率时出现 log(0)。解决:加一个极小值 eps,或者先做通道质量检查,把方差过小的通道剔除。

4.5 现象:训练集准确率高但测试集崩溃

原因:按窗随机划分导致同一受试者泄漏。解决:按受试者或按记录文件划分,确保训练和测试没有重叠受试者。这个坑几乎每个新手都会踩一次。

5. 进阶技巧:用发作预测任务验证CHB-MIT方案是否真的可用

如果你已经把发作检测跑通,下一步建议做发作预测:在发作开始前 5 到 30 分钟给出预警。这个任务更接近临床需求,也更能暴露特征和模型的真实上限。具体做法是:把发作前一段时间的窗标为正,发作间期标为负,发作中和发作后一段设为忽略区。忽略区不参与损失计算,避免模型学到发作后抑制这种无关模式。

def make_prediction_labels(seizure_samples, sfreq, total_len, pre_sec=300, ignore_sec=60): y = np.zeros(total_len, dtype=int) mask = np.ones(total_len, dtype=bool) for s, e in seizure_samples: pre_start = max(0, int((s - pre_sec) * sfreq)) pre_end = int(s * sfreq) y[pre_start:pre_end] = 1 ignore_start = max(0, int((s - ignore_sec) * sfreq)) ignore_end = min(total_len, int((e + ignore_sec) * sfreq)) mask[ignore_start:ignore_end] = False return y, mask

逻辑说明:pre_sec 控制发作前正样本时长,ignore_sec 控制发作前后忽略区。参数说明:mask 为 False 的样本在训练时权重设为零。验证时用 AUC 和敏感度在固定误报率下评估,不要只看准确率。

我自己的习惯是:每次拿到新的 CHB-MIT数据集.rar,先跑一遍通道检查和标注对齐,再切窗,最后按受试者划分。任何一步跳过,后面都要花更多时间返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询