scikit-learn:如何使用管道组合LabelEncoder和OneHotEncoder?

13

在进行机器学习分类任务的标签预处理时,我需要对取字符串值的标签进行独热编码。由于来自 sklearn.preprocessingOneHotEncoder 或来自 kera.np_utilsto_categorical 需要 int 输入,这意味着我需要在独热编码之前使用 LabelEncoder。我已经手动用一个自定义类完成了这个过程:

class LabelOneHotEncoder():
    def __init__(self):
        self.ohe = OneHotEncoder()
        self.le = LabelEncoder()
    def fit_transform(self, x):
        features = self.le.fit_transform( x)
        return self.ohe.fit_transform( features.reshape(-1,1))
    def transform( self, x):
        return self.ohe.transform( self.la.transform( x.reshape(-1,1)))
    def inverse_tranform( self, x):
        return self.le.inverse_transform( self.ohe.inverse_tranform( x))
    def inverse_labels( self, x):
        return self.le.inverse_transform( x)

我相信在sklearn API中使用 sklearn.pipeline 一定有办法做到这一点,但是当使用以下代码时:

LabelOneHotEncoder = Pipeline( [ ("le",LabelEncoder), ("ohe", OneHotEncoder)])

我从OneHotEncoder那里得到了错误的提示信息ValueError: bad input shape()。我猜测是由于LabelEncoder的输出需要通过添加一个无关的第二维来进行重塑。但我不知道如何添加这个特性。

4个回答

24

他们不友好地玩耍很奇怪...我很惊讶。我会按照你的建议扩展这个类,以返回重新塑形的数据。

class ModifiedLabelEncoder(LabelEncoder):

    def fit_transform(self, y, *args, **kwargs):
        return super().fit_transform(y).reshape(-1, 1)

    def transform(self, y, *args, **kwargs):
        return super().transform(y).reshape(-1, 1)

那么使用管道应该可以工作。

pipe = Pipeline([("le", ModifiedLabelEncoder()), ("ohe", OneHotEncoder())])
pipe.fit_transform(['dog', 'cat', 'dog'])

https://github.com/scikit-learn/scikit-learn/blob/a24c8b46/sklearn/preprocessing/label.py#L39


感谢您的输入。一开始我接受了您的答案,因为它看起来很明显会起作用,但是在实现时我遇到了一些错误。首先,管道构造函数需要类而不是实例,所以必须是ModifiedLabelEncoder而不是ModifiedLabelEncoder()。其次,reshape参数应该是(-1,1)。之后,ModifiedLabelEncoder可以自行工作,但在管道中却不行。当调用fit_transform时,我得到一个TypeError: super(type, obj): obj must be an instance or subtype of type的错误。 - Learning is a mess
1
@Learningisamess 错了。管道接受实例,而不是类。 - Vivek Kumar
@Learningisamess 我已经纠正了上面的代码,请现在检查一下。如果还有错误,请在问题中发布完整的堆栈跟踪信息。 - Vivek Kumar
@VivekKumar:确实,我在管道方面犯了关于实例与类的错误。我会尽快检查新代码并报告。 - Learning is a mess
在支持额外参数(*args, **kwargs)之后,这段代码能够正常工作。已接受答案,谢谢! - Learning is a mess

17

从scikit-learn 0.20开始,OneHotEncoder接受字符串,因此您不再需要在其之前使用LabelEncoder。并且您可以将其直接用于管道中。


感谢更新,更新后可能会利用这些信息。 - Learning is a mess

0

我使用了一个自定义类来包装我的标签编码函数,并返回整个更新过的数据集。

 class CustomLabelEncode(BaseEstimator, TransformerMixin):
  def fit(self, X, y=None):
   return self
  def transform(self, X ,y=None):
    le=LabelEncoder()
    for i in X[cat_cols]:
    X[i]=le.fit_transform(X[i])
    return X 
cat_cols=['Family','Education','Securities Account','CDAccount','Online','CreditCard']
le_ct=make_column_transformer((CustomLabelEncode(),cat_cols),remainder='passthrough') 
pd.DataFrame(ct3.fit_transform(X)) #This will show you your changes
Final_pipeline=make_pipeline(le_ct)

[我已经实现了它,你可以查看我的 Github 链接] [1]: https://github.com/Ayushmina-20/sklearn_pipeline


-1

虽然这不是针对所提出的问题,但如果您想将LabelEncoder应用于所有列,可以使用以下格式

df_non_numeric =df.select_dtypes(['object'])
non_numeric_cols = df_non_numeric.columns.values
from sklearn.preprocessing import LabelEncoder
for col in non_numeric_cols:
    df[col] = LabelEncoder().fit_transform(df[col].values)
df.head()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接