问题1、机器学习或深度学习中如何有效处理分类数据?

1 分类数据传统处理方法

分类(Categorical)特征常被称为离散特征、分类特征,数据类型通常是object类型,而机器学习模型通常只能处理数值数据,所以需要对Categorical数据转换成Numeric特征。

Categorical特征又有两类,我们需要理解它们的具体含义并进行对应的转换。

(1)有序(Ordinal)类型:

这种类型的Categorical存在着自然的顺序结构,如果你对Ordinal 类型数据进行排序的话,可以是增序或者降序,比如在衣服型号这个特征中具体的值可能有:S、M、L、XL等衣服尺码,其中S:(Small)表示小 ,M(Middle)表示中 ,L(Large)表示大,XL(extra large)表示加大尺码,它们之间有XL>L>M>S的大小关系。

(2)常规(Nominal)类型或无序类型:

这种是常规的Categorical类型,不能对Nominal类型数据进行排序,这类特征无谁大谁小之分。比如颜色特征可能的值有:red、yellow、blue、black等,我们不能说red>yellow>blue>black。

对于Ordinal和Nominal类型数据有不同的方法将它们转换成数字。

1.1 处理有序类型

对于Ordinal类型数据可以使用OrdinalEncoder、LabelEncoder进行编码处理,功能相同,都将每一个类别的特征转换成一个新的整数(0到类别数n-1之间)。例如S、M、L、XL等衣服尺码这四个类别进行OrdinalEncoder(或LabelEncoder)处理后会映射成0、1、2、3,这样数据间的自然大小关系也会保留下来。以下数据集data_set共有4列,这4列从左到右分别表示型号、颜色、性别、标签。其中型号为有序类别,其它都是常规类别。这些都是字符,现在利用sklearn中预处理模块preprocessing,把型号转换为数字,具体代码如下:

(1)导入数据

from sklearn.preprocessing import OrdinalEncoder,LabelEncoder,OneHotEncoder
import numpy as np
 
import numpy as np
 
data_set=np.array([['L','red','Female','yes'],['M','red','Male','no'],['M','yellow','Female','yes'],['XL','blue','Male','no']])

data_set的结果如下

