Sklearn ColumnTransformer + Pipeline = TypeError

Posted

技术标签:

【中文标题】Sklearn ColumnTransformer + Pipeline = TypeError【英文标题】: 【发布时间】:2021-06-17 08:36:36 【问题描述】:

我正在尝试正确使用 sklearn 中的管道和列转换器,但总是以错误告终。我在下面的例子中重现了它。

# Data to reproduce the error
X = pd.DataFrame([[1,  2 , 3,  1 ],
                  [1, '?', 2,  0 ],
                  [4,  5 , 6, '?']],
                 columns=['A', 'B', 'C', 'D'])

#SimpleImputer to change the values '?' with the mode
impute = SimpleImputer(missing_values='?', strategy='most_frequent')

#Simple one hot encoder
ohe = OneHotEncoder(handle_unknown='ignore', sparse=False)

col_transfo = ColumnTransformer(transformers=[
    ('missing_vals', impute, ['B', 'D']),
    ('one_hot', ohe, ['A', 'B'])],
    remainder='passthrough'
)

然后调用transformer如下:

col_transfo.fit_transform(X)

返回以下错误:

TypeError: Encoders require their input to be uniformly strings or numbers. Got ['int', 'str']

【问题讨论】:

【参考方案1】:

它给你一个错误,因为OneHotEncoder 只接受一种数据格式。在您的情况下,它是numbersobject 的混合体。为了克服这个问题,您可以在 imputerOneHotEncoder 之后分离管道,以便在 imputing 的输出上使用 astype 方法。比如:

ohe.fit_transform(imputer.fit_transform(X[['A','B']]).astype(float))

【讨论】:

但是在应用 SimpleImputer 之后,我们应该在每一列中都只有整数,不是吗?此外,如果我最终这样做了,我将不得不分别处理训练和测试,而单个管道允许单个拟合。 不,您将 pipelineColumnTransformer 混淆了。每个变压器的流水线输出是下一个变压器的输入。但是,您的代码中的 ColumnTransformer 正在对 X 数据帧的不同列进行不同的转换。 这个想法是之后能够在管道中使用col_transfo。例如Pipeline(steps=[('preprocessing', col_transfo), ('model', RandomForestClassifier)])。使用您的解决方案,我觉得我必须分别进行训练、验证和测试,并手动转换数据框以添加新列,删除列“A”和“B”等等。【参考方案2】:

错误不是来自 ColumnTransformer 而是来自 OneHotEncoder 对象

col_transfo = ColumnTransformer(transformers=[
    ('missing_vals', impute, ['B', 'D'])],
    remainder='passthrough'
)

col_transfo.fit_transform(X)

数组([[2, 1, 1, 3], [2, 0, 1, 2], [5, 0, 4, 6]], dtype=object)

ohe.fit_transform(X)

TypeError: 参数必须是字符串或数字

OneHotEncoder 抛出此错误是因为对象获取混合类型的值(int + string)以在同一列上进行编码,您需要将浮点列转换为字符串才能应用它

【讨论】:

【参考方案3】:

ColumnTransformer 并行应用其变压器,而不是按顺序应用。所以OneHotEncoder 看到未估算的列B 并拒绝混合类型。

在您的情况下,只需对所有列进行估算,然后编码 A, B

encoder = ColumnTransformer(transformers=[
    ('one_hot', ohe, ['A', 'B'])],
    remainder='passthrough'
)
preproc = Pipeline(steps=[
    ('impute', impute),
    ('encode', encoder),
    # optionally, just throw the model here...
])

如果A,C 中的未来缺失值会导致错误很重要,那么同样将impute 包装到它自己的ColumnTransformer 中。

另见Apply multiple preprocessing steps to a column in sklearn pipeline

【讨论】:

谢谢。从那以后我就明白了。 sklearn 文档只是忽略了它不是按顺序应用而是并行应用的事实。这样可以避免很多麻烦:)

以上是关于Sklearn ColumnTransformer + Pipeline = TypeError的主要内容,如果未能解决你的问题,请参考以下文章

sklearn ColumnTransformer:变压器中的重复列

sklearn OneHotEncoder 与 ColumnTransformer 导致稀疏矩阵代替创建假人

sklearn Pipeline:“ColumnTransformer”类型的参数不可迭代

sklearn.compose.ColumnTransformer:fit_transform() 接受 2 个位置参数,但给出了 3 个

Sklearn ColumnTransformer + Pipeline = TypeError

将 FunctionTransformer 与 sklearn Pipeline 和 ColumnTransformer 一起使用 - 错误:无效的类型提升