许多MNE-Python的数据对象如Raw、epoch、Evoked等都有原地修改数据的方法,它们是可选的或必须的。在处理大型数据集时,这是有利的,因为它减少了执行计算所需的计算机内存。然而,如果你没有意识到它的发生,它可能会导致意想不到的结果。像往常一样,我们将首先导入我们需要的模块,并加载一些示例数据:

1
2
3
4
5
6
7
import mne

sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = sample_data_folder / "MEG" / "sample" / "sample_audvis_raw.fif"
# the preload flag loads the data into memory now
raw = mne.io.read_raw_fif(sample_data_raw_file, preload=True)
raw.crop(tmax=10.0) # raw.crop() always happens in-place

这里截取数据的crop方法就是原地修改的。

信号预处理

大多数MNE-Python数据对象都有用于过滤的内置方法,包括高通、低通和带通滤波器(filter)、带阻滤波器(notch_filter)、希尔伯特变换(apply_hilbert),甚至是任意或用户定义的函数(apply_function)。它们通常都是就地修改数据。

所以如果我们想要保留未处理的数据以供比较,必须先进行复制。例如:

1
2
3
4
5
6
original_raw = raw.copy()
raw.apply_hilbert()
print(
f"original data type was {original_raw.get_data().dtype}, after "
f"apply_hilbert the data type changed to {raw.get_data().dtype}."
)

original data type was float64, after apply_hilbert the data type changed to complex128.

可以看到,希尔伯特变换之后数据的dtype发生了改变。

选择通道

选择通道方法也是原地该数据的。

1
2
3
print(f'original data had {original_raw.info["nchan"]} channels.')
original_raw.pick("eeg") # selects only the EEG channels
print(f'after picking, it has {original_raw.info["nchan"]} channels.')

original data had 376 channels.
after picking, it has 60 channels.

使用copy参数

上面我们看到了一个使用复制方法来方便比较处理前后数据的示例。在使用某些mne-python函数时不需要这样做,因为它们有一个copy参数,可以指定copy=True或copy=False(原地修改,默认)。如Set_eeg_reference就是这样一个函数。

1
2
3
rereferenced_raw, ref_data = mne.set_eeg_reference(original_raw, ["EEG 003"], copy=True)
fig_orig = original_raw.plot()
fig_reref = rereferenced_raw.plot()

image.png
可以发现original_raw没变。

另一个例子是函数mne.pick_info,它是对mne.info字典进行操作的,而不是数据本身。

总的来说,如果我们希望避免每次重新加载数据并重复之前的步骤,那么应该习惯raw.copy().filter(…).plot()或者raw.copy().apply_proj().compute_psd().plot()等写代码方式。