深度学习笔记(十二)---One-hot编码

在学习语义分割过程中,最后的逐像素分类网络中,对像素进行分类时使用了one-hot编码,这也是现分类任务中常用的一种分类方式。那么什么是one-hot编码呢?为什么使用One-hot呢?

One-hot 编码:称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。One-Hot编码是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值。然后,每个整数值被表示为二进制向量,除了整数的索引之外,它都是零值,它被标记为1。

自然状态码为:000,001,010,011,100,101

独热编码为:000001,000010,000100,001000,010000,100000

可以这样理解,对于每一个特征,如果它有m个可能值,那么经过独热编码后,就变成了m个二元特征。并且,这些特征互斥,每次只有一个激活。因此,数据会变成稀疏的。

这样做的好处主要有:

  • 解决了分类器不好处理属性数据的问题
  • 在一定程度上也起到了扩充特征的作用

原因:使用One-hot的直接原因是现在多分类cnn网络的输出通常是softmax层(为什么使用softmax?),而它的输出是一个概率分布,从而要求输入的标签也以概率分布的形式出现,进而算交叉熵之类。

下面通过python手动实现One-hot:

#展示标签生成one-hot向量的过程
import numpy as np
labels_dense=np.asarray([0,3,2,3,1,1]) #要展示的标签

num_labels = labels_dense.shape[0]
num_classes=4
index_offset = np.arange(num_labels) * num_classes
labels_one_hot = np.zeros((num_labels, num_classes))
labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1 
#将标签对应的向量位置置1(拉平以后对应1的位置为0,7,10,15,17,21)
#flat():1-D iterator over the array,raval:拉平向量

print(labels_one_hot)
#横着看,0对应着第一行的第一个数为1,第一个3对应着第二行的第四个数为1

结果如下: 

[[1. 0. 0. 0.]
 [0. 0. 0. 1.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]
 [0. 1. 0. 0.]
 [0. 1. 0. 0.]]

有人使用sklearn实现One-hot编码,这里摘抄一下,代码如下:

from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder()

>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])  

>>> enc.n_values_
array([2, 3, 4])

>>> enc.feature_indices_
array([0, 2, 5, 9])

>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  1.,  0.,  0.]])
enc.fit([[ 1., 0., 0., 1., 0., 0., 1.,  0., 0.]]) 

这个fit中,所有的数组第一个元素取值分别为:0,1,0,1(黄色标注的),最大为1,且为两种元素(0,1),说明用2个状态位来表示就可以了,且该维度的value值为2(该值只与最大值有关系,最大值为1)

所有的数组第二个元素取值分别为:0,1,2,0(红色标注的),最大为2,且为两种元素(0,1,2),说明用3个状态位来表示就可以了,且该维度的value值为3(该值只与最大值有关系,最大值为2)

所有的数组第三个元素取值分别为:3,0,1,2(天蓝色标注的),最大为3,且为两种元素(0,1,2,3),说明用4个状态位来表示就可以了,且该维度的value值为4(该值只与最大值有关系,最大值为4)

所以整个的value值为(2,3,4),这也就解释了 enc.n_values_等于array([2,3,4])的原因。而enc.feature_indices_则是特征索引,该例子中value值为(2,3,4),则特征索引从0开始,到2的位置为第一个,到2+3=5的位置为第二个,到2+3+4的位置为第三个,索引为array([0,2,5,9])

那么接下来理解

>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  1.,  0.,  0.]])

这个就好办了,enc.transform就是将[0,1,1]这组特征转换成one hot编码,toarray()则是转成数组形式。[0,1,1],
第一个元素是0,由于之前的fit的第一个维度为2(有两种表示:10,01.程序中10表示0,01表示1),所以用1,0表示用黄色标注);
第二个元素是1,由于之前的fit的第二个维度为3(有三种表示:100,010,001.程序中100表示0,010表示1,001表示2),所以用0,1,0表示用红色标注);
第三个元素是1,由于之前的fit的第三个维度为4(有四种表示:1000,0100,0010,0001.程序中1000表示0,0100表示1,0010表示2,0001表示3),
所以用0,1,0,0(用天蓝色标注)表示。综上所述:[0,1,1]就被表示为array([[ 1., 0., 0., 1., 0., 0., 1., 0., 0.]])。
>>> import numpy
>>> import scipy
>>> import sklearn
>>> from sklearn.preprocessing import OneHotEncoder
>>> enc = OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])  
#一个4行3列的数组,即有4个样本,3个特征;
>>> enc.n_values_#每个特征的取值个数(第一列共有2个取值,第二列有3个,第三列有4个)
array([2, 3, 4])
>>> enc.feature_indices_
array([0, 2, 5, 9])#独热编码后每个特征开始和结束的下标;
[0,2,5,9]中的四个数的间距是[2,3,4];
相当于给出9位数,前2位截取给第一个特征,
这2位数的开始下标是0结束下标是2;中间3位数截取给第二个特征,
这3位数的开始下标接着上面即从2开始到5结束....
>>> enc.transform([[0, 1, 1]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  1.,  0.,  0.]])
#对新拿到的[0,1,1]做独热编码,即有第一列是[1,0],
第二列是[0,1,0],第三列是[0,1,0,0],
所以最终拼在一起得到它的独热编码就是[1,0,0,1,0,0,1,0,0]

 

我们常常也使用One-hot编码处理离散型特征,具体原因参见博客:One-hot编码及数据归一化

 

 

 

你可能感兴趣的:(深度学习笔记,知识点)