FunctionTransformer与Pipeline/ColumnTransformer使用报错及原理咨询
Sklearn Pipeline/ColumnTransformer报错修复及技术疑问解答
报错原因与修复
核心问题分析
- 函数依赖全局变量:
drop_cols直接操作全局的data而非传入的参数,导致Pipeline运行时返回的是原始数据集(含已被删除的f列),与后续X_train的列不匹配。 - 列定义不一致:
num_clmns/cat_clmns基于原始data定义,但X_train已删除f列,导致ColumnTransformer找不到对应列。 - 组件位置错误:全局列删除操作不应放在ColumnTransformer内部,它是针对全量数据的处理,需放在ColumnTransformer之前。
修复后的代码
import pandas as pd from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import OneHotEncoder from sklearn.preprocessing import StandardScaler from sklearn.preprocessing import FunctionTransformer # 生成测试数据 a = range(1, 10) b = range(10, 100, 10) c = range(11, 110, 11) d = range(12, 120, 12) e = ['aa','bb','cc','dd','ee','ff','gg','hh','ii'] f_list = ['ф','и','с','в','у','а','п','р','ш'] g = ['!','@','#','$','%','^','&','*','('] test={'a': a, 'b': b, 'c': c, 'd': d, 'e': e, 'f': f_list, 'g': g} data = pd.DataFrame(test, columns=['a', 'b', 'c', 'd', 'e', 'f', 'g']) # 修复删除列函数:使用传入的参数而非全局变量 def drop_cols(X): cols = ['g'] return X.drop(cols, axis=1) # 拆分数据集 x = data.drop('f', axis=1) y = data['f'] # 基于拆分后的x定义列,保证列匹配 num_clmns = x.select_dtypes(include='int').columns cat_clmns = x.select_dtypes(include='object').columns X_train, X_test, y_train, y_test = train_test_split(x, y, train_size=0.3, random_state=42) # 列转换组件:仅处理x中存在的列 trans = ColumnTransformer([ ('num_trans1', StandardScaler(), num_clmns), ('cat_trans1', OneHotEncoder(sparse_output=False, handle_unknown='ignore'), cat_clmns) ], remainder='passthrough') # 正确的Pipeline顺序:全局处理→列转换→建模 pipe = Pipeline([ ('drop_g', FunctionTransformer(drop_cols)), ('trans', trans), ('rtc', RandomForestClassifier()) ]) pipe.fit(X_train, y_train) print("Pipeline训练成功")
技术疑问解答
1. 三者的数据流转机制
- FunctionTransformer:把普通Python函数包装成sklearn兼容组件,全量接收输入数据,全量输出转换结果,不针对特定列,仅做全局数据处理。
- ColumnTransformer:对数据集的不同列子集并行应用不同转换器,流程为:拆分指定列子集→各子集单独执行fit_transform/transform→拼接所有结果输出。
- Pipeline:将组件按顺序串联,前一个组件的输出作为后一个组件的输入,训练时依次执行fit_transform(最后一个模型组件执行fit),预测时依次执行transform后调用模型predict,数据单向流转。
2. ColumnTransformer.fit_transform与Pipeline.fit的差异
- ColumnTransformer.fit_transform:针对多列子集做并行训练+转换,同时记录每个转换器的训练状态(如标准化的均值方差),最终返回拼接后的特征矩阵,属于同一层级的多分支处理。
- Pipeline.fit:按顺序执行串行全流程训练,每个组件的训练依赖前序输出,负责保存整个链的训练状态,后续可直接处理新数据,属于线性的连续处理。
3. Pipeline构建的列与DataFrame规则
- 列定义必须匹配当前数据:所有基于列名的操作(如ColumnTransformer指定列),必须基于当前流转到该组件的DataFrame列,不能复用原始数据的列定义。
- 数据修改在前,列定义在后:若有删/加列操作,需在操作完成后再定义后续组件的列列表,避免列不存在的错误。
- 组件顺序符合逻辑:全局数据处理(如删列、全局标准化)放前面,特定列处理(如ColumnTransformer)放中间,模型放最后。
- 禁止依赖全局变量:转换器逻辑必须依赖传入参数,不能用全局DataFrame,否则会导致训练/预测时数据不匹配。
内容的提问来源于stack exchange,提问作者InfinityVaL
相关产品推荐
相关产品推荐

