1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AppleのEmbedding Atlas 後編:CHB-MIT EEGデータで発作検知可視化パイプラインを構築してみた

Posted at

はじめに

こんにちは、しゅんです。前編では Embedding Atlas を使って Iris や Ariel データを可視化しました。
前編

今回は、PhysioNet が公開する CHB-MIT Scalp EEG Database を題材に、短時間ウィンドウごとのスペクトル特徴量を抽出し、UMAP で埋め込んだ結果を Embedding Atlas で対話的に探索する「発作検知パイプライン」をご紹介します。

CHB-MIT Scalp EEG Database の詳細

CHB-MIT Scalp EEG Database は、米MITと児童病院(Children's Hospital Boston)が共同で収集した小児てんかん患者の頭皮EEGデータセットです。

  • 収録対象:24名の小児てんかん患者
  • セッション数:986セッション(各セッション30分~2時間程度)
  • ファイル形式
    • 信号データ:EDF(European Data Format)形式
    • 発作アノテーション:同名.edf.seizures テキストファイル
  • チャネル数:23~26チャネル(国際10–20システムに基づく配置)
  • サンプリング周波数:256 Hz
  • アノテーション
    • 各発作区間の「開始時刻(秒)」と「終了時刻(秒)」を記述
    • 複数発作がある場合は行を追加
  • 用途:発作検知アルゴリズムの評価、被験者識別、睡眠ステージ解析など
  • ライセンス:非商用研究目的で無料
  • ダウンロード方法: (42.6 GB)
  • AWS CLI の最新バージョンのインストールまたは更新が前提

aws s3 sync --no-sign-request s3://physionet-open/chbmit/1.0.0/ DESTINATION

1. 特徴量抽出:make_extract_all_chb.py

#!/usr/bin/env python3
# make_extract_all_chb.py

import os, glob
import mne
import pandas as pd
from tqdm import tqdm
from mne.time_frequency import psd_array_welch

BASE_DIR = "/Users/syun/chbmit/DESTINATION"  # CHB-MITのルートフォルダ
bands = {'delta':(1,4), 'theta':(4,8), 'alpha':(8,13), 'beta':(13,30)}

all_dfs = []
pattern = os.path.join(BASE_DIR, "chb*", "*.edf")
edf_paths = glob.glob(pattern)
print(f"Found {len(edf_paths)} EDF files")

for path in tqdm(edf_paths, desc="Extracting features"):
    raw = mne.io.read_raw_edf(path, preload=True, verbose=False)
    raw.filter(1, 40, fir_design='firwin', verbose=False)
    data = raw.get_data()          # (n_channels, n_times)
    sf  = raw.info['sfreq']        # 256.0 Hz

    # Welch法でPSD計算
    psd, freqs = psd_array_welch(data, sfreq=sf,
                                 fmin=1, fmax=30, verbose=False)

    feats = {}
    for band,(fmin,fmax) in bands.items():
        mask = (freqs>=fmin)&(freqs<fmax)
        for idx, ch in enumerate(raw.ch_names):
            feats[f"{ch}_{band}"] = psd[idx, mask].mean()

    # メタデータ:セッション名
    session = os.path.basename(path).replace(".edf","")
    feats["session"] = session

    all_dfs.append(pd.DataFrame([feats]))

# Parquet出力
df_all = pd.concat(all_dfs, ignore_index=True)
df_all.to_parquet("chb_all_features.parquet", index=False)
print(f"✅ chb_all_features.parquet saved (shape={df_all.shape})")
  • ポイント

    • 23~26チャネル全てについて、δ/θ/α/β帯の平均パワーを計算
    • 各セッションは1行にまとめ、後続分析が容易な形式に

2. UMAP 投影:project_chb_umap.py

#!/usr/bin/env python3
# project_chb_umap.py

import pandas as pd
import umap

df = pd.read_parquet("chb_all_features.parquet")
df = df.fillna(0)  # 欠損値を0埋め

# 特徴量列だけ抽出
feat_cols = [c for c in df.columns if c!="session"]

# UMAP設定 & 実行
reducer = umap.UMAP(
    n_neighbors=15,
    min_dist=0.1,
    metric='euclidean',
    random_state=42
)
proj = reducer.fit_transform(df[feat_cols].values)

df["proj_x"], df["proj_y"] = proj[:,0], proj[:,1]
df.to_parquet("chb_all_with_proj.parquet", index=False)
print(f"✅ chb_all_with_proj.parquet saved (shape={df.shape})")
  • ポイント

    • n_neighbors=15, min_dist=0.1 で試行
    • 986セッション→2次元座標に圧縮

3. Embedding Atlas で可視化

embedding-atlas chb_all_with_proj.parquet \
  --x proj_x --y proj_y --text session
  • Color bysession → 特定患者/セッションごとの分布比較
  • Density:δ/θ/α/β 各帯の密度等高線表示
  • Nearest Neighbors:類似セッションの即時強調表示

各セッションは点として配置され、患者間・患者内での発作・非発作パターンの違いを直感的に把握できます。

結果

.venv_embedding-atlas) syun@syunnoMacBook-Pro embedding-atlas % embedding-atlas chb_all_with_proj.parquet \    
  --x proj_x --y proj_y --text session