array([[‘L’, ‘red’, ‘Female’, ‘yes’],

[‘M’, ‘red’, ‘Male’, ‘no’],

[‘M’, ‘yellow’, ‘Female’, ‘yes’],

[‘XL’, ‘blue’, ‘Male’, ‘no’]], dtype=’

(2)进行转换

x1 = data_set[:,0]           #获取第1列数据
x1=x1.reshape(-1,1)          #转换为2D,transform传递的X一定要是2D的,即                                       #(samples,features)
oe = OrdinalEncoder()        #实例化
ord=oe.fit(x1)               #导入数据
oe.transform(x1)             #转换后的数据为:array([[0],[1],[1],[]2])
oe.categories_               #属性.categories_查看类别特征究竟有多少类别

1.2 处理常规类型

1.1节用OrdinalEncoder、OrdinalEncoder把分类变量型号转换为数字,同样可以把颜色、性别、标签等这些属于常规类型的特征转换为整数(0到类别数n-1之间)。具体代码如下:

1.2.1 把标签转换为数字

使用LabelEncoder把标签特征转换为数字。

y = data_set[:,-1]        #获取最后一列数据
le = LabelEncoder()       #实例化
le.fit_transform(y)       #也可以直接fit_transform一步到位
le.classes_               #属性.classes_查看标签中究竟有多少类别['no', 'yes']
label                     #查看获取的结果label[1, 0, 1, 0]

1.2.2 把颜色、性别转换为数字

x2 = data_set[:,1:-1]        #获取第2、3列数据
oe = OrdinalEncoder()        #实例化
ord=oe.fit_transform(x2)     #导入数据并进行转换
print(ord) 

运行结果如下:

[[1. 0.]

[1. 1.]

[2. 0.]

[0. 1.]]

在表示颜色这一列中,我们使用[0,1,2]代表了三个不同的颜色,然而这种转换是正确的吗?[0,1,2]这三个数字在算法看来,是连续且可以计算的,这三个数字相互不等,有大小,甚至有着可以相加相乘的联系。所以算法会把颜色,性别这样的常规分类特征,都误会成是有序特征这样的分类特征,把本来互相平等、独立的颜色特征误认为有大小的区分,如blue>yellow>red,blue的重要性是yellow颜色的2倍,这显然是不合理的。因此,我们把分类转换成数字的时候,忽略了数字中自带的数学性质,所以给算法传达了一些不准确的信息,而这会影响我们的建模。如何解决这个问题?

对于Nominal类型数据可以使用OneHotEncoder进行编码处理,尽量向算法传达最准确的信息。

1.2.3 使用OneHotEncoder方法

对于常规类别特征采用独热编码(One-Hot)方式处理,可以保证特征的基本属性,向算法专递最准确的信息。one-hot如何做到这点的呢?首先我们来了解一下one-hot编码的原理。

独热编码会为每个离散值创建一个哑特征(dummy feature)。什么是哑特征呢?举例来说,对于‘颜色’这一特征中的‘blue’,我们将其编码为[blue=1,yellow=0,red=0],同理,对于‘yellow’,我们将其编码为[blue=0,yellow=1,red=0],特点就是向量只有一个1,其余均为0,故称之为one-hot。即把颜色特征转换成如下表示:

图1-1 one-hot编码示意图

从图1-1可知,独热编码进行了如下转换:

①把字符类型转换为数字类型。

②把一个字段(颜色字段)变成3个字段(字段个数为颜色的类别总数)

③对新创建的3个字段,颜色对应位置的值置为1,其它2列位置的都是0。

这么做的目的是为了保证每一个离散取值的“无序性、公平性、彼此正交性”。

下面我们用代码实现颜色和性别字段的one-hot转换。

(1)把字符转换为数字

x2 = data_set[:,1:-1]        #获取第2、3列数据
oe=OrdinalEncoder()          #实例化
x2=oe.fit_transform(x2)      #先把字符转换为数字型
print(x2)

打印结果如下:

[[1. 0.]

[1. 1.]

[2. 0.]

[0. 1.]]

(2)把数字转换为独热编码

oh = OneHotEncoder(categories='auto')        #实例化
x3=oh.fit_transform(x2).toarray()            #导入数据并进行转换
print(x3)

打印结果如下:

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

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

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

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

前3列为颜色,后2列为性别。

【说明】OneHotEncoder是sklearn方法,pandas有一个对于方法,即get_dummies,它可直接把字符转换为oneHot编码。具体使用可参考如下博客:

https://blog.csdn.net/maymay_/article/details/80198468

对于Nominal类型数据可以使用独热编码(OneHotEncoder)有其合理的一面,但也有很多不足,如当遇到大数据,一个特征的类别很多几百,甚至几千或更多,而且这样的特征还有很多,如此一来,把这些特征转换成one-hot编码后,特征数将非常巨大!此外,这种方法只是简单把类别数据转换成0或1,无法准确反应这些特征内容隐含的一些规则或这些类别的分布信息,如一个表示地址的特征,可能包括北京、上海、杭州、美国纽约、华盛顿、洛杉矶,东京、大阪等等,这些属性具有一定分布特性,北京、上海、杭州之间的距离较近,而上海与纽约之间的距离应该比较远,诸如此类问题,one-hot是无法表示的。

是否有更有好、更有效的处理方法呢?有,就是接下来将介绍的Learned Embedding方法。

(以下内容待续)

2、使用Embendding方法处理分类数据

2.1传统处理方法的不足

2.2 Learned Embedding方法简介

2.3 Learned Embedding方法的巨大威力

3、简单实例:使用不同方法实现机器学习