独热编码(one-hot encoding)

原文 https://blog.csdn.net/a595130080/article/details/64442800

一、介绍

在数据处理和特征工程中,经常会遇到类型数据,如性别分为[男,女](暂不考虑其他。。。。),手机运营商分为[移动,联通,电信]等,我们通常将其转为数值带入模型,如[0,1], [-1,0,1]等,但模型往往默认为连续型数值进行处理,这样其实是违背我们最初设计的,也会影响模型效果。

 

独热编码便是解决这个问题,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。

如自然编码为:0,1

独热编码为:10,01           

 

可以理解为对有m个取值的特征,经过独热编码处理后,转为m个二元特征,每次只有一个激活。

 

如数字字体识别0~9中,6的独热编码为:

0000001000

 

二、优点

独热编码的优点为:

1.能够处理非连续型数值特征。 
2.在一定程度上也扩充了特征。比如性别本身是一个特征,经过one hot编码以后,就变成了男或女两个特征。

 

当然,当特征类别较多时,数据经过独热编码可能会变得过于稀疏。

·


三、实现 

我们可以自己根据实际问题实现独热编码,如0~9数字识别中

# labels 变成one-hot encoding, [2] -> [0, 0, 1, 0, 0, 0, 0, 0, 0, 0]

# digit 0 ,  representedas 10

# labels 变成one-hot encoding, [10] -> [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]

            labels =np.array([x[0] for x in labels])          

            one_hot_labels= []

            for numin labels:

                        one_hot= [0.0] * 10

                        ifnum == 10:

                                    one_hot[0]= 1.0

                        else:

                                    one_hot[num]= 1.0

                        one_hot_labels.append(one_hot)

 

 



在sklearn中也有现有的函数可以直接调用:

 

import numpy as np

fromsklearn.preprocessing import OneHotEncoder

 

enc = OneHotEncoder()

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

print"enc.n_values_is:",enc.n_values_

print"enc.feature_indices_is:",enc.feature_indices_

print enc.transform([[0, 1, 1]]).toarray()

 

代码运行结果

enc.n_values_ is: [234]

enc.feature_indices_ is:[0259]

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

 

这里样本有三个维度,第一维有2个取值,第二维有3个取值,第三维有4个取值,也就是enc.n_values_ = [234], 而enc.feature_indices_为维度取值范围累加,则[0, 1, 1]经过编码为:

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

 

1.to_categorical的功能

