Braindecode系列 (4):使用自定义数据集

Braindecode系列:使用自定义数据集

  • 0. 引言
  • 1. 数据转换步骤说明
    • 1.1 加载库包
    • 1.2 加载数据
    • 1.3 提取信息
    • 1.4 数据转换
    • 1.5 数据操作
  • 2. 示例
  • 3. 总结

0. 引言

Braindecode系列中,我会介绍跟BCI IV 2a有关的所有相关示例。
在前面的章节中,我们介绍了Braindecode中,为训练模型创建了两种受支持的配置: trialwise decodingcropped decoding 以及如何进行数据增强的内容。在Braindecode系列的前三篇文章中,我们使用的数据集均来自BCIC IV 2a数据集,直接从网上下载且保存在本地(一般保存在C:\Users\用户名\mne_data目录下)。下载后的文件为 .mat文件,一般以下图的形式进行展示:
Braindecode系列 (4):使用自定义数据集_第1张图片
然而,有些读者一直在使用mne库,对于mne库也使用了很久了,不想改变传统数据处理方式有些读者一直在使用 .gdf文件种种原因不能直接替换为Braindecode库。为了解决该问题,我们就需要使用库先对自己的文件进行处理,然后将该数据加载到Braindecode库的数据函数中,即今天的主题:使用自定义数据集。在本章节中,我会展示如何使用自定义数据集来训练EEG深度模型。

注意:配置环境部分内容参考该系列的第一篇文章!!!

1. 数据转换步骤说明

此示例展示了如何将数据 Xy 作为 numpy 数组转换为braindecode兼容的数据格式。

1.1 加载库包

首先,加载所需要的库包。具体代码如下:

import mne

from braindecode.datasets import create_from_X_y

1.2 加载数据

首先,我们使用 mne 获取一些数据:

# 5, 6, 7, 10, 13, 14 are codes for executed and imagined hands/feet
subject_id = 22
event_codes = [5, 6, 9, 10, 13, 14]
# event_codes = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

# This will download the files if you don't have them yet,
# and then return the paths to the files.
physionet_paths = mne.datasets.eegbci.load_data(
    subject_id, event_codes, update_path=False)

# Load each of the files
parts = [mne.io.read_raw_edf(path, preload=True, stim_channel='auto')
         for path in physionet_paths]

1.3 提取信息

我们从加载的数据中获取所需的数据目标标签和附加信息采样频率通道名称。请注意,这些数据和信息可以来自任何来源。具体代码如下:

X = [raw.get_data() for raw in parts]
y = event_codes
sfreq = parts[0].info["sfreq"]
ch_names = parts[0].info["ch_names"]

1.4 数据转换

在完成上述操作后,就可以将数据转换为与skorchbraindecode兼容的数据格式:

windows_dataset = create_from_X_y(
    X, y, drop_last_window=False, sfreq=sfreq, ch_names=ch_names,
    window_stride_samples=500,
    window_size_samples=500,
)

windows_dataset.description  # look as dataset description

1.5 数据操作

在完成数据转换后,你就可以进行一些相关的数据操作,包括但不限制于:

  • 输出样本数
  • 为数据编制索引

具体代码如下:

# 输出样本数量
print(len(windows_dataset))  # get the number of samples

# 为数据编制索引
i = 0
x_i, y_i, window_ind = windows_dataset[0]
n_channels, n_times = x_i.shape  # the EEG data
_, start_ind, stop_ind = window_ind
print(f"n_channels={n_channels}  -- n_times={n_times} -- y_i={y_i}")
print(f"start_ind={start_ind} -- stop_ind={stop_ind}")

2. 示例

为了更好地帮助大家理解上述操作说明,或者说更好地使用自己的数据完成上述操作。这里,我以读取.gdf文件,然后将读取后的数据进行转换为例帮助大家更好的理解。具体代码如下:

import mne
import matplotlib.pyplot as plt
from braindecode.datasets import create_from_X_y

