AI预处理后训练集与测试集Feature shape不匹配问题排查与解决
问题原因与解决方法
核心原因
- 预处理对象未复用:你的
preprocessing函数直接返回训练集转换后的结果,没有保存拟合好的预处理管道。处理测试集时如果重新调用这个函数,会基于测试集的数据重新拟合预处理逻辑,导致独热编码生成的特征数和训练集不一致——比如测试集的分类列中,部分训练集存在的类别没有出现,独热编码就不会生成对应特征列,最终特征数减少。 - 列划分逻辑重复执行:每次调用函数都会重新划分
cat_cols和num_cols,如果测试集的列数据分布和训练集有差异(比如某列在训练集是分类列,在测试集因为唯一值数量变化被划分为数值列),也会导致特征数不匹配。
解决步骤
1. 修改预处理函数,返回拟合后的预处理对象
把原来直接返回转换后数据的逻辑,改成返回拟合好的预处理管道,同时保留基于训练集的列划分结果:
def get_preprocessor(X_train): cat_cols = [] num_cols = [] # 仅基于训练集划分列类型 for cols in X_train.columns: if X_train[cols].nunique() < 10 and X_train[cols].dtype == "object": cat_cols.append(cols) elif X_train[cols].dtype in ["int64", "float64"]: num_cols.append(cols) num_transformer = SimpleImputer(strategy="constant") cat_transformer = Pipeline(steps=[ ("imputer", SimpleImputer(strategy="most_frequent")), ("onehot", OneHotEncoder(handle_unknown="ignore")) ]) preprocessor = ColumnTransformer( transformers=[ ("num", num_transformer, num_cols), ("cat", cat_transformer, cat_cols) ]) # 仅在训练集上拟合预处理管道 preprocessor.fit(X_train) return preprocessor, cat_cols, num_cols
2. 统一训练集与测试集的处理流程
用训练集拟合好的预处理对象处理测试集,全程复用同一管道:
# 1. 处理训练集 preprocessor, _, _ = get_preprocessor(X_train) X_train_processed = preprocessor.transform(X_train) # 2. 训练模型(以随机森林为例) from sklearn.ensemble import RandomForestRegressor model = RandomForestRegressor(random_state=42) model.fit(X_train_processed, y_train) # 3. 处理测试集:必须用训练集拟合好的preprocessor X_test_processed = preprocessor.transform(X_test) # 4. 执行预测 y_pred = model.predict(X_test_processed)
关键说明
- 复用训练集的预处理管道,能保证独热编码的特征数量、顺序和训练集完全一致。即使测试集出现训练集没有的类别,
OneHotEncoder的handle_unknown="ignore"参数会自动忽略这些类别,不会新增特征;如果测试集缺少训练集的类别,也会保留对应特征列并填充0。 - 列划分仅基于训练集,避免测试集的数据分布差异导致列类型判断错误,从根源上保证特征逻辑的一致性。
内容的提问来源于stack exchange,提问作者Fish Ung
相关产品推荐
相关产品推荐

