Braindecode系列:使用自定义数据集
- 0. 引言
- 1. 数据转换步骤说明
- 1.1 加载库包
- 1.2 加载数据
- 1.3 提取信息
- 1.4 数据转换
- 1.5 数据操作
- 2. 示例
- 3. 总结
0. 引言
在Braindecode
系列中,我会介绍跟BCI IV 2a
有关的所有相关示例。
在前面的章节中,我们介绍了Braindecode
中,为训练模型创建了两种受支持的配置: trialwise decoding
和 cropped decoding
以及如何进行数据增强的内容。在Braindecode
系列的前三篇文章中,我们使用的数据集均来自BCIC IV 2a
数据集,直接从网上下载且保存在本地(一般保存在C:\Users\用户名\mne_data
目录下)。下载后的文件为 .mat
文件,一般以下图的形式进行展示:
然而,有些读者一直在使用mne库,对于mne库也使用了很久了,不想改变传统数据处理方式
;有些读者一直在使用 .gdf文件
种种原因不能直接替换为Braindecode
库。为了解决该问题,我们就需要使用库先对自己的文件进行处理,然后将该数据加载到Braindecode库的数据函数中,即今天的主题:使用自定义数据集
。在本章节中,我会展示如何使用自定义数据集
来训练EEG深度模型。
注意:配置环境部分内容参考该系列的第一篇文章!!!
1. 数据转换步骤说明
此示例展示了如何将数据 X
和 y
作为 numpy
数组转换为braindecode
兼容的数据格式。
1.1 加载库包
首先,加载所需要的库包。具体代码如下:
import mnefrom 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 数据转换
在完成上述操作后,就可以将数据转换为与skorch
和braindecode
兼容的数据格式:
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_ydata_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 dataraw.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):使用自定义数据集 已经介绍完毕了!!! 如果有什么疑问欢迎在评论区提出,对于共性问题可能会后续添加到文章介绍中。
如果觉得这篇文章对你有用,记得点赞、收藏并分享给你的小伙伴们哦😄。