问题 当有2个类时,sklearn LabelBinarizer返回向量


以下代码:

from sklearn.preprocessing import LabelBinarizer
lb = LabelBinarizer()
lb.fit_transform(['yes', 'no', 'no', 'yes'])

收益:

array([[1],
       [0],
       [0],
       [1]])

但是,我希望每个类有一列:

array([[1, 0],
       [0, 1],
       [0, 1],
       [1, 0]])

(我需要这种格式的数据,所以我可以把它交给一个在输出层使用softmax函数的神经网络)

当有两个以上的类时,LabelBinarizer的行为符合要求:

from sklearn.preprocessing import LabelBinarizer
lb = LabelBinarizer()
lb.fit_transform(['yes', 'no', 'no', 'yes', 'maybe'])

回报

array([[0, 0, 1],
       [0, 1, 0],
       [0, 1, 0],
       [0, 0, 1],
       [1, 0, 0]])

上面,每班有1列。

当有2个类时,有没有简单的方法来实现相同的(每个类1列)?

编辑:基于yangjie的回答,我写了一个类来包装LabelBinarizer以产生上述所需的行为: http://pastebin.com/UEL2dP62

import numpy as np
from sklearn.preprocessing import LabelBinarizer


class LabelBinarizer2:

    def __init__(self):
        self.lb = LabelBinarizer()

    def fit(self, X):
        # Convert X to array
        X = np.array(X)
        # Fit X using the LabelBinarizer object
        self.lb.fit(X)
        # Save the classes
        self.classes_ = self.lb.classes_

    def fit_transform(self, X):
        # Convert X to array
        X = np.array(X)
        # Fit + transform X using the LabelBinarizer object
        Xlb = self.lb.fit_transform(X)
        # Save the classes
        self.classes_ = self.lb.classes_
        if len(self.classes_) == 2:
            Xlb = np.hstack((Xlb, 1 - Xlb))
        return Xlb

    def transform(self, X):
        # Convert X to array
        X = np.array(X)
        # Transform X using the LabelBinarizer object
        Xlb = self.lb.transform(X)
        if len(self.classes_) == 2:
            Xlb = np.hstack((Xlb, 1 - Xlb))
        return Xlb

    def inverse_transform(self, Xlb):
        # Convert Xlb to array
        Xlb = np.array(Xlb)
        if len(self.classes_) == 2:
            X = self.lb.inverse_transform(Xlb[:, 0])
        else:
            X = self.lb.inverse_transform(Xlb)
        return X

编辑2:事实证明,杨杰还写了一个新版本的LabelBinarizer,太棒了!


4696
2017-08-11 16:26


起源



答案:


我认为没有直接的方法可以做到,特别是如果你想拥有它 inverse_transform

但你可以使用numpy轻松构建标签

In [18]: import numpy as np

In [19]: from sklearn.preprocessing import LabelBinarizer

In [20]: lb = LabelBinarizer()

In [21]: label = lb.fit_transform(['yes', 'no', 'no', 'yes'])

In [22]: label = np.hstack((label, 1 - label))

In [23]: label
Out[23]:
array([[1, 0],
       [0, 1],
       [0, 1],
       [1, 0]])

然后你可以使用 inverse_transform 通过切片第一列

In [24]: lb.inverse_transform(label[:, 0])
Out[24]:
array(['yes', 'no', 'no', 'yes'],
      dtype='<U3')

基于上述解决方案,您可以编写一个继承的类 LabelBinarizer,这使得二元和多类情况下的操作和结果一致。

from sklearn.preprocessing import LabelBinarizer
import numpy as np

class MyLabelBinarizer(LabelBinarizer):
    def transform(self, y):
        Y = super().transform(y)
        if self.y_type_ == 'binary':
            return np.hstack((Y, 1-Y))
        else:
            return Y

    def inverse_transform(self, Y, threshold=None):
        if self.y_type_ == 'binary':
            return super().inverse_transform(Y[:, 0], threshold)
        else:
            return super().inverse_transform(Y, threshold)

然后

lb = MyLabelBinarizer()
label1 = lb.fit_transform(['yes', 'no', 'no', 'yes'])
print(label1)
print(lb.inverse_transform(label1))
label2 = lb.fit_transform(['yes', 'no', 'no', 'yes', 'maybe'])
print(label2)
print(lb.inverse_transform(label2))

