One-Hot技术详解 郝伟,2020/12/21

[TOC]

1. 1 前言

我们经常会遇到包含没有特定优先顺序的数字序列。比如以下情况: 一个“宠物”变量的可能的值序列:“猫”、“狗”、“马”。 一个“颜色”变量的可能的值序列:“红”、“绿”、“蓝”。 一个“方位”变量的可能的值序列:“上”、“下”、“前”。 在这些值的序列中的数据通常表示类别或类别的值,并且在列中的数据经过标签编码时也是如此,这会通常会对机器学习模型的性能(如精准度)产生负面的影响。为避免这种情况,列中的数据可以使用各类编码技术来解决,其中one-hot编码就是一种对机器学习而言特别有效的解决方式。它是指将包含数字分类数据的列拆分为许多列,具体取决于该列中存在的类别数量。每列包含对应于其放置在哪一列的 “0” 或 “1”。

2. 2 原理

One-hot编码是一种矢量表示形式,其中矢量中的所有元素均为0(除1之外,其他元素的值为1),其中1表示指定元素类别的布尔值。还有一种类似的实现方式称为“单冷编码”,其中向量中的所有元素均为1,但其中一个元素的值为0。例如,[0,0,0,1,0]和[1,0,0,0,0]可能是单热向量的一些示例。也用于表示数据的与此类似的技术是统计中的虚拟变量。这与其他编码方案截然不同,其他编码方案都允许多个位的值为1。

首先,让我们来看一个示例,来理解one-hot编码。下表是比较以二进制,格雷码和单引号表示的从0到7的数字表示形式的表格:

十进制码 | 二进制码 | 二进制格雷码 | One-Hot码 |:--:|:--:|:--:|:--:| 0 | 000 | 000 | 0000000 1 | 001 | 001 | 0000001 2 | 010 | 011 | 0000010 3 | 011 | 010 | 0000100 4 | 100 | 110 | 0001000 5 | 101 | 111 | 0010000 6 | 110 | 101 | 0100000 7 | 111 | 100 | 1000000

实际上,对于很多问题,在同一维度中存在若干种可能性且这个可能性是互斥的。比如上面的数字ID的问题,我们可以提出这样的问题:“这是数字1吗?”、“这是2吗?”,...,“这是数字7吗?”。我们使用0表示false,1表示真,那么一旦在向量中命中1,则问题的答案为真。one-hot编码将分类特征转换为一种与分类和回归算法更好地结合的格式。在需要多种数据表示形式的方法中非常有用。例如,某些向量可能对于回归是最佳的(基于以前的返回值近似函数),而某些向量可能对于分类是最佳的(分类为固定的集合/类,通常为二进制)。

给定六种水果并使用顺序编码,为类别值分配一个ID可以得到:[(1, 苹果),(2, 香蕉),(3, 西瓜),(4, 葡萄),(5, 黄桃),(6, 柠檬)]。计算机知道如何表示这些类别,因为它知道如何处理数字。但是,这种编码方法不是很有效,因为它倾向于自然赋予较高的数字更高的权重。说我们的“苹果”类别大于或小于“苹果”类别,或者说将“柠檬”类别添加到“黄桃”将给我们一个类别“偏好水果”,这是没有道理的,因为这些数值不是序数。如果我们以one-hot的方式表示这些类别,则实际上将行替换为列。为此,我们为每个给定类别创建一个布尔列,其中每个列中只有一个列的值可以为1:

苹果 | 香蕉 | 西瓜 | 葡萄 | 黄桃 | 柠檬 |:--:|:--:|:--:|:--:|:--:|:--:|:--:| 1 | 0 | 0 | 0 | 0 | 0 0 | 1 | 0 | 0 | 0 | 0 0 | 0 | 1 | 0 | 0 | 0 0 | 0 | 0 | 1 | 0 | 0 0 | 0 | 0 | 0 | 1 | 0 0 | 0 | 0 | 0 | 0 | 1

从上表我们可以看到,与其他编码相比,one-hot需要更多位的数数。对于n位数字,one-hot只能表示n个值,而二进制码或格雷码可以使用 $n$ 位数字表示 $2^n$ 个值。

3. 3 python实现

让我们看一个简单的示例(演示效果参见这里),该示例说明如何通过一键编码方案将数据集中的分类列中的值转换为对应的数值。我们将创建一个非常简单的数据集-国家及其ID的列表:

