You need to enable JavaScript to run this app. sklearn的Pipeline是否会将X和y同时传递给后续处理步骤?
优惠活动
大模型
产品
解决方案
定价
更多

sklearn的Pipeline是否会将X和y同时传递给后续处理步骤?

问题根源

原生scikit-learn的Pipeline设计上只允许中间转换器修改特征矩阵X,不会向transform方法传入标签y,也不会处理转换器返回的标签值。同时你自定义的transform方法没有设置y的默认值,当sklearn默认调用transform(X)时就会触发缺少参数的TypeError。

解决方案1:使用imbalanced-learn的Pipeline(推荐,改动最小)

imbalanced-learn是sklearn生态的官方扩展库,它的Pipeline原生支持样本筛选、采样类操作,可以正确传递并更新y。
首先安装依赖:

pip install imbalanced-learn

分两步修改代码即可:

  1. 修正自定义转换器的逻辑和兼容性问题
import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.neighbors import LocalOutlierFactor
from sklearn.preprocessing import StandardScaler

class OutlierExtractor1(BaseEstimator, TransformerMixin):
    def __init__(self, novelty=True):
        self.scaler = StandardScaler()
        # 开启novelty模式,支持测试集推理
        self.lof = LocalOutlierFactor(metric='euclidean', novelty=novelty)
        self.is_inlier = None

    def fit(self, X, y=None):
        # 训练阶段仅用训练集拟合标准化和LOF模型
        X_norm = self.scaler.fit_transform(X)
        self.lof.fit(X_norm)
        # 记录训练集的内样本索引
        self.is_inlier = self.lof.predict(X_norm) == 1
        return self

    def transform(self, X, y=None):
        X_norm = self.scaler.transform(X)
        # 只有传入y的时候才做样本过滤(训练阶段)
        if y is not None:
            # 训练集用fit阶段预计算的内样本索引
            if len(X) == len(self.is_inlier):
                inlier = self.is_inlier
            else:
                # 验证阶段计算当前输入的内样本索引
                inlier = self.lof.predict(X_norm) == 1
            return X.loc[inlier, :], y.loc[inlier]
        # 预测阶段没有y,直接返回原X,不过滤样本
        return X
  1. 将sklearn的Pipeline替换为imblearn的Pipeline
from imblearn.pipeline import Pipeline # 仅修改此处导入即可
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import fbeta_score, make_scorer

space = {'rf__max_depth': [9, 11, 12, 14],
         'rf__n_estimators': [80, 90, 100]}

pipe = Pipeline([('outliers', OutlierExtractor1()),
                 ('rf', RandomForestClassifier(criterion = 'entropy',
                                               min_samples_split = 4,
                                               min_samples_leaf = 2,
                                               min_impurity_decrease = 0.01,
                                               random_state=0))])

ftwo_scorer = make_scorer(fbeta_score, beta=2)
search = GridSearchCV(pipe, param_grid = space, scoring = ftwo_scorer, cv = 4, return_train_score = True, verbose = 1)
search.fit(X = downsampled, y = target)
pd.DataFrame(search.cv_results_)
解决方案2:无额外依赖,封装模型逻辑

如果不想引入第三方库,可以把离群值移除逻辑封装到分类器的fit方法中,不需要修改中间转换器,完全兼容原生sklearn生态:

from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import LocalOutlierFactor
from sklearn.preprocessing import StandardScaler

class RFWithOutlierFilter(RandomForestClassifier):
    def fit(self, X, y, sample_weight=None):
        # 先做离群值过滤
        scaler = StandardScaler()
        X_norm = scaler.fit_transform(X)
        lof = LocalOutlierFactor(metric='euclidean')
        is_inlier = lof.fit_predict(X_norm) == 1
        X_filtered = X.loc[is_inlier, :]
        y_filtered = y.loc[is_inlier]
        # 再调用原生fit方法
        return super().fit(X_filtered, y_filtered, sample_weight=sample_weight)

# 后续Pipeline不需要加outliers步骤
pipe = Pipeline([
    ('rf', RFWithOutlierFilter(criterion = 'entropy',
                               min_samples_split = 4,
                               min_samples_leaf = 2,
                               min_impurity_decrease = 0.01,
                               random_state=0))
])

该方案的缺点是离群值过滤逻辑和模型耦合在一起,如果要更换基础模型需要重新封装。

注意事项
  • 离群值过滤仅应在训练阶段执行,测试/预测阶段不能删除样本,否则会导致评估指标计算错误,也不符合线上推理的实际场景。
  • LocalOutlierFactor默认的novelty=False模式仅支持对训练集做离群检测,要对新样本做检测必须设置novelty=True。

内容的提问来源于stack exchange,提问作者Ana Carolina Rodrigues

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 20:54:03