必须显式设置 n_features_in_ 和 feature_names_in_,否则触发 notfittederror;get_feature_names_out 需实现以避免下游特征错位;返回 dataframe 时需手动保留索引列名;验证须通过 check_transformer_general 等三步测试。

为什么不能直接继承 TransformerMixin 就完事?
很多初学者以为只要继承 TransformerMixin、写个 fit 和 transform 就能被 Pipeline 或 ColumnTransformer 接受——但实际会报 NotFittedError 或 AttributeError: 'MyTransformer' object has no attribute 'n_features_in_' 。这是因为 Scikit-learn 从 1.0 版本起强制要求所有转换器必须显式设置 n_features_in_(输入特征数)和 feature_names_in_(输入列名,可选),否则会被视为“未正确拟合”。
实操建议:
- 必须在
fit方法末尾手动赋值:self.n_features_in_ = X.shape[1];若想兼容get_feature_names_out,还需存self.feature_names_in_ = getattr(X, 'columns', None) or np.array([f'x{i}' for i in range(X.shape[1])]) - 不要依赖
TransformerMixin.fit_transform的默认实现——它只是调用fit+transform,不处理属性校验;你得自己确保transform开头有check_is_fitted(self) - 如果输入是稀疏矩阵或 pandas DataFrame,
X.shape[1]没问题,但取列名要用getattr(X, 'columns', None),不能硬写X.columns
get_feature_names_out 不实现会怎样?
不实现该方法本身不会导致报错,但一旦你把它放进 ColumnTransformer 并调用 get_feature_names_out(),就会触发 NotImplementedError;更隐蔽的问题是:某些下游工具(如 sklearn-inspect 或模型解释库)会静默跳过该转换器的特征映射,导致特征对齐出错。
实操建议:
- 哪怕只是做恒等映射,也建议返回
input_features(即传入的列名)或按规则生成新名字,例如:def get_feature_names_out(self, input_features=None): if input_features is None: input_features = self.feature_names_in_ return np.array([f"{feat}_log1p" for feat in input_features]) - 如果转换后特征数变化(如 one-hot 展开),必须严格对应输出维度;返回数组长度 ≠
transform输出列数时,Pipeline会静默失败或后续predict报维度错 - 别在
get_feature_names_out里做计算或 IO——它应是纯函数,且必须接受input_features参数(哪怕你不使用)
如何让自定义转换器支持 pandas DataFrame 输入并保留索引和列名?
原生 transform 返回 ndarray 会丢掉索引和列名,导致和后续步骤(比如另一个只认 DataFrame 的转换器)衔接断裂。这不是 bug,而是设计选择:Scikit-learn 核心只承诺处理 numpy 数组。
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
实操建议:
- 在
transform中判断输入类型:if hasattr(X, 'index') and hasattr(X, 'columns'),然后用pd.DataFrame(result, index=X.index, columns=new_cols)包装输出 - 但要注意:
ColumnTransformer默认把每列转成 2D ndarray 再拼接,所以如果你返回 DataFrame,需配合remainder='passthrough'或统一用FeatureUnion等方式协调;更稳妥的做法是只在最外层封装一层适配器 - 别在
fit里修改X的副本(如X.dropna())——这会污染原始数据;要用X.copy()或明确声明copy=True
验证是否真正兼容 Scikit-learn 的三步检查法
光跑通 fit/transform 不代表兼容。真正落地时容易卡在 Pipeline 集成、超参搜索或跨版本部署上。
实操建议:
- 用
check_estimator(MyTransformer())(来自sklearn.utils.estimator_checks)——但它只对 estimator 有效;对 transformer 要手动跑:check_transformer_general(MyTransformer(), X)+check_transformers_unfitted(MyTransformer()) - 在
Pipeline中混用你的转换器和StandardScaler,然后调用pipeline.named_steps['my'].get_feature_names_out(),确认不崩、返回合理结果 - 用
joblib.dump(pipeline, 'pipe.pkl')再load,验证反序列化后仍能transform——很多自定义类因闭包变量或相对路径引用而 dump 失败
真正麻烦的往往不是逻辑,而是那些没被文档强调的隐式契约:比如 fit 必须返回 self,transform 输入 shape 必须和 fit 一致,还有——别在 __init__ 里做耗时初始化,因为 GridSearchCV 会反复实例化它。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










