对Numpy数组使用OneHotEncoder后,训练集与测试集列数不一致问题排查
OneHotEncoder编码后训练集与测试集维度不一致的问题
先看你提供的原始代码:
print X.shape, test_data.shape #gives (4100, 15) (410, 15) onehotencoder_1 = OneHotEncoder(categorical_features = [0, 3, 4, 5, 6, 8, 9, 11, 12]) X = onehotencoder_1.fit_transform(X).toarray() onehotencoder_2 = OneHotEncoder(categorical_features = [0, 3, 4, 5, 6, 8, 9, 11, 12]) test_data = onehotencoder_2.fit_transform(test_data).toarray() print X.shape, test_data.shape #gives (4100, 46) (410, 43)
你遇到的问题是:对训练集X和测试集test_data的相同分类特征做OneHot编码后,两者的输出维度却不一样。这是个很典型的预处理错误,我来帮你拆解原因和解决办法:
问题根源
你犯了机器学习预处理中的常见错误:给训练集和测试集分别使用独立的编码器,并且各自执行了fit操作。
OneHotEncoder的fit方法会根据输入数据里的分类特征的所有唯一值生成编码规则。比如某个特征在训练集里有5个不同类别,编码器就会生成5列编码;但如果这个特征在测试集里只出现了3个类别,单独fit的编码器只会生成3列编码。这就直接导致了最终输出的数组维度不一致。
更关键的是,这种做法会让测试集的编码逻辑和训练集不匹配,后续模型在测试集上的预测结果肯定会出问题。
正确的解决方案
核心原则是:预处理规则必须从训练集学习,再应用到测试集上。也就是说,只在训练集上fit一次编码器,然后用同一个编码器去transform测试集。修改后的代码如下:
print(X.shape, test_data.shape) # 输出 (4100, 15) (410, 15) # 只初始化一个编码器,在训练集上完成fit和transform onehotencoder = OneHotEncoder(categorical_features = [0, 3, 4, 5, 6, 8, 9, 11, 12]) X = onehotencoder.fit_transform(X).toarray() # 直接用已经fit好的编码器处理测试集,不要调用fit方法 test_data = onehotencoder.transform(test_data).toarray() print(X.shape, test_data.shape) # 现在两者的维度会完全一致
额外的版本兼容提醒
如果你使用的是scikit-learn 0.22及以上版本,categorical_features参数已经被官方弃用,推荐使用ColumnTransformer来更规范地处理列级别的预处理,避免弃用警告。示例代码如下:
from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder # 指定需要做OneHot编码的列索引 categorical_features = [0, 3, 4, 5, 6, 8, 9, 11, 12] # 创建ColumnTransformer,对指定列执行编码,其余列保持原样 column_transformer = ColumnTransformer( transformers=[('onehot_encoder', OneHotEncoder(), categorical_features)], remainder='passthrough' ) # 仅在训练集上fit,然后完成transform X = column_transformer.fit_transform(X) # 用同一个transformer处理测试集 test_data = column_transformer.transform(test_data)
这样处理后,训练集和测试集的编码维度会完全一致,也符合机器学习的最佳实践。
内容的提问来源于stack exchange,提问作者prashantgpt91
相关产品推荐
相关产品推荐

