- 데이터셋명: CHB-MIT Scalp EEG Database
- 출처: Children's Hospital Boston (CHB) / MIT
- 목적: 소아 발작(Seizure) 감지
- 대상: 소아 간질 환자
- 데이터 타입: 두피 뇌파(Scalp EEG)
- 전체 환자 수: 21명
- 환자 번호: chb01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24
- 제외된 번호: chb12, chb13, chb17 (데이터 없음)
- 모든 환자: 발작 환자 (간질 진단)
/data/datasets/chb-mit-scalp-eeg-database-1.0.0/
├── chb01/
│ ├── chb01-summary.txt # 메타데이터 (발작 시간 등)
│ ├── chb01_01.edf # EDF 파일 (recording 1)
│ ├── chb01_02.edf
│ └── ...
├── chb02/
└── ...
각 환자별 chb{XX}-summary.txt 파일 포함:
File Name: chb01_01.edf
Number of Seizures: 0
File Name: chb01_03.edf
Number of Seizures: 1
Seizure Start Time: 2996 seconds
Seizure End Time: 3036 seconds
- 시스템: 10-20 International System
- Montage 타입: Bipolar (Longitudinal Bipolar / Double Banana)
- 채널 수: 16개 (고정)
channels = [
# 좌측 Lateral Chain
"FP1-F7", "F7-T7", "T7-P7", "P7-O1",
# 우측 Lateral Chain
"FP2-F8", "F8-T8", "T8-P8", "P8-O2",
# 좌측 Parasagittal Chain
"FP1-F3", "F3-C3", "C3-P3", "P3-O1",
# 우측 Parasagittal Chain
"FP2-F4", "F4-C4", "C4-P4", "P4-O2"
]- Frontal Pole: FP1, FP2
- Frontal: F3, F4, F7, F8
- Central: C3, C4
- Temporal: T7, T8 (구 T3, T4)
- Parietal: P3, P4, P7, P8 (P7, P8는 구 T5, T6)
- Occipital: O1, O2
- Sampling Rate: 256 Hz
- 파일 형식: EDF (European Data Format)
- Recording 길이: 환자/파일마다 다름 (보통 1시간)
- 데이터 타입: Float (uV 단위)
전처리는 2단계로 나뉨:
Stage 1 (process1.py): EDF → PKL (정제)
↓
Stage 2 (process2.py): PKL → Segments (세그먼트화 + 라벨링)
- EDF 파일에서 유효한 채널만 추출
- 메타데이터(발작 시간) 파싱
- 환자별로 정제된 데이터 저장
-
Summary 파일 파싱 (
process_metadata())chb{p}-summary.txt읽기- 발작 횟수, 시작/종료 시간 추출
- 시간(초) → 샘플 인덱스 변환:
time * 256 - 1
-
채널 선택 (
drop_channels())- Summary 파일에서 유효 채널 목록 확인
- EDF에서 해당 채널만 추출
- 누락된 채널은 zero-padding
-
저장 (
compressed_pickle())- 출력 경로:
/data/datasets/BigDownstream/chb-mit/processed/ - 형식:
.pkl(pickle) - 구조:
{ 'FP1-F7': np.array([...]), # shape: (N,) where N = total samples 'F7-T7': np.array([...]), ... 'metadata': { 'seizures': int, # 발작 횟수 'times': [(start, end), ...], # 발작 시간 (샘플 인덱스) 'channels': [...] # 유효 채널 목록 } }
- 출력 경로:
parameters = [
(patient, reference_file, start_file, end_file, summary_idx),
...
]
with mp.Pool(mp.cpu_count()) as pool:
pool.starmap(start_process, parameters)- 느린 EDF 파싱을 한 번만: EDF 읽기는 시간이 오래 걸림
- 채널 정렬: 환자마다 다른 채널 순서/이름 통일
- 메타데이터 파싱: Summary 파일의 복잡한 형식 한 번만 처리
- 재사용성: 다양한 세그먼트 실험에 재사용 가능
- 연속 신호를 10초 세그먼트로 분할
- 발작 여부에 따라 라벨링
- Train/Validation/Test 분할
- 클래스 불균형 해소 (오버샘플링)
test_pats = ["chb23", "chb24"] # 2명
val_pats = ["chb21", "chb22"] # 2명
train_pats = ["chb01" ~ "chb20"] # 17명 (12, 13, 17 제외)| Split | 환자 수 | 환자 번호 |
|---|---|---|
| Train | 17명 | chb01-20 (12, 13, 17 제외) |
| Validation | 2명 | chb21, chb22 |
| Test | 2명 | chb23, chb24 |
1) 기본 세그먼트 (모든 신호)
SAMPLING_RATE = 256
SEGMENT_LENGTH = 10 # 초
for i in range(0, signal.shape[1], SAMPLING_RATE * 10): # 10초 step
segment = signal[:, i : i + 10 * SAMPLING_RATE] # (16, 2560)
# 발작 포함 여부 확인
label = 0
for seizure_start, seizure_end in seizure_times:
if i < seizure_start < i + 10*256 or i < seizure_end < i + 10*256:
label = 1
break
# 저장
save({"X": segment, "y": label}, f"{filename}-{i}.pkl")2) 추가 발작 샘플 (오버샘플링)
# 발작 구간만 5초 step으로 추가 샘플링
for idx, (seizure_start, seizure_end) in enumerate(seizure_times):
# 발작 ±1초 범위
start = max(0, seizure_start - SAMPLING_RATE)
end = min(seizure_end + SAMPLING_RATE, signal.shape[1])
# 5초 step
for i in range(start, end, 5 * SAMPLING_RATE):
segment = signal[:, i : i + 10 * SAMPLING_RATE]
label = 1
# 파일명에 's-add' 표시로 구분
save({"X": segment, "y": label}, f"{filename}-s-{idx}-add-{i}.pkl")- 경로:
/data/datasets/BigDownstream/chb-mit/processed_seg/{train,val,test}/ - 형식:
.pkl - 구조:
{"X": np.array (16, 2560), "y": int (0 or 1)} - 파일명:
- 기본:
chb01_01.edf-0.pkl,chb01_01.edf-2560.pkl - 추가:
chb01_01.edf-s-0-add-25344.pkl
- 기본:
- Label 0: 정상 (발작 없음)
- Label 1: 발작 있음
10초 세그먼트 내에 발작 시작 또는 종료 시점이 포함되면 label = 1
예시:
시간: [0초 -------- 100초(발작) --- 110초 -------- 200초]
세그먼트: [90-100] [100-110] [110-120]
라벨: 0 1 0
전형적인 1시간 recording:
- 총 시간: 3600초
- 발작 구간: ~40초 (1%)
- 정상 구간: ~3560초 (99%)
기본 10초 세그먼트만 사용 시:
- Label 0: 356개
- Label 1: 4개 ← 너무 적음!
- 불균형 비율: 89:1
전략:
- 정상 구간: 10초 step (sparse sampling)
- 발작 구간: 5초 step (dense sampling) ← 2배 증가
효과:
기본 세그먼트:
- Label 0: 356개
- Label 1: 4개
오버샘플링 후:
- Label 0: 356개 (동일)
- Label 1: 4 + 8 = 12개 ← 3배 증가
- 불균형 비율: 89:1 → 30:1 (개선)
시각적 예시:
발작 구간: 100-110초
기본 세그먼트 (10초 step):
├─ [100-110초]: label=1
└─ 1개
추가 발작 샘플 (5초 step, 99-111초 범위):
├─ [99-109초]: label=1 ← 추가
├─ [104-114초]: label=1 ← 추가
└─ 3개 (총 3배)
각 Split별로:
- ✅ Label 0과 1이 모두 섞여 있음
- ✅ Train/Val/Test 모두 발작 환자 포함
⚠️ 여전히 클래스 불균형 존재 (정상 >> 발작)- ✅ 오버샘플링으로 어느 정도 완화
| 구분 | 항목 | 원본 (CHB-MIT Original) | 수정 (DIVER 적용) |
|---|---|---|---|
| 데이터셋 | 전체 서브젝트 수 | 21명 | 21명 (동일) |
| Train | 17명 (chb01-20, 12/13/17 제외) | 17명 (동일) | |
| Validation | 2명 (chb21, chb22) | 2명 (동일) | |
| Test | 2명 (chb23, chb24) | 2명 (동일) | |
| 원본 데이터 | Sampling Rate | 256 Hz | 256 Hz (동일) |
| 파일 형식 | EDF | EDF (동일) | |
| 채널 수 | 16개 (고정) | 16개 (동일) | |
| 채널 시스템 | 전극 배치 시스템 | 10-20 System | 10-20 System (동일) |
| Montage 타입 | Bipolar Montage | Bipolar Montage (동일) | |
| 채널 목록 | FP1-F7, F7-T7, T7-P7, P7-O1, FP2-F8, F8-T8, T8-P8, P8-O2, FP1-F3, F3-C3, C3-P3, P3-O1, FP2-F4, F4-C4, C4-P4, P4-O2 |
동일 | |
| ELC 파일 사용 | ❌ 없음 | ✅ 사용 (standard_1005.elc) | |
| 전처리 Stage 1 | 입력 경로 | /data/datasets/chb-mit-scalp-eeg-database-1.0.0 |
동일 |
| 출력 경로 | /data/datasets/BigDownstream/chb-mit/processed |
동일 | |
| 채널 선택 | Summary 파일 기반 | 동일 | |
| 메타데이터 추출 | seizures, times, channels | 동일 | |
| 중간 저장 형식 | .pkl (pickle) |
동일 | |
| 전처리 Stage 2 | 세그먼트 길이 | 10초 | 10초 (동일) |
| 슬라이딩 윈도우 | 10초 step (non-overlapping) | 10초 step (동일) | |
| 추가 샘플링 | 발작 구간 ±1초, 5초 step | 동일 | |
| 리샘플링 | 타겟 Sampling Rate | - (256 Hz 유지) | ✅ 500 Hz |
| 리샘플링 방법 | - | scipy.signal.resample | |
| Reshape | - | ✅ (16, 5000) → (16, 10, 500) | |
| 라벨링 | 라벨 종류 | Binary (0, 1) | Binary (0, 1) (동일) |
| 라벨 0 | 정상 (발작 없음) | 동일 | |
| 라벨 1 | 발작 있음 | 동일 | |
| 라벨링 기준 | 10초 세그먼트 내 발작 포함 여부 | 동일 | |
| 라벨 정보 출처 | chb{p}-summary.txt |
동일 | |
| 클래스 불균형 해소 | 발작 구간 5초 step 오버샘플링 | 동일 | |
| 최종 출력 | Shape | (16, 2560) | ✅ (16, 10, 500) |
| 16채널, 2560샘플 | 16채널, 10×1초, 500샘플/초 | ||
| 데이터 구조 | {"X": array, "y": int} |
{"signal": array, "label": int, "elc_info": dict} |
|
| 저장 형식 | .pkl (pickle) |
✅ LMDB | |
| 출력 경로 | /data/datasets/BigDownstream/chb-mit/processed_seg/ |
서버 업로드 경로 | |
| 메모리/성능 | 메모리 요구량 | - | 200GB+ |
| 병렬 처리 | CPU 멀티프로세싱 | 동일 | |
| 정규화 | ❌ 없음 | ❌ 없음 (모델에서 처리) |
# 원본 (256Hz)
signal_256 = np.array (16, 2560) # 16채널 × 10초 × 256Hz
# Step 1: 리샘플링 (256Hz → 500Hz)
from scipy.signal import resample
signal_500 = resample(signal_256, 5000, axis=1) # (16, 5000)
# Step 2: Reshape (10개 1초 세그먼트)
signal_final = signal_500.reshape(16, 10, 500) # (16, 10, 500)elc_info = {
"channel_names": [
"FP1-F7", "F7-T7", "T7-P7", "P7-O1",
"FP2-F8", "F8-T8", "T8-P8", "P8-O2",
"FP1-F3", "F3-C3", "C3-P3", "P3-O1",
"FP2-F4", "F4-C4", "C4-P4", "P4-O2"
],
"electrode_pairs": {
"FP1-F7": ["FP1", "F7"],
"F7-T7": ["F7", "T7"],
...
},
"electrode_positions": {
# standard_1005.elc에서 로드
"FP1": [x, y, z],
"F7": [x, y, z],
...
},
"xyz_id": np.array (16, 3) # channel_names 순서의 전극 3D 좌표
}# Key: "{patient}_{recording}_{segment_index}"
key = "chb01_01_0"
# Value: pickled dictionary
value = {
"sample": np.array (16, 10, 500), # float32 (v1: "signal")
"label": int (0 or 1),
"data_info": { # v1: "metadata" + "elc_info" 통합
# ISRUC-compatible fields
"Dataset": "CHBMIT-Seizure",
"modality": "EEG",
"release": "1.0.0",
"subject_id": "chb01",
"task": "seizure-detection",
"resampling_rate": 500,
"original_sampling_rate": 256,
"segment_index": 0,
"start_time": 0.0,
"channel_names": list, # 16 bipolar channels
"electrode_pairs": dict, # Bipolar pairs
"electrode_positions": dict, # 3D coordinates
"xyz_id": np.array (16, 3), # channel_names 순서
# CHBMIT-specific fields
"segment_id": "chb01_01_0",
"split": "train",
"is_oversampled": False
}
}- 기본 세그먼트:
{patient}_{recording}_{sample_index}- 예:
chb01_01_0,chb01_01_2560
- 예:
- 추가 발작 샘플:
{patient}_{recording}_s{seizure_idx}_add_{sample_index}- 예:
chb01_03_s0_add_25344
- 예:
- ✅ EDF 파일 무결성 확인됨
- ✅ 채널 정렬 완료 (16개 고정)
⚠️ Artifact rejection 없음 (원본 신호 그대로 사용)⚠️ 정규화 없음 (모델 학습 시 적용)
- 환자 정보 보호: 환자 번호만 사용 (개인정보 제거됨)
- 클래스 불균형: 오버샘플링으로 완화했으나 여전히 존재
- ELC 매핑: Bipolar 채널 → 두 전극 위치 모두 저장
- 메모리: 전체 데이터셋 크기 고려 시 200GB+ 메모리 권장
환자당 평균:
- Recording 수: ~30개
- Recording 길이: ~1시간
- 기본 세그먼트: ~360개/recording
- 오버샘플링 포함: ~400개/recording
전체 데이터셋:
- Train: 17명 × 30 × 400 = ~204,000 샘플
- Val: 2명 × 30 × 400 = ~24,000 샘플
- Test: 2명 × 30 × 400 = ~24,000 샘플
- 총: ~252,000 샘플
용량 (LMDB):
- 샘플당: ~40KB (16×10×500 float32 + metadata)
- 총: ~10GB (압축 후)
Shoeb, A. (2009).
Application of Machine Learning to Epileptic Seizure Detection.
In: Proceedings of the 26th International Conference on Machine Learning (ICML).
- 공식 사이트: https://physionet.org/content/chbmit/1.0.0/
- PhysioNet: https://physionet.org/content/chbmit/1.0.0/
- DOI: 10.13026/C2K01R
- CBraMod: https://github.com/your-org/CBraMod (Seizure detection model)
- 작성일: 2025-11-21
- 데이터셋 버전: CHB-MIT v1.0.0
- 전처리 버전: DIVER 적용 v1.0
- 작성자: Bohee Lee
- 데이터 사용: 연구 목적으로 자유롭게 사용 가능
- 인용 필수: 논문 발표 시 원본 논문 인용 필요
- Open Access: Public dataset