Skip to content

第6章: イベントとエポック化

きれいにフィルタ済みの連続データができたので、いよいよそれを短い試行のスニペット(Epochs)に切り出します。ERPに関するすべては、ここから組み立てられています。この章では、イベントの見つけ方と、Epochs を正しく構築する方法を扱います。

import mne
import matplotlib.pyplot as plt
from pathlib import Path

mne.set_log_level("WARNING")

sample_folder = Path(mne.datasets.sample.data_path()) / "MEG" / "sample"
raw = mne.io.read_raw_fif(sample_folder / "sample_audvis_raw.fif", preload=True)

# 刺激チャンネルを削除する前にイベントを見つける -- トリガーを見つけるにはこのチャンネルが必要
events = mne.find_events(raw, stim_channel="STI 014")

raw.pick(["eeg", "eog"])
raw.filter(l_freq=1.0, h_freq=40.0)
print("見つかったイベント数:", len(events))
print(events[:10])
見つかったイベント数: 320
[[27977     0     2]
 [28345     0     3]
 [28771     0     1]
 [29219     0     4]
 [29652     0     2]
 [30025     0     3]
 [30450     0     1]
 [30839     0     4]
 [31240     0     2]
 [31665     0     3]]

イベントを見つける2つの方法

第3章で見た通り、イベントは次の2箇所のどちらかにあります。

# 方法1: 専用の刺激/トリガーチャンネル(このデータセット)
events = mne.find_events(raw, stim_channel="STI 014")

# 方法2: ファイルに付随するアノテーション(あなた自身の.edf記録)
events, event_id = mne.events_from_annotations(raw)

どちらの方法でも、最終的に events 配列が得られます。1行が1つのイベントに対応し、列は [sample_number, 0, event_code] です。event_code は単なる整数で、人間にわかりやすい意味は event_id 辞書を通じて付与します。

# このデータセットのイベントコードはMNEによって文書化されている:
event_id = {
    "auditory/left": 1,
    "auditory/right": 2,
    "visual/left": 3,
    "visual/right": 4,
    "smiley": 5,
    "button": 32,
}

fig = mne.viz.plot_events(events, sfreq=raw.info["sfreq"], event_id=event_id)
plt.show()

png

"auditory/left" のような名前に含まれる / に注目してください。MNEはこれを階層的なものとして扱います。後で epochs["auditory"] とすると auditory/leftauditory/right の両方がまとめて選ばれ、epochs["auditory/left"] とすればその1つだけが選ばれます。これは単に、event_id を作るときにあなたが選ぶ命名規則です。関連する条件をグループ化するために使ってください。

Epochs を作成する

mne.Epochs は、すべてのイベントの周辺で固定の時間窓を切り出します。主なパラメータは以下の通りです。

  • tmintmax: イベントを基準とした時間窓の範囲(秒)。例えば -0.2 から 0.5 は、イベントの200ms前から500ms後まで。
  • baseline: 平均値をすべてのチャンネルから差し引く時間窓(通常はイベント前の期間)。任意の電圧オフセットを補正し、エポック同士を比較可能にします。(-0.2, 0.0) が典型的な選択です。
  • reject: チャンネル型ごとのピーク・ツー・ピーク振幅のしきい値を指定する辞書。これを超えるエポックは自動的に破棄されます。ICAで取り切れなかったアーティファクトに対する、大まかながら効果的な第2の防衛線です。
  • preload: Raw の場合と同じ意味で、データを即座に読み込みます。
epochs = mne.Epochs(
    raw,
    events,
    event_id=event_id,
    tmin=-0.2,
    tmax=0.5,
    baseline=(-0.2, 0.0),
    preload=True,
    reject=dict(eeg=150e-6, eog=250e-6),
)
epochs
General
MNE object type Epochs
Measurement date 2002-12-03 at 19:01:10 UTC
Participant Unknown
Experimenter MEG
Acquisition
Total number of events 300
Events counts auditory/left: 63
auditory/right: 69
button: 16
smiley: 15
visual/left: 72
visual/right: 65
Time range -0.200 – 0.499 s
Baseline -0.200 – 0.000 s
Sampling frequency 600.61 Hz
Time points 421
Metadata No metadata set
Channels
EEG and
EOG
Head & sensor digitization 146 points
Filters
Highpass 1.00 Hz
Lowpass 40.00 Hz

何が除外されたかを確認する

reject のしきい値は、汚染されたエポックを自動的に破棄します。どれだけの割合が、なぜ破棄されたのかを必ず確認してください。破棄される試行の割合が大きすぎる場合、しきい値が厳しすぎるか、上流のアーティファクト除去ステップに改善の余地があるサインです。

print(epochs.drop_log_stats(), "% のエポックが除外された")
epochs.plot_drop_log()
plt.show()
6.25 % のエポックが除外された

png

エポックの選択とブラウズ

event_id のラベルを使って条件名でインデックス指定でき、raw.plot() と同じ感覚で個々の試行をブラウズできます。

print("全auditory試行 (leftとrightを合わせたもの):", len(epochs["auditory"]))
print("auditory/leftのみ:", len(epochs["auditory/left"]))

epochs.plot(n_epochs=10, scalings="auto")
plt.show()
全auditory試行 (leftとrightを合わせたもの): 132
auditory/leftのみ: 63

png

エポックの保存(任意)

Epochs オブジェクトの内容に満足したら、保存しておくことで次回パイプライン全体を再実行する手間を省けます。

epochs.save("my-epo.fif", overwrite=True)
epochs = mne.read_epochs("my-epo.fif")
(-epo.fif という命名規則は単なる提案ではなく、MNEの要件です。)

まとめ

  • イベントは、刺激チャンネル(mne.find_events)かアノテーション(mne.events_from_annotations)のいずれかから得られます。
  • event_id は、人間にわかりやすい条件名(/ で階層化することも可能)を整数コードに対応づけます。
  • mne.Epochs(raw, events, event_id, tmin, tmax, baseline, reject) が、試行のスニペットを切り出してクリーンにします。
  • 除外しきい値を適用した後は、必ず epochs.plot_drop_log() を確認してください。

次へ: 第7章 — ERP解析 — これらのエポックを平均してERPそのものを作ります。