有没有办法在 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
转换器和FunctionTransformer
与pd.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'
)。它的主要区别在于transform
s 测试数据的方式: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
KBinsDiscretizer
和 pd.qcut
没有得到相同的结果。根据您的说法,两种解决方案应该是相同的。
@m_power,数学内容是一样的(虽然我可以理解由于插值造成的细微差异,但我在你这样的随机示例中没有发现任何差异),只是格式不同。 KBinsDiscretizer
的 bin_edges_
匹配 qcut
的第二个可选输出 bins
随机示例。 qcut
将输出作为间隔返回,而KBinsDiscretizer
将编码返回为 one-hot 或 ordinal。以上是关于有没有办法在 sklearn 管道中链接 pd.cut FunctionTransformer?的主要内容,如果未能解决你的问题,请参考以下文章
sklearn 管道有没有办法在网格搜索期间进行有步骤和无步骤的训练?我可以删除步骤,但如何将其传递给 GridSearchCV?
为啥我在 python 的 sklearn 中使用管道和没有管道得到不同的值