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

Posted

技术标签:

【中文标题】有没有办法在 sklearn 管道中链接 pd.cut FunctionTransformer?【英文标题】:Is there a way to chain a pd.cut FunctionTransformer in a sklearn Pipeline? 【发布时间】:2020-10-07 22:23:07 【问题描述】:

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

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

ValueError: 输入数组必须是一维的

这是我的代码:

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))
])

我广泛搜索了 *** 和 google,但找不到解决此问题的方法。在这里的任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

sklearn 已经有这样的转换器,KBinsDiscretizer(匹配pd.qcut,使用strategy='quantile')。它的主要区别在于transforms 测试数据的方式: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)

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

【讨论】:

感谢您的及时回复。通过使用 FeatureSelector 从我的 DataFrame 中选择“Fare”列,我以为我正在为 FunctionTransformer 提供一个应该与 pd.qcut 一起使用的熊猫系列,例如pd.qcut(df['Fare'], q=5) @LazyEval 在管道中的FeatureSelector 参数中将['Fare'] 替换为'Fare' 将以这种方式工作:X[['Fare']] 是一个数据框,但X['Fare'] 是一个系列,这将在qcut 工作。这适用于您的第二个更简单的管道,但会在第一个中失败,因为现在 SimpleImputer 将抱怨一维输入。 哦,好吧,我什至没有真正想过 X['Fare'] 和 X[['Fare']] 之间的区别......我傻了。谢谢! 当应用于一个简单的一维数组(例如np.random.rand(10,1))时,quantile KBinsDiscretizerpd.qcut 没有得到相同的结果。根据您的说法,两种解决方案应该是相同的。 @m_power,数学内容是一样的(虽然我可以理解由于插值造成的细微差异,但我在你这样的随机示例中没有发现任何差异),只是格式不同。 KBinsDiscretizerbin_edges_ 匹配 qcut 的第二个可选输出 bins 随机示例。 qcut 将输出作为间隔返回,而KBinsDiscretizer 将编码返回为 one-hot 或 ordinal。

以上是关于有没有办法在 sklearn 管道中链接 pd.cut FunctionTransformer?的主要内容,如果未能解决你的问题,请参考以下文章

Sklearn:有没有办法为管道定义特定的分数类型?

sklearn 管道有没有办法在网格搜索期间进行有步骤和无步骤的训练?我可以删除步骤,但如何将其传递给 GridSearchCV?

为啥我在 python 的 sklearn 中使用管道和没有管道得到不同的值

有没有办法使用 SKlearn 获得滑动嵌套交叉验证?

Keras Sklearn Tuner 模块“sklearn”没有属性“管道”

为什么我在python中的sklearn中使用管道获取不同的值而没有管道