data_path = '../../../dataset/BCICIV_2a_gdf/'
filename = "../../../dataset/BCICIV_2a_gdf/A02T.gdf" #文件位置根据实际情况修改
# 核心数据为n_channels(数据维度)和n_times(数据时长)
raw = mne.io.read_raw_gdf(filename) #mne读取gdf数据

print(raw.info)
print(raw.ch_names)

raw.plot()
plt.show()

# Find the events time positions
# 在我们关注的事件发生时,打上一个我们认得出的标记,
# 这样子就可以从我们收集到的一长段数据中,找到我们感兴趣的事件范围了。
events, _ = mne.events_from_annotations(raw)

# Pre-load the data

raw.load_data()

# 获得了8-40Hz的raw信号
raw.filter(8., 40., fir_design='firwin')  # 使用iir滤波器进行滤波

# Remove the EOG channels and pick only desired EEG channels
# 删除无用通道:我们是四分类想象,EOG-xxxx是眼睛的通道,跟我们的实验无关,删除
raw.info['bads'] += ['EOG-left', 'EOG-central', 'EOG-right']


# # 绘制SSP矢量图
# raw.plot_projs_topomap()
# plt.show()
# pick_types()函数用来获取raw中的数据
# meg=False 表示不获取meg信号   eog信号同  stim信号同
# eeg=True 表示获取eeg信号
# exclude=‘bad’ 表示排除bad坏道的通道
picks = mne.pick_types(raw.info, meg=False, eeg=True, eog=False, stim=False,
                       exclude='bads')

# Extracts epochs of 3s time period from the datset into 288 events for all 4 classes#
# 分段:根据event来分段,提取epochs
# events(events有很多种类),但是我们这里只需要四类events,即769,770,771,772
# tmin和tmax是根据event开始的时间来计算的。
# 这四类events都是从Cue开始计算,即坐标中的2s,而我们需要分析的是范式中Motor imagery的3s数据,
# 这对应的是events开始后的第1s和第4s。因此,tmin,tmax=1,4.
# 现在更多的人认为开始前的0.5s对分类时有帮助的,因此现在更多地人采样时间为0.5-3.5s
tmin, tmax = 0.5, 3.5
# left_hand = 769,right_hand = 770,foot = 771,tongue = 772
event_id = dict({'769': 7,'770': 8,'771': 9,'772': 10})

# 将数据中四个时间的数据提取出来
epochs = mne.Epochs(raw, events, event_id, tmin, tmax, proj=True, picks=picks,
                baseline=None, preload=True)

data_x = epochs.get_data()
labels = epochs.events[:,-1] - 7 + 1
sfreq = epochs.info["sfreq"]
ch_names = epochs.info["ch_names"]

# window_stride_samples这里设置751是因为 每秒采样250个数据 3s的数据长度总共750个样本点,但是它会多出一个点 所以现在采样长度为751
windows_dataset = create_from_X_y(
    data_x, labels, drop_last_window=False, sfreq=sfreq, ch_names=ch_names,
    window_stride_samples=751,
    window_size_samples=751,
)

print(len(windows_dataset))

i = 0
x_i, y_i, window_ind = windows_dataset[0]
n_channels, n_times = x_i.shape  # the EEG data
_, start_ind, stop_ind = window_ind
print(f"n_channels={n_channels}  -- n_times={n_times} -- y_i={y_i}")
print(f"start_ind={start_ind} -- stop_ind={stop_ind}")

3. 总结

到此,使用 Braindecode系列(4):使用自定义数据集 已经介绍完毕了!!! 如果有什么疑问欢迎在评论区提出,对于共性问题可能会后续添加到文章介绍中。

如果觉得这篇文章对你有用,记得点赞、收藏并分享给你的小伙伴们哦。

你可能感兴趣的:(运动想象,脑机接口,深度学习,运动想象,脑机接口,python)