不一致的LabelBinarizer行为会破坏管道

时间:2018-02-21 21:22:12

标签: python python-3.x numpy scikit-learn

我的管道看起来像这样:

import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelBinarizer

train_animals = pd.DataFrame({'animal': ['cat', 'dog', 'dog']})

lb = LabelBinarizer()
lb.fit_transform(train_animals.animal)

生成:

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

但是,当我在看不见的数据上应用我的管道时:

test_animals = pd.DataFrame({'animal': ['cat', 'cat', 'duck', 'fish']})
lb.transform(test_animals)

它会吐出来:

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

打破了一切。

我需要LabelBinarizer来保持onehotencode并且永远不会生成单个列。所以:

lb = LabelBinarizer()
lb.fit_transform(train_animals.animal)

理想情况下会产生:

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

2 个答案:

答案 0 :(得分:1)

我认为我已经提出了一个破解内部label_binarize功能的解决方案,该解决方案适用于DataFrameMapper

import pandas as pd
import numpy as np
from sklearn.preprocessing import label_binarize, LabelBinarizer
from sklearn.base import TransformerMixin
from sklearn_pandas import DataFrameMapper

class SafeLabelBinarizer(TransformerMixin):

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

    def fit(self, X):
        X = np.array(X)
        self.lb.fit(X)
        self.classes_ = self.lb.classes_

    def transform(self, X):
        K = np.append(self.classes_, ['__FAKE__'])
        X = label_binarize(X, K, pos_label=1, neg_label=0)
        X = np.delete(X, np.s_[-1], axis=1)
        return X

    def fit_transform(self, X):
        self.fit(X)
        return self.transform(X)

培训数据:

train_animals = pd.DataFrame({'animal': ['cat', 'dog', 'dog']})

mapper = DataFrameMapper([
    ('animal', SafeLabelBinarizer())], df_out=True)

mapper.fit_transform(train_animals)

>>>

    animal_cat  animal_dog
0   1   0
1   0   1
2   0   1

看不见的数据:

test_animals = pd.DataFrame({'animal': ['cat', 'cat', 'duck', 'fish']})
mapper.transform(test_animals)

>>>

    animal_cat  animal_dog
0   1   0
1   1   0
2   0   0
3   0   0

答案 1 :(得分:0)

它的documented here二进制数据只包含1列。

  

返回:Y:                  形状的数组或CSR矩阵[n_samples,n_classes]。                  对于二元问题,形状将为[n_samples,1]。

如果每个类别需要一列,可以尝试以下方法:

1)pd.get_dummies()

train_animals = pd.DataFrame({'animal': ['cat', 'dog', 'dog']})
pd.get_dummies(train_animals).values

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

但是这种方法的警告是你需要在分割成训练和测试之前转换数据。不只是火车数据。因为在测试数据上它会生成不同数量的列。

2)CategoricalEncoder()

from sklearn.preprocessing import CategoricalEncoder
enc = CategoricalEncoder()
train_animals = pd.DataFrame({'animal': ['cat', 'dog', 'dog']})
enc.fit_tranform(train_animals[['animals']])

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

现在,CategoricalEncoder仍在开发分支中,因此可能不容易使用。

3)您可以使用LabelEncoder和OneHotEncoder的组合代替CategoricalEncoder。有关使用的更多详细信息,请参阅我的其他答案:

但对于第2点和第3点,您需要确保“动物”中的所有可能值。列出现在火车上。如果测试集包含看不见的值,则会抛出错误,因为ML模型无法对测试数据做任何事情,而且还没有看到。