简单来说,to_categorical就是将类别向量转换为二进制(只有0和1)的矩阵类型表示。其表现为将原有的类别向量转换为独热编码的形式。先上代码看一下效果:


 
 
  1. from keras.utils.np_utils import *
  2. #类别向量定义
  3. b = [ 0, 1, 2, 3, 4, 5, 6, 7, 8]
  4. #调用to_categorical将b按照9个类别来进行转换
  5. b = to_categorical(b, 9)
  6. print(b)
  7. 执行结果如下:
  8. [ [1. 0. 0. 0. 0. 0. 0. 0. 0.]
  9. [ 0. 1. 0. 0. 0. 0. 0. 0. 0.]
  10. [ 0. 0. 1. 0. 0. 0. 0. 0. 0.]
  11. [ 0. 0. 0. 1. 0. 0. 0. 0. 0.]
  12. [ 0. 0. 0. 0. 1. 0. 0. 0. 0.]
  13. [ 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  14. [ 0. 0. 0. 0. 0. 0. 1. 0. 0.]
  15. [ 0. 0. 0. 0. 0. 0. 0. 1. 0.]
  16. [ 0. 0. 0. 0. 0. 0. 0. 0. 1.]]

 

to_categorical最为keras中提供的一个工具方法,从以上代码运行可以看出,将原来类别向量中的每个值都转换为矩阵里的一个行向量,从左到右依次是0,1,2,...8个类别。2表示为[0. 0. 1. 0. 0. 0. 0. 0. 0.],只有第3个为1,作为有效位,其余全部为0。

2.one_hot encoding(独热编码)介绍

独热编码又称为一位有效位编码,上边代码例子中其实就是将类别向量转换为独热编码的类别矩阵。也就是如下转换:


 
 
  1. 0 1 2 3 4 5 6 7 8
  2. 0=> [ 1. 0. 0. 0. 0. 0. 0. 0. 0.]
  3. 1=> [ 0. 1. 0. 0. 0. 0. 0. 0. 0.]
  4. 2=> [ 0. 0. 1. 0. 0. 0. 0. 0. 0.]
  5. 3=> [ 0. 0. 0. 1. 0. 0. 0. 0. 0.]
  6. 4=> [ 0. 0. 0. 0. 1. 0. 0. 0. 0.]
  7. 5=> [ 0. 0. 0. 0. 0. 1. 0. 0. 0.]
  8. 6=> [ 0. 0. 0. 0. 0. 0. 1. 0. 0.]
  9. 7=> [ 0. 0. 0. 0. 0. 0. 0. 1. 0.]
  10. 8=> [ 0. 0. 0. 0. 0. 0. 0. 0. 1.]

那么一道思考题来了,让你自己编码实现类别向量向独热编码的转换,该怎样实现呢?

以下是我自己粗浅写的一个小例子,仅供参考:


 
 
  1. def convert_to_one_hot(labels, num_classes):
  2. #计算向量有多少行
  3. num_labels = len(labels)
  4. #生成值全为0的独热编码的矩阵
  5. labels_one_hot = np.zeros((num_labels, num_classes))
  6. #计算向量中每个类别值在最终生成的矩阵“压扁”后的向量里的位置
  7. index_offset = np.arange(num_labels) * num_classes
  8. #遍历矩阵,为每个类别的位置填充1
  9. labels_one_hot.flat[index_offset + labels] = 1
  10. return labels_one_hot
  11. #进行测试
  12. b = [ 2, 4, 6, 8, 6, 2, 3, 7]
  13. print(convert_to_one_hot(b, 9))
  14. 测试结果:
  15. [ [0. 0. 1. 0. 0. 0. 0. 0. 0.]
  16. [ 0. 0. 0. 0. 1. 0. 0. 0. 0.]
  17. [ 0. 0. 0. 0. 0. 0. 1. 0. 0.]
  18. [ 0. 0. 0. 0. 0. 0. 0. 0. 1.]
  19. [ 0. 0. 0. 0. 0. 0. 1. 0. 0.]
  20. [ 0. 0. 1. 0. 0. 0. 0. 0. 0.]
  21. [ 0. 0. 0. 1. 0. 0. 0. 0. 0.]
  22. [ 0. 0. 0. 0. 0. 0. 0. 1. 0.]]

 

3.源码解析

to_categorical在keras的utils/np_utils.py中,源码如下:


 
 
  1. def to_categorical(y, num_classes=None, dtype='float32'):
  2. """Converts a class vector (integers) to binary class matrix.
  3. E.g. for use with categorical_crossentropy.
  4. # Arguments
  5. y: class vector to be converted into a matrix
  6. (integers from 0 to num_classes).
  7. num_classes: total number of classes.
  8. dtype: The data type expected by the input, as a string
  9. (`float32`, `float64`, `int32`...)
  10. # Returns
  11. A binary matrix representation of the input. The classes axis
  12. is placed last.
  13. # Example
  14. ```python
  15. # Consider an array of 5 labels out of a set of 3 classes {0, 1, 2}:
  16. > labels
  17. array([0, 2, 1, 2, 0])
  18. # `to_categorical` converts this into a matrix with as many
  19. # columns as there are classes. The number of rows
  20. # stays the same.
  21. > to_categorical(labels)
  22. array([[ 1., 0., 0.],
  23. [ 0., 0., 1.],
  24. [ 0., 1., 0.],
  25. [ 0., 0., 1.],
  26. [ 1., 0., 0.]], dtype=float32)
  27. ```
  28. """
  29. #将输入y向量转换为数组
  30. y = np.array(y, dtype= 'int')
  31. #获取数组的行列大小
  32. input_shape = y.shape
  33. if input_shape and input_shape[ -1] == 1 and len(input_shape) > 1:
  34. input_shape = tuple(input_shape[: -1])
  35. #y变为1维数组
  36. y = y.ravel()
  37. #如果用户没有输入分类个数,则自行计算分类个数
  38. if not num_classes:
  39. num_classes = np.max(y) + 1
  40. n = y.shape[ 0]
  41. #生成全为0的n行num_classes列的值全为0的矩阵
  42. categorical = np.zeros((n, num_classes), dtype=dtype)
  43. #np.arange(n)得到每个行的位置值,y里边则是每个列的位置值
  44. categorical[np.arange(n), y] = 1
  45. #进行reshape矫正
  46. output_shape = input_shape + (num_classes,)
  47. categorical = np.reshape(categorical, output_shape)
  48. return categorical

看过源码之后,确实觉得自己的代码还需要完善。框架里的一些api,我们可以先自己想着来写,然后和源码进行对比学习,这是一个很好的学习方法。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值