经独热编码后SVM分类器预测报错:测试集特征数不匹配
解决SVM预测时特征数不匹配的问题
嘿,这个报错其实是机器学习预处理里最常见的坑之一——训练集和测试集的特征处理必须严格保持一致!你训练时把特征扩到了982维,但测试集还是原始的7维,模型当然会懵圈。而且你现在的代码里每次独热编码都重新初始化OneHotEncoder还调用fit_transform,这会导致编码规则每次都变,后续的列索引也全乱了,测试集根本没法复用这些规则。
我给你梳理下核心问题和修复方案:
核心问题
- 你在训练集上多次调用
OneHotEncoder.fit_transform(),每次都会重新学习编码规则,而且因为独热编码会增加特征数,后续的categorical_features参数(比如[14]、[37])其实已经对应不上原来的列位置了,完全是错误的。 - 测试集没有经过和训练集完全一样的编码流程,直接用原始特征去预测,维度自然不匹配。
修复方案:复用训练阶段的编码器,统一预处理流程
最稳妥的做法是用ColumnTransformer来统一管理所有列的预处理,同时保存训练时用到的编码器,测试集只做transform(复用训练规则),不做fit。
修改后的完整代码
import pandas as pd import numpy as np from sklearn.preprocessing import LabelEncoder, OneHotEncoder from sklearn.svm import LinearSVC from sklearn.compose import ColumnTransformer # ---------------------- 训练集预处理 ---------------------- df = pd.read_csv('train.csv', header=None) features = df.iloc[:,:-1].values labels = df.iloc[:,-1].values # 第一步:先给所有分类列做LabelEncoder(把字符串转成模型能识别的数值) # 你原来处理的是列2、3、4、5,先把这些列存下来 categorical_columns = [2, 3, 4, 5] label_encoders = {} for col in categorical_columns: le = LabelEncoder() # 训练集上用fit_transform,同时保存这个编码器 features[:, col] = le.fit_transform(features[:, col]) label_encoders[col] = le # 第二步:用ColumnTransformer一次性处理独热编码,避免手动跟踪列索引 # 这个工具会自动处理分类列的编码,非分类列直接保留 column_transformer = ColumnTransformer( transformers=[ # 指定对categorical_columns做独热编码,输出为密集数组 ('onehot_encoder', OneHotEncoder(sparse_output=False), categorical_columns) ], remainder='passthrough' # 其他列不做处理,直接保留 ) # 训练集上做fit_transform,学习编码规则 encoded_train_features = column_transformer.fit_transform(features) # 训练SVM模型 X_train = np.array(encoded_train_features) y_train = np.array(labels) clf = LinearSVC() clf.fit(X_train, y_train) # ---------------------- 测试集预处理 ---------------------- d_test = pd.read_csv('query.csv') Z_test = d_test.values # 第一步:用训练时保存的LabelEncoder转换测试集的分类列 for col in categorical_columns: # 注意:如果测试集出现训练集没有的类别,这里会报错,可以加handle_unknown='ignore'(sklearn>=0.24支持) Z_test[:, col] = label_encoders[col].transform(Z_test[:, col]) # 第二步:用训练好的ColumnTransformer做transform,得到和训练集维度一致的特征 encoded_test_features = column_transformer.transform(Z_test) # 现在可以正常预测了 confidence = clf.predict(encoded_test_features) print("The query image belongs to Class ") print(confidence)
关键注意点
- 绝对不要在测试集上用fit/fit_transform:
fit是从数据中学习规则,测试集必须复用训练集的规则,否则特征的维度、含义都会和训练时不一样,模型根本无法识别。 - 用ColumnTransformer替代手动编码:手动一次次调用OneHotEncoder很容易因为特征数变化导致列索引错误,ColumnTransformer会自动帮你管理列的位置,靠谱得多。
- 保存LabelEncoder:独热编码的前提是分类列已经转成数值,所以必须用训练时的LabelEncoder来转换测试集的对应列,不能重新训练。
- 处理未知类别(可选):如果测试集可能出现训练集没见过的分类值,可以在初始化LabelEncoder时加
le = LabelEncoder(handle_unknown='ignore'),这样遇到未知类别会自动忽略(或者用其他方式填充),避免报错。
内容的提问来源于stack exchange,提问作者arindom
相关产品推荐
相关产品推荐

