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

Posted

技术标签:

【中文标题】scikit-learn:如何使用管道组合 LabelEncoder 和 OneHotEncoder?【英文标题】:scikit-learn: How to compose LabelEncoder and OneHotEncoder with a pipeline? 【发布时间】:2018-08-02 09:42:20 【问题描述】:

在为机器学习分类任务预处理标签时,我需要对采用字符串值的标签进行热编码。碰巧来自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 的输出需要通过添加一个微不足道的第二个轴来重塑。我不确定如何添加此功能。

【问题讨论】:

【参考方案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()

【讨论】:

【参考方案2】:

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

 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

【讨论】:

【参考方案3】:

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

【讨论】:

感谢您的更新,更新后可能会使用此信息。【参考方案4】:

奇怪的是他们不能很好地一起玩......我很惊讶。我会扩展该类以按照您的建议返回重塑后的数据。

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 @Learningisamess 错误。管道接受实例,而不是类。 @Learningisamess 我已经更正了上面的代码,请立即检查。如果仍然有错误,请在问题中发布完整的错误堆栈跟踪。 @VivekKumar:确实我在关于管道的实例与类上错了。将很快检查新代码并报告。 添加对额外参数的支持后,代码确实可以工作 (*args, **kwargs)。采纳答案,谢谢!

以上是关于scikit-learn:如何使用管道组合 LabelEncoder 和 OneHotEncoder?的主要内容,如果未能解决你的问题,请参考以下文章

scikit-learn:应用任意函数作为管道的一部分

当最后一个估计器不是转换器时,如何使用 scikit-learn 管道进行转换?

如何在 scikit-learn 管道中将时代添加到 Keras 网络

如何在 scikit-learn 中使用管道调整自定义内核函数的参数

如何在 scikit-learn 管道中的 CountVectorizer 之前包含 SimpleImputer?

如何在 scikit-learn 的管道中对变换参数进行网格搜索