第2章: MNE-Pythonのコアとなる概念¶
MNE-Pythonは、MEG/EEG解析のための標準的なオープンソースPythonライブラリです。Pythonを使って発表されているEEG論文の多くがこれを利用しています。公式のドキュメントとチュートリアルは mne.tools にあり、このチュートリアルシリーズの内容はすべて、そのドキュメントに基づいて、最初の一歩として書き直したものです。
MNEで行うことのほとんどすべては、4つのオブジェクト型を中心に回っています。これらを覚えてしまえば、ライブラリの残りの部分も自然に読めるようになります。すべての関数は、この4つのどれかを作る・変換する・そこから情報を取り出す、という仕事をしているからです。
4つのコアオブジェクト¶
| オブジェクト | 元となるデータの形 | 表すもの |
|---|---|---|
Info |
(メタデータのみ) | チャンネル名/型、サンプリングレート、フィルタ履歴、不良チャンネル、モンタージュなど、記録を説明する「ヘッダー」情報 |
Raw |
(n_channels, n_times) |
連続記録全体 |
Epochs |
(n_epochs, n_channels, n_times) |
イベントの周辺を切り出した、多数の短いスニペット |
Evoked |
(n_channels, n_times) |
エポック群の平均 — これがあなたのERPです |
Raw、Epochs、Evoked のどのオブジェクトも .info という属性を持っています。これはどれも同じ種類のメタデータ格納庫で、そのオブジェクトが保持しているデータについて説明します。一度 .info の中身を確認すれば、3つのどれについても同じように調べ方がわかります。
実際のデータ(前の章までで使った公開サンプルデータセット)を読み込んで、それぞれを見てみましょう。
import mne
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)
raw.pick(["eeg", "eog"]) # あなた自身のデータと同様に、このチュートリアルはEEGに焦点を絞る
raw
| General | ||
|---|---|---|
| Filename(s) | sample_audvis_raw.fif | |
| MNE object type | Raw | |
| Measurement date | 2002-12-03 at 19:01:10 UTC | |
| Participant | Unknown | |
| Experimenter | MEG | |
| Acquisition | ||
| Duration | 00:04:38 (HH:MM:SS) | |
| Sampling frequency | 600.61 Hz | |
| Time points | 166,800 | |
| Channels | ||
| EEG | and | |
| EOG | ||
| Head & sensor digitization | 146 points | |
| Filters | ||
| Highpass | 0.10 Hz | |
| Lowpass | 172.18 Hz | |
Info: メタデータ¶
raw.info は辞書のように振る舞います。特に役立つキーをいくつか紹介します。
print("サンプリングレート:", raw.info["sfreq"])
print("チャンネル数:", raw.info["nchan"])
print("不良チャンネル:", raw.info["bads"])
print("すでに適用済みのハイパス/ローパス:", raw.info["highpass"], raw.info["lowpass"])
raw.info # そのまま表示すると、読みやすい要約全体が得られる
サンプリングレート: 600.614990234375
チャンネル数: 61
不良チャンネル: ['EEG 053']
すでに適用済みのハイパス/ローパス: 0.10000000149011612 172.17630004882812
| General | ||
|---|---|---|
| MNE object type | Info | |
| Measurement date | 2002-12-03 at 19:01:10 UTC | |
| Participant | Unknown | |
| Experimenter | MEG | |
| Acquisition | ||
| Sampling frequency | 600.61 Hz | |
| Channels | ||
| EEG | and | |
| EOG | ||
| Head & sensor digitization | 146 points | |
| Filters | ||
| Highpass | 0.10 Hz | |
| Lowpass | 172.18 Hz | |
Raw: 連続記録¶
内部的には、Raw は普通の2次元NumPy配列をラップしています。行がチャンネル、列が時間サンプルです。.get_data() でその配列を直接取得できます。MNEが行っていることは、最終的にはすべてメタデータの付いた配列演算にすぎない、ということを覚えておくと役立ちます。
data = raw.get_data()
print("データの形状 (チャンネル数, 時間サンプル数):", data.shape)
print("データはデフォルトでボルト単位。例えば最初のチャンネルの最初の5サンプル:", data[0, :5])
データの形状 (チャンネル数, 時間サンプル数): (61, 166800)
データはデフォルトでボルト単位。例えば最初のチャンネルの最初の5サンプル: [1.13989260e-05 9.85015885e-06 7.68188489e-06 5.82336435e-06
6.81457530e-07]
いたるところに出てくるコードパターン¶
MNEのいたるところで登場するお決まりの書き方がいくつかあります。今のうちに見分けられるようになっておくと、後々の混乱を防げます。
1. 多くのメソッドはオブジェクトをその場で(in place)変更します(そして連鎖できるように、そのオブジェクト自身も返します)。raw.filter(...) は raw そのものを変更します。元のものをそのまま残しておきたい場合は、先に .copy() します。
raw_filtered = raw.copy().filter(l_freq=1, h_freq=40) # raw自体は変更されない
raw.filter(l_freq=1, h_freq=40) # raw自体が変更される
raw_filt = raw.copy().filter(...))。フィルタをかけていない raw を比較用にそのまま残しておくために、あえてこうしています。
2. preload: preload=False(場合によってはこれがデフォルト)でファイルを読み込むと、実際の信号ではなくヘッダー/メタデータのみが読み込まれます。.info を調べたいだけの場合や、全体を読み込む前にクロップ(切り出し)したい場合は、この方が高速です。ほとんどの処理ステップは preload=True(読み込み時に指定するか、後で raw.load_data() を呼ぶ)を必要とします。
3. picks: 多くの関数は picks 引数を受け取り、チャンネルの一部だけを対象に操作できます。例: picks="eeg"、picks=["Fz", "Cz"]、picks="eog"。
4. verbose: ほとんどすべての関数が verbose=... を受け取り、上で設定したグローバルな mne.set_log_level(...) とは独立に、その関数自身のログ出力を制御できます。
ノートブックを離れずにヘルプを見る¶
Jupyterでは、任意の関数・メソッドの後ろに ? を付けると、そのdocstring(パラメータの完全な一覧、デフォルト値、説明)がポップアップ表示されます。「この引数は何をするんだっけ?」という疑問に、VS Codeを離れずに答える最速の方法です。
raw.filter?
まとめ¶
Info= メタデータ。すべてのオブジェクトに付いてくる。Raw= 連続記録(2次元: チャンネル × 時間)。Epochs= 試行のスニペット(3次元: 試行 × チャンネル × 時間) — 第6章。Evoked=Epochsの平均 = あなたのERP — 第7章。- インプレースなメソッドの前には
.copy()、データを実際に読み込むにはpreload=True、チャンネルを選ぶにはpicks、その場でドキュメントを見るにはfunction?を使うことを忘れずに。