Loading data from chb_all_with_proj.parquet
     FP1-F7_delta   F7-T7_delta   T7-P7_delta   P7-O1_delta  ...  VNS_beta     proj_x    proj_y                  FILE_NAME
0    8.858657e-10  1.764916e-09  7.376013e-10  1.603063e-09  ...       0.0   8.885270  5.587948  chb_all_with_proj.parquet
1    8.584892e-10  3.807528e-10  3.428298e-10  3.192264e-10  ...       0.0   8.827070  0.517095  chb_all_with_proj.parquet
2    3.015182e-10  1.808278e-10  9.515979e-11  1.316609e-10  ...       0.0   5.863206 -0.101678  chb_all_with_proj.parquet
3    3.337923e-10  1.956481e-10  1.428465e-10  1.890894e-10  ...       0.0   5.621890  0.189674  chb_all_with_proj.parquet
4    1.455937e-10  2.226266e-10  8.724599e-11  2.002493e-10  ...       0.0   4.195142  1.697780  chb_all_with_proj.parquet
..            ...           ...           ...           ...  ...       ...        ...       ...                        ...
681  2.165244e-10  4.052604e-10  8.749266e-10  7.846272e-10  ...       0.0   6.814955  2.804620  chb_all_with_proj.parquet
682  5.686283e-10  1.223299e-09  2.065206e-09  1.556322e-09  ...       0.0   8.300296  3.819256  chb_all_with_proj.parquet
683  4.748919e-10  1.258660e-09  2.268122e-09  1.933899e-09  ...       0.0   8.253319  3.795711  chb_all_with_proj.parquet
684  2.310469e-09  8.774290e-10  8.605009e-10  9.259115e-10  ...       0.0  10.568083  2.417742  chb_all_with_proj.parquet
685  1.467647e-09  7.436803e-10  1.075059e-09  9.689776e-10  ...       0.0  10.415847  2.174259  chb_all_with_proj.parquet

[686 rows x 396 columns]
INFO:     Started server process [28098]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:5055 (Press CTRL+C to quit)

まとめ

  • CHB-MIT EEG の全セッションを「チャネル×帯域パワー特徴量」に変換
  • UMAP で 2D に埋め込み、セッション間のスペクトル類似度を可視化
  • Embedding Atlas を使えば、ノーコードで密度推定や最近傍探索を駆使した発作パターンの探索が可能

これにより、臨床 EEG データの発作検知モデル開発や、被験者識別、異常検知パイプラインの初期探索を高速かつインタラクティブに行えます。ぜひご自身のデータでもお試しください!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?