[[1 0]
 [0 1]
 [0 1]
 [1 0]]
['yes' 'no' 'no' 'yes']
[[0 0 1]
 [0 1 0]
 [0 1 0]
 [0 0 1]
 [1 0 0]]
['yes' 'no' 'no' 'yes' 'maybe']

15
2017-08-11 17:24



谢谢你的搭档,根据你的回答,我创建了一个符合预期的新LabelBinarizer类: pastebin.com/UEL2dP62 - applecider
再次感谢配偶,看起来我们根据您的原始代码同时编写了新版本的LabelBinarizer;) - applecider
@applecider太棒了!很高兴我能帮忙。 - yangjie
这是一个优雅的解决方案,但有一个不一致的地方 LabelBinarizer。通常,每排1个 transform 输出数组出现在对应于相应元素的列中 classes_ 属性。但在二元情况下, MyLabelBinarizer 让它落后。这可以通过使用轻松修复 np.hstack((1-Y, Y)) 在里面 transform 方法和 Y[:, 1] 在 inverse_transform。 - bogatron


答案:


我认为没有直接的方法可以做到,特别是如果你想拥有它 inverse_transform

但你可以使用numpy轻松构建标签

In [18]: import numpy as np

In [19]: from sklearn.preprocessing import LabelBinarizer

In [20]: lb = LabelBinarizer()

In [21]: label = lb.fit_transform(['yes', 'no', 'no', 'yes'])

In [22]: label = np.hstack((label, 1 - label))

In [23]: label
Out[23]:
array([[1, 0],
       [0, 1],
       [0, 1],
       [1, 0]])

然后你可以使用 inverse_transform 通过切片第一列

In [24]: lb.inverse_transform(label[:, 0])
Out[24]:
array(['yes', 'no', 'no', 'yes'],
      dtype='<U3')

基于上述解决方案,您可以编写一个继承的类 LabelBinarizer,这使得二元和多类情况下的操作和结果一致。

from sklearn.preprocessing import LabelBinarizer
import numpy as np

class MyLabelBinarizer(LabelBinarizer):
    def transform(self, y):
        Y = super().transform(y)
        if self.y_type_ == 'binary':
            return np.hstack((Y, 1-Y))
        else:
            return Y

    def inverse_transform(self, Y, threshold=None):
        if self.y_type_ == 'binary':
            return super().inverse_transform(Y[:, 0], threshold)
        else:
            return super().inverse_transform(Y, threshold)

然后

lb = MyLabelBinarizer()
label1 = lb.fit_transform(['yes', 'no', 'no', 'yes'])
print(label1)
print(lb.inverse_transform(label1))
label2 = lb.fit_transform(['yes', 'no', 'no', 'yes', 'maybe'])
print(label2)
print(lb.inverse_transform(label2))

[[1 0]
 [0 1]
 [0 1]
 [1 0]]
['yes' 'no' 'no' 'yes']
[[0 0 1]
 [0 1 0]
 [0 1 0]
 [0 0 1]
 [1 0 0]]
['yes' 'no' 'no' 'yes' 'maybe']

15
2017-08-11 17:24



谢谢你的搭档,根据你的回答,我创建了一个符合预期的新LabelBinarizer类: pastebin.com/UEL2dP62 - applecider
再次感谢配偶,看起来我们根据您的原始代码同时编写了新版本的LabelBinarizer;) - applecider
@applecider太棒了!很高兴我能帮忙。 - yangjie
这是一个优雅的解决方案,但有一个不一致的地方 LabelBinarizer。通常,每排1个 transform 输出数组出现在对应于相应元素的列中 classes_ 属性。但在二元情况下, MyLabelBinarizer 让它落后。这可以通过使用轻松修复 np.hstack((1-Y, Y)) 在里面 transform 方法和 Y[:, 1] 在 inverse_transform。 - bogatron


这应该做到这一点

labels = ['yes', 'no', 'no', 'yes']
np.array([[1,0] if l=='yes' else [0,1] for l in labels])

1
2017-08-11 16:42



确实应该这样做,但我想坚持使用scikit做事的方式,因为LabelBinarizer有像inverse_transform等有用的方法。 - applecider
是的,我阅读了文档并没有找到那个选项 - jay s
确实是一个快速而简单的技巧,谢谢! - Syed Rafay