字符串分类特征的一种热编码

Posted

技术标签:

【中文标题】字符串分类特征的一种热编码【英文标题】:One hot encoding of string categorical features 【发布时间】:2016-05-08 13:09:19 【问题描述】:

我正在尝试对琐碎的数据集执行一次热编码。

data = [['a', 'dog', 'red']
        ['b', 'cat', 'green']]

使用 Scikit-Learn 预处理这些数据的最佳方法是什么?

首先,您会关注 Scikit-Learn 的 OneHotEncoder。但是一个热门的编码器不支持字符串作为特征;它只离散整数。

那么您将使用LabelEncoder,它将字符串编码为整数。但是随后您必须将标签编码器应用到每一列并存储这些标签编码器中的每一个(以及应用它们的列)。这感觉非常笨重。

那么,在 Scikit-Learn 中最好的方法是什么?

请不要推荐pandas.get_dummies。这就是我现在通常使用的一种热编码。但是,它的局限性在于您不能单独对训练/测试集进行编码。

【问题讨论】:

pandas.get_dummies 二进制编码也被决策树分类器视为连续,因此不适用于该场景。 【参考方案1】:

如果你在 sklearn>0.20.dev0

In [11]: from sklearn.preprocessing import OneHotEncoder
    ...: cat = OneHotEncoder()
    ...: X = np.array([['a', 'b', 'a', 'c'], [0, 1, 0, 1]], dtype=object).T
    ...: cat.fit_transform(X).toarray()
    ...: 
Out[11]: array([[1., 0., 0., 1., 0.],
           [0., 1., 0., 0., 1.],
           [1., 0., 0., 1., 0.],
           [0., 0., 1., 0., 1.]])

如果你在 sklearn==0.20.dev0

In [30]: cat = CategoricalEncoder()

In [31]: X = np.array([['a', 'b', 'a', 'c'], [0, 1, 0, 1]], dtype=object).T

In [32]: cat.fit_transform(X).toarray()
Out[32]:
array([[ 1.,  0., 0.,  1.,  0.],
       [ 0.,  1.,  0.,  0.,  1.],
       [ 1.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  1.,  0.,  1.]])

另一种方法是使用 category_encoders。

这是一个例子:

% pip install category_encoders
import category_encoders as ce
le =  ce.OneHotEncoder(return_df=False, impute_missing=False, handle_unknown="ignore")
X = np.array([['a', 'dog', 'red'], ['b', 'cat', 'green']])
le.fit_transform(X)
array([[1, 0, 1, 0, 1, 0],
       [0, 1, 0, 1, 0, 1]])

【讨论】:

CategorialEncoder 已与 OneHotEncoder 合并,因此功能包含在当前版本的 sklearn==0.20.dev0【参考方案2】:

我已经多次遇到这个问题,我在this book at his page 100 中找到了解决方案:

我们可以应用这两种转换(从文本类别到整数类别,然后从整数 使用 LabelBinarizer 类一次性将类别转换为单热向量):

示例代码在这里:

from sklearn.preprocessing import LabelBinarizer
encoder = LabelBinarizer()
housing_cat_1hot = encoder.fit_transform(data)
housing_cat_1hot

结果: 请注意,默认情况下,这会返回一个密集的 NumPy 数组。您可以通过传递来获得稀疏矩阵 sparse_output=True 到 LabelBinarizer 构造函数。

您可以在 sklearn 官方文档中找到有关 LabelBinarizer 的更多信息,here

【讨论】:

这在 Windows 10 上的 Python 3.6 中失败。>>> Housing_cat_1hot = encoder.fit_transform(data) ----------- Traceback(最近一次调用最后):文件“",第 1 行,在 ,,, ,,, ,,, 这不是一种热编码,而是虚拟编码。【参考方案3】:

非常好的问题。

但是,从某种意义上说,这是一个私人案例,它经常出现(至少对我而言)——考虑到适用于 X 矩阵子集的 sklearn 阶段,我想申请(可能有几个)给定整个矩阵。例如,在这里,您有一个知道在单个列上运行的阶段,并且您想应用它三次 - 每列一次。

这是使用Composite Design Pattern的经典案例。

这是一个(草图)可重用阶段,它接受将列索引映射到转换以应用于它的字典:

class ColumnApplier(object):
    def __init__(self, column_stages):
        self._column_stages = column_stages

    def fit(self, X, y):
        for i, k in self._column_stages.items():
            k.fit(X[:, i])

        return self

    def transform(self, X):
        X = X.copy()
        for i, k in self._column_stages.items():
            X[:, i] = k.transform(X[:, i])

        return X

现在,在这个上下文中使用它,从

开始
X = np.array([['a', 'dog', 'red'], ['b', 'cat', 'green']])
y = np.array([1, 2])
X

您只需使用它将每个列索引映射到您想要的转换:

multi_encoder = \
    ColumnApplier(dict([(i, preprocessing.LabelEncoder()) for i in range(3)]))
multi_encoder.fit(X, None).transform(X)

一旦你开发了这样一个阶段(我不能发布我使用的那个),你可以反复使用它来进行各种设置。

【讨论】:

老实说,我以前创建过类似的东西。而且感觉很笨重。 Scikit-Learn 应该有一个在底层抽象这个的类,因为它是一种常见的设计模式。如果没有,那么我认为这方面的 PR 是合适的。 您的解决方案对此数据有问题: X = np.array([['cat'],['dog','cat'],['pet','man'],[ '猫']]) y = [1,2,3,4] 我通常也会做类似的事情,但一个已知的缺点是LabelEncoder#transform 在看到训练中没有出现的字符串时会崩溃。 不应该fit_transform 纠正这个吗?

以上是关于字符串分类特征的一种热编码的主要内容,如果未能解决你的问题,请参考以下文章

机器学习:如何在具有分类和数字特征的 pandas 数据帧上应用一种热编码?

一种热编码及其与 DecisionTreeClassifier 的组合

keras中多标签图像的一种热编码

logit 和 sklearn 管道的一种热编码

如何对变体长度特征进行一种热编码?

Pytorch - 使用一种热编码和 softmax 的(分类)交叉熵损失