4.2 处理类别数据
到目前为止,我们仅学习了处理数值型数据的方法。然而,在真实数据集中,经常会出现一个或多个类别数据的特征列。我们在讨论类别数据时,又可以进一步将他们划分为标称特征(nominal feature)和有序特征(ordinal feature)。可以将有序特征理解为类别的值是有序的或者是可以排序的。如T恤衫的尺寸就是一个有序特征,因为我们可以为其值排序XL>L>M。相反,标称数据则不具备排序的特性。继续刚才。例子,我们可以将T恤衫的颜色看作一个标称特征,因为一般说来,对颜色进行比较,如红色大于蓝色这种说法是不符合常理的。
在探索类别数据的处理技巧之前,我们先构造一个数据集来用来描述问题:
从代码的输出结果中可以看到,我们新构造的DataFrame分别包含一个标称特征(颜色)、一个有序特征(尺寸)以及一个数值特征(价格)。类标(此处假定我们构造的数据集用于监督学习)存储在最后一列。在本书中,我们讨论的分类学习算法中均不使用有序信息作为类标。
4.2.1 有序特征的映射
为了确保学习算法可以正确地使用有序特征,我们需要将类别字符串转换为整数。但是,没有一个适当的方法可以自动将尺寸特征转换为正确的顺序。由此,需要我们手工定义相应的映射。在接下来的例子中,假设我们了解特征值间的差异,如:XL=L+1=M+2。
如果在后续过程中需要将整数值还原为有序字符串,可以简单地定义一个逆映射字典:inv_size_mapping={v:k for k,v in size_mappping.items()},与前面用到的size_mapping类似,可以通过pandas的map方法将inv_size_mapping应用于经过转换的特征列上。
4.2.2 类标的编码
许多机器学习库要求类标以整数值的方式进行编码。虽然scikit-learn中大多数分类预估器都会在内部将类标转换为整数,但通过将类标转换为整数序列能够从技术角度避免某些问题的产生,在实践中这被认为是一个很好的做法。为了对类标进行编码,可以采用与前面讨论的有序特征映射相类似的方式。要清楚一点,类标并不是有序的,而且对于特定的字符串类标,赋予哪个整数值给它对我们来说并不重要。因此,我们可以简单地以枚举的方式从0开始设定类标。
接下来,我们可以使用映射字典将类标转换为整数:
我们可以通过下列代码将映射字典中的键一值对倒置,以将换转过的类标还原回原始的字符串表示:
此外,使用scikit-learn中的LabelEncoder类可以更加方便地完成对类标的整数编码工作:
请注意:fit_transform方法相当于分别调用fit和transform方法的快捷方式,我们还可以使用inverse_transform方法将整数类标还原为原始的字符串表示:
4.2.3 标称特征上的独热编码
在前面小节中,我们曾使用字典映射的方法将有序的尺寸特征转换为整数。由于scikit-learn的预估器将类标作为无序数据进行处理,可以使用scikit-learn中的LabelEncoder类将字符串类标转换为整数。同样,也可以用此方法处理数据集中标称数据格式的color列,代码如下:
执行上述代码,NumPy数组X的第一列现在被赋予新的color值,具体编码结果如下:
·blue→0
·green→1
·red→2
如果我们就此打住,直接将得到的数组导入分类器,那么就会犯处理类别数据时最常见的错误。读者发现问题所在了吗?虽然颜色的值并没有特定的顺序,但是学习算法将假定green大于blue、red大于green。虽然算法的这一假定不太合理,但最终还是能够生成有用的结果。然而,这个结果可能不是最优的。
解决此问题最常用的方法就是独热编码(one-hot encoding)技术。这种方法的理念就是创建一个新的虚拟特征(dummy feature),虚拟特征的每一列各代表标称数据的一个值。在此,我们将color特征转换为三个新的特征:blue、green以及red。此时可以使用二进制值来标识样本的颜色。例如,蓝色样本可以标识为:blue=1,green=0,以及red=0。此编码转换操作可以使用scikit-learn.proprocessing模块中的OneHotEncoder来实现:
当我们初始化OneHotEncoder对象时,需要通过categorical_features参数来选定我们要转换的特征所在的位置(如color是特征矩阵X的第1列)。默认情况下,当我们调用OneHotEncoder的transform方法时,它会返回一个稀疏矩阵。出于可视化的考虑,我们可以通过toarray方法将其转换为一个常规的NumPy数组。稀疏矩阵是存储大型数据集的一个有效方法,被许多scikit-learn函数所支持,特别是在数据包含很多零值时非常有用。为了略过toarry的使用步骤,我们也可以通过在初始化阶段使用OneHotEncoder(…,sparse=False)来返回一个常规的Numpy数组。
另外,我们可以通过pandas中的get_dummies方法,更加方便地实现独热编码技术中的虚拟特征。当应用于DataFrame数据时,get_dummies方法只对字符串列进行转换,而其他的列保持不变。