import pandas as pd

ids = [id + 1 for id in range(6)]
fruits = ['苹果', '香蕉', '西瓜', '葡萄', '黄桃', '柠檬']
df = pd.DataFrame(list(zip(ids, fruits)), columns=['ids', 'fruits'])
df.head()

可以得到以下内容

   ids  fruits
0   1    苹果
1   2    香蕉
2   3    西瓜
3   4    葡萄
4   5    黄桃
5   6    柠檬

只需一行代码即可获得:

y = pd.get_dummies(df.fruits)
y.head()

即可得到以下one-hot分组:

. | 柠檬| 苹果| 葡萄| 西瓜| 香蕉| 黄桃 |:--:|:--:|:--:|:--:|:--:|:--:|:--:| 0| 0| 1| 0| 0| 0| 0 1| 0| 0| 0| 0| 1| 0 2| 0| 0| 0| 1| 0| 0 3| 0| 0| 1| 0| 0| 0 4| 0| 0| 0| 0| 0| 1

分类后,我们可以方便地进行表示和叠加,比如我最喜欢的水果是苹果和西瓜,其他的编码需要两个来表示,而使用了one-hot后,只需一个向量即可表示。比如苹果和西瓜的的one-hot编码分别是100000和000010,那么可以将这两个向量合并为100010。由于这个类都有独立的位表示为1,同时在分类时,又不会重复,所以无论出现什么样的选择,都可以实现自由地叠加,而不会遇到任何问题。

4. 4 应用场景

one-hot在机器学习中广泛得使用,尤其是在处理分类化数据(Categorical Data)的问题中。对于分类问题,由于计算机默认缺少分类数据,同时又无法直接使用使用分类数据(如“苹果”或“香蕉”),所以需要进行分类的预处理。大多数机器学习技术和模型都适用于非常有限的使用二进制表示的数据集,比如在CNN中会消耗数据并产生在[0, 1)范围内的结果。所以绝大多数机器学习算法都接收从中提取特征的样本数据(“训练数据”)。一个很好的例子是分类(Classification),其中输入在技术上可以不受限制,但是输出通常限于几个类。在二进制分类的情况下,比如教一个神经网络实现对交通中人和车的进行分类。我们可以将对人的映射为0,对车的映射为1。在大多数情况下,我们希望对其进行预测的训练数据都是分类的,例如上面提到的带有水果的示例。同样,尽管这对我们来说很有意义,但是单词本身对算法没有意义。在这些算法中都可以使用one-hot来表示数据,尽管这不是必需的但往往都非常有效。

5. 5 优缺点

one-hot虽然很流行,但是一样和其他类型的编码一样,即有很多优点,同样也有很多问题。

5.1. 5.1 优点

one-hot编码的优点很多,主要包括以下四点:

  1. 简单有效,能够非常便捷地确定系统的分类状态;
  2. 可以进行状态的叠加;
  3. 运算速度极快;
  4. one-hot实现,在编码层面便于落地;
  5. 对于非法状态也很容易检测到。

5.2. 5.2 缺点

one-hot的唯一缺点就是所需要的编码过长。当有n种状态时,二进制编码只需$log n$位即可,而one-hot需要n位。但是对于现在计算机充分的存储空间,结合算法和模型的优化(比如问题规模的拆分)在大部分场景下,都可以高效地使用one-hot而不会遇瓶颈问题。

6. 6 结论

由于one-hot编码非常简单高效,因此它在计算机科学领域,尤其是机器学习编码问题中广泛流行。现在有大量的研究都是基于此编码,所以从事自然语言处理或相关研究,必需学习并利用好这种编码。

7. 参考资料

[1] Why One-Hot Encode Data in Machine Learning?, https://machinelearningmastery.com/why-one-hot-encode-data-in-machine-learning/ [2] One-Hot Encode Features With Multiple Labels, https://chrisalbon.com/machine_learning/preprocessing_structured_data/one-hot_encode_features_with_multiple_labels/ [3] One-Hot Encoding in Python with Pandas and Scikit-Learn, https://stackabuse.com/one-hot-encoding-in-python-with-pandas-and-scikit-learn/ [4] 数据预处理:独热编码(One-Hot Encoding)和 LabelEncoder标签编码, https://www.cnblogs.com/zongfa/p/9305657.html

results matching ""

    No results matching ""