Sklearn Pipeline调用get_feature_names_out()在DataFrame拟合时失败问题咨询
sklearn Pipeline中FunctionTransformer特征重命名的DataFrame适配问题
问题描述
在sklearn 1.3.1版本搭建Pipeline时,使用FunctionTransformer的feature_names_out参数重命名特征,出现两种输入场景下的不一致行为:
- 输入为numpy数组时,
p.get_feature_names_out()正常返回重命名后的特征名x0__log、x1__log:
from typing import List import numpy as np import pandas as pd from sklearn.preprocessing import FunctionTransformer, StandardScaler from sklearn.pipeline import make_pipeline def with_suffix(_, names: List[str]): return [name + '__log' for name in names] p = make_pipeline( FunctionTransformer(np.log1p, feature_names_out=with_suffix), StandardScaler() ) df = pd.DataFrame([[1,2], [3,4], [5,6]], columns=['a', 'b']) p.fit_transform(df.values) p.get_feature_names_out()
- 直接输入DataFrame调用
p.fit_transform(df)时,p.get_feature_names_out()抛出ValueError: input_features is not equal to feature_names_in_错误。查看各步骤特征名可见:
print(p.feature_names_in_) print(p[0].get_feature_names_out()) print(p[1].feature_names_in_) ['a' 'b'] ['a__log' 'b__log'] ['a' 'b']
第一步元数据已生成正确的重命名特征名,但第二步StandardScaler的feature_names_in_仍保留原始列名,导致特征名传递冲突。
原因分析
这是sklearn的预期行为:FunctionTransformer的feature_names_out仅用于定义特征名的映射规则(供Pipeline的get_feature_names_out()等方法读取元数据),不会主动修改输出DataFrame的列名。当输入为DataFrame时,np.log1p处理后返回的DataFrame仍保留原始列名,后续步骤会读取该列名作为自身的feature_names_in_,Pipeline串联特征名时会发现元数据与实际接收的特征名不一致,从而触发错误。
解决方案
需要让FunctionTransformer输出的DataFrame列名与feature_names_out返回的特征名保持一致,可通过包装器实现:
def wrapped(func): def _func(X): W = func(X) if isinstance(X, pd.DataFrame): W = W.rename(columns=dict(zip(X.columns, with_suffix(None, X.columns)))) return W return _func p = make_pipeline( FunctionTransformer(wrapped(np.log1p), feature_names_out=with_suffix), StandardScaler() ) p.fit_transform(df) p.get_feature_names_out() # 正常返回['a__log' 'b__log']
该方案确保无论输入是numpy数组还是DataFrame,Pipeline的特征名传递逻辑一致,避免冲突。
内容的提问来源于stack exchange,提问作者patricksurry
相关产品推荐
相关产品推荐

