原文地址:http://www.kdnuggets.com/2015/12/beyond-one-hot-exploration-categorical-variables.html
通过给机器学习算法的每一个类别分配一个整数,将类别变量编码为数值变量。在这里,我们探索转换类别变量的不同方式及其对多维数据的影响。
在机器学习中,数据是国王。用来预测数据对算法和模型很重要,也很有趣,但是机器学习仍然秉承着“garbage-in-garbage-out”。考虑到这一点,让我们看一小部分输入数据:类别变量。
类别变量是表示固定数量的可能性的变量,而不是连续数字的变量。每个值代表那些有限组或类别的一个衡量标准。它们不同于有序变量的地方在于不论类别有多少,从一个类别到另一个类别的距离始终是相等的,而有序变量则存在某种排序规则。例如:
1. 有序变量:低,中,高
2.类别变量:乔治亚,南卡罗来纳,……,纽约
我们后续使用的机器学习算法往往更倾向于使用数字作输入,而非字符串,因此我们需要编写一些方法进行转换。
快速感知:本文反复出现的一个概念就是维度的概念。简单来说,就是数据表中的列数,但是它在最终模型中具有显著的下游效应。在极端情况下,“维度的诅咒(curse of dimensionality)”概念认为在高纬空间内事物会停止正常工作。即使在相对低纬的问题中,具有更多维度的数据集需要更多的参数供模型理解,这意味着需要更多数据才能学好这些参数。如果数据量固定,则只添加额外的维度而不增加数据量会对最终模型的精度造成不利影响。
回到手头的问题:我们想将类别别量编码成数字变量,但是我们关心维度的问题。最容易想到的答案就是给每个类别分配一个整数(假设我们知道所有可能的类别)。这称为顺序编码。它不会为问题增加维度,但是无形中增加了变量可能原本不存在的顺序。
方法
为了进行好坏评估,我写了一个用不同方法测试同一数据集的python脚本。首先概述整个过程:
(1)先收集一个有类别变量的分类问题的数据集
(2)使用一些编码方法将X数据集转换为数值
(3)用scikit-learn的交叉验证分数和BernouliNB()分类器生成数据集的分数(译者注:一种评估方式)。每个数据集重复10x次,并使用所有分数的平均集
(4)存储数据集的维度,平均分数和编码时间,然后生成分数
对UCI数据库的一些数据集,都重复以上过程。使用的数据集如下:
(1)Car Evaluation
(2)Mushrooms
(3)Splice Junctions
我尝试了七种不同的编码方式(4-7的描述来自statsmodel的文档):
(1)Ordinal(序列化):如上所述。
(2)One-Hot:每个类别有一列,根据某条数据时候包含这一类别用1或0填充。
(3)Binary(二进制):首先需要序列化类别,然后将整数转化为二进制编码,再将二进制字符串的数字拆分成单独的列。这较one-hot而言使用更小的维度进行编码,但是有一些距离失真。
(4)Sum:比较给定级别的相关变量的平均值与所有级别上的相关变量的总平均值。也就是说,从第一个k-1级别比到k级别,在本例中,级别1与所有其他级别比较,级别2与所有其他级别比较,级别3与所有其他级别比较。
(5)Polynomial:在类别变量中,k=4级别多项式的系数的趋势是线性、二次或三次的。这里的类别变量假设由基本的等间距的数字变量表示。因此,这种类型的编码仅用于等间距的有序分类变量。
(6)Backward Difference:将一个级别变量的平均数与上一个级别相比较。这种类型的编码适用于标称型变量或有序变量。
(7)Helmert:将一个级别变量的平均数与前面所有级别的平均数相比较。因此,“reverse”这一名称用于对forward Helmert编码加以区分。
结果
结论
这不是一个详尽的研究,但是似乎二进制编码执行更好些,没有明显的维度增加。如预期的一样,有序化执行不理想。
如想查看源代码,添加或建议新数据集或编码方式,请见github,欢迎贡献、评论与建议。