独热编码这东西很有趣,和数字电路里面的格雷码有异曲同工之妙!其实也很正常,统计机器学习特别是自然语言处理方面的兴起正是引入了通信领域的数学模型,这段历史很有趣,可以看看吴军老师的《数学之美》。

我们在处理机器学习数据的时候经常会见到离散特征的数据,例如水果的颜色、人名等,离散特征的挑战在于不是连续的方式,这导致很难用数字去描述,所以引入独热编码进行处理。

独热编码,One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。

One-Hot编码是分类变量作为二进制向量的表示。这首先要求将分类值映射到整数值。然后,每个整数值被表示为二进制向量,除了整数的索引之外,它都是零值,它被标记为1。

例如:

祖国特征:["中国","美国,"法国"](这里N=3):

中国  =>  100

美国  =>  010

法国  =>  001

可以看到:特征值有几个,独热编码就有几位,重点在不同编码之间的距离上面。

在回归,分类,聚类等机器学习算法中,特征之间距离的计算或相似度的计算是非常重要的,而我们常用的距离或相似度的计算都是在欧式空间的相似度计算,计算余弦相似性,基于的就是欧式空间。

而我们使用one-hot编码,将离散特征的取值扩展到了欧式空间,离散特征的某个取值就对应欧式空间的某个点。

将离散型特征使用one-hot编码,确实会让特征之间的距离计算更加合理。

但是,应该可以看到,处理过后的是稀疏矩阵,scikit-learn提供了处理稀疏矩阵的紧凑表示方法,sparse设为Ture表示启用稀疏矩阵来处理

所以下面来看代码:

# ——创建时间:2019.3.8——
# 类别变量表示
# 独热编码与稀疏矩阵表示方法
from sklearn.feature_extraction import DictVectorizer

# 列出了著名的一些AI专家的名字
data = [{'name':'Alan','born':1912,'died':1954},
        {'name':'Herbert','born':1916,'deid':2001},
        {'name':'Jacek Karpinski','born':1927,'deid':2010},
        {'name':'Marvin Minsky','born':1927,'died':2016}]

# sparse设为Ture表示启用稀疏矩阵来处理
vec = DictVectorizer(sparse=True,dtype=int)
one_hot = vec.fit_transform(data)
print(one_hot)

输出结果:

  (0, 0)	1912
  (0, 2)	1954
  (0, 3)	1
  (1, 0)	1916
  (1, 1)	2001
  (1, 4)	1
  (2, 0)	1927
  (2, 1)	2010
  (2, 5)	1
  (3, 0)	1927
  (3, 2)	2016
  (3, 6)	1

输出很奇怪,没有达到预期效果,找到bug,是数据deid和died相互混淆,这虽然是人工出错,但也属于提前数据尚未预处理好,洗干净。

修改后如下:

  (0, 0)	1912
  (0, 1)	1954
  (0, 2)	1
  (1, 0)	1916
  (1, 1)	2001
  (1, 3)	1
  (2, 0)	1927
  (2, 1)	2010
  (2, 4)	1
  (3, 0)	1927
  (3, 1)	2016
  (3, 5)	1

注意:某些机器学习算法,比如决策树,本身就可以处理离散特征在这些情况下不需要使用独热编码!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