简介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, preloadFalse, verboseFalse) print(通道数:, len(raw.ch_names)) print(采样率:, raw.info[sfreq]) print(时长(秒):, raw.n_times / raw.info[sfreq]) print(通道名:, raw.ch_names[:10])逻辑说明preloadFalse 避免一次性把长记录全部读进内存适合先探查。参数说明read_raw_edf 的 verboseFalse 减少输出干扰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, preloadTrue, verboseFalse) 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 用于记录缺失情况。参数说明preloadTrue 在切窗阶段需要真正加载数据如果缺失通道超过两个建议直接跳过该受试者否则模型学到的空间模式不可靠。3. 从EDF到训练样本切窗、标注对齐与标签生成3.1 发作标注怎么读、怎么对齐到样本CHB-MIT 的标注文件通常每行描述一段记录包含发作开始秒数和结束秒数。常见格式是 “发作开始 发作结束” 两个数字也可能带通道名。读取后要做的第一件事是把秒数乘以采样率得到样本点索引再和 EDF 的总长度比较。如果结束秒数超过记录时长说明标注和 EDF 不匹配必须排查是不是拿错了受试者目录。import numpy as np def parse_seizure_annotation(txt_path): seizures [] with open(txt_path, r, encodingutf-8, errorsignore) 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_sec2, step_sec1): 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_sec300, ignore_sec60): y np.zeros(total_len, dtypeint) mask np.ones(total_len, dtypebool) 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先跑一遍通道检查和标注对齐再切窗最后按受试者划分。任何一步跳过后面都要花更多时间返工。希望帮到你。本文还有配套的精品资源点击获取
