有没有办法在 sklearn 管道中链接 pd.cut FunctionTransformer?

Is there a way to chain a pd.cut FunctionTransformer in a sklearn Pipeline?

我正在使用 sklearn 制作 DataFrame 预处理管道并链接各种类型的预处理步骤。

我想链接一个 SimpleImputer 转换器和一个 FunctionTransformer 应用 pd.qcut(或 pd.cut),但我不断收到以下错误:

ValueError: Input array must be 1 dimensional

这是我的代码:

from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import FunctionTransformer

class FeatureSelector(BaseEstimator, TransformerMixin):
    def __init__(self, features):
        self._features = features

    def fit(self, X, y=None):
        return self

    def transform(self, X, y=None):
        return X[self._features]

fare_transformer = Pipeline([
    ('fare_selector', FeatureSelector(['Fare'])),
    ('fare_imputer', SimpleImputer(strategy='median')),
    ('fare_bands', FunctionTransformer(func=pd.qcut, kw_args={'q': 5}))
])

如果我简单地将 FeatureSelector 转换器和 FunctionTransformerpd.qcut 链接在一起并省略 SimpleImputer:

,也会发生同样的情况
fare_transformer = Pipeline([
    ('fare_selector', FeatureSelector(['Fare'])),
    ('fare_bands', FunctionTransformer(func=pd.qcut, kw_args={'q': 5}))
])

我广泛搜索了 Whosebug 和 google,但找不到解决此问题的方法。如有任何帮助,我们将不胜感激!

sklearn 已经有了这样的转换器,KBinsDiscretizer(匹配pd.qcut,使用strategy='quantile')。它的主要区别在于它 transform 测试数据的方式:FunctionTransformer 版本将“重新调整”分位数,而内置 KBinsDiscretizer 将保存分位数统计数据以对测试数据进行分箱。正如 @m_power 在评论中指出的那样,它们在 bin 边缘附近也不同,以及转换数据的格式。

但要具体解决错误:这意味着您的函数 qcut 仅适用于一维数组,而 FunctionTransformer 发送整个数据帧。您可以在 qcut 周围定义一个薄包装器来完成这项工作,例如

def frame_qcut(X, y=None, q=10):
    return X.apply(pd.qcut, axis=0, q=q)

(假设您将获得一个数据框。)