如何将存储信号的DataFrame转换为3维NumPy数组供CNN使用
问题原因
直接对存储一维数组的DataFrame调用np.array()+astype(float)报错的核心原因是:此时生成的是(样本数, 通道列数)形状的object类型二维数组,每个元素是独立的一维数组对象,numpy无法直接把存储序列的object元素转成单个float值。
现有DataFrame转三维数组方案
如果已经生成了目标DataFrame,用逐行堆叠的方式即可得到标准float类型三维数组,不会触发序列赋值错误:
# 提取所有信号列,排除标签列 signal_cols = [col for col in df.columns if col != 'label'] # 逐样本堆叠各通道信号,输出形状为(样本数, 通道数, 单通道信号长度) X = np.stack( df.apply(lambda row: np.stack(row[signal_cols], axis=0), axis=1).values, axis=0 ).astype(np.float32) # 单独提取标签数组 y = df['label'].values
转换完成后可通过print(X.shape)验证维度,正常输出格式为(总样本数, 信号通道数, 单通道采样点数),可直接作为CNN模型输入。
更高效的读取代码优化
当前读取代码存在两个明显问题:一是用逐点循环append的方式提取通道值效率极低,二是使用了pandas已弃用的df.append()方法,大样本量下速度很慢。可以直接在读取阶段就构建三维数组,省去DataFrame二次转换的步骤:
import os import numpy as np from numpy import genfromtxt rootdir = r'/content/gdrive/MyDrive/orderdEEG' signal_list = [] label_list = [] # 配置要提取的通道列索引,如需9个通道改为list(range(9))即可 channel_cols = [1,2,3,4,5,6,7,8] # 配置单通道固定采样点数量 sample_len = 339 for subdir, dirs, files in os.walk(rootdir): for file in files: # 跳过非CSV文件避免读取异常 if not file.lower().endswith('.csv'): continue file_path = os.path.join(subdir, file) # 读取CSV时直接跳过表头行 raw_data = genfromtxt(file_path, delimiter=',', skip_header=1) # 截取固定长度、固定通道的信号,转置为(通道数, 采样点)格式 sample = raw_data[:sample_len, channel_cols].T.astype(np.float32) signal_list.append(sample) label_list.append(subdir[-1]) # 直接堆叠得到三维输入数组 X = np.stack(signal_list, axis=0) y = np.array(label_list)
维度适配说明
不同框架的CNN对输入维度顺序要求不同:
- PyTorch的CNN默认输入形状为
(样本数, 通道数, 信号长度),上述代码生成的数组可直接使用 - TensorFlow/Keras的CNN默认输入形状为
(样本数, 信号长度, 通道数),只需执行X = X.transpose(0, 2, 1)调整维度顺序即可 - 所有样本的信号长度必须保持一致,否则
np.stack()会抛出维度不匹配错误,固定截取339个采样点即可规避该问题
内容的提问来源于stack exchange,提问作者Belal Ezzat
相关产品推荐
相关产品推荐

