Sklearn train_test_split拆分多输入数据时输出维度不符合预期
形状异常的核心原因
手动拼接两个特征数组的步骤触发了numpy的对象数组退化机制,根本没有生成符合维度预期的规则张量,具体过程如下:
- 逐样本zip配对X1、X2之后,每个配对元素是形状为(12,)的X1单样本、形状为(51,5)的X2单样本,两者形状完全不匹配,numpy无法将其拼接成连续的多维数值数组
- 此时执行
np.array(list(zip(X1, X2))),最终生成的X不是预期的(1920, 2)形状的规则数组,而是dtype为object的一维数组,长度和样本数一致,每个元素是存了两个特征数组的元组 - 后续拆分完成后,对X_train做
[:, 0]、[:, 1]切片时,因为整个数组是一维结构,切出来的结果本质还是长度为1536的一维对象数组,并不会自动展开每个元素里存的原始特征维度,最终拿到的形状自然和预期差了特征维度部分。
可直接使用的正确实现方案
方案1:跳过手动拼接步骤(最稳妥无额外开销)
train_test_split原生支持同步拆分多个第一维样本数一致的数组,会基于同一套随机抽样索引完成所有数组的拆分,完全不需要手动打包特征:
from sklearn.model_selection import train_test_split X1 = np.load('x_train.npy') X2 = np.load('oneHot.npy') y = np.load('y_train.npy') # 按相同索引同步拆分所有输入数组 X1_train, X1_valid, X2_train, X2_valid, y_train, y_valid = train_test_split( X1, X2, y, test_size=0.2, random_state=42 )
拆分完成后形状完全符合预期:
X1_train形状为(1536, 12)X2_train(即原代码中的oneHot_train)形状为(1536, 51, 5)
方案2:确需打包特征时的正确拼接逻辑
如果业务场景要求必须把两个特征打包成单个对象传入拆分函数,不能直接用zip转普通数组,需要在拆分后主动展开堆叠特征:
# 初始化和样本数等长的object数组,逐样本存入配对的特征 X = np.empty(len(X1), dtype=object) for idx in range(len(X1)): X[idx] = (X1[idx], X2[idx]) X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2) # 从object数组中逐样本提取特征,沿样本维度重新拼成规则张量 X1_train = np.stack([sample[0] for sample in X_train]) oneHot_train = np.stack([sample[1] for sample in X_train])
补充验证技巧:可以在执行拼接后直接打印
X.shape和X.dtype确认数组类型,如果输出显示dtype=object且第一维就是总样本数,就说明触发了numpy的对象数组退化,需要调整拼接逻辑。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

