working-with-categorical-variables

分类变量处理

分类变量是经常遇到的问题。一方面它们提供了信息;另一方面,它们可能是文本形式——纯文字或者与文字相关的整数——就像表格的索引一样。

因此,我们在建模的时候往往需要将这些变量量化,但是仅仅用简单的id或者原来的形式是不行的。因为我们也需要避免在上一节里通过阈值创建二元特征遇到的问题。如果我们把数据看成是连续的,那么也必须解释成连续的。

Getting ready

这里boston数据集不适合演示。虽然它适合演示二元特征,但是用来创建分类变量不太合适。因此,这里用iris数据集演示。

解决问题之前先把问题描述清楚。假设有一个问题,其目标是预测花萼的宽度;那么花的种类就可能是一个有用的特征。

首先,让我们导入数据:

In [1]:
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data
y = iris.target

现在Xy都获得了对应的值,我们把它们放到一起:

In [2]:
import numpy as np
d = np.column_stack((X, y))

How to do it...

下面我们把花类型y对应那一列转换成分类特征:

In [9]:
from sklearn import preprocessing
text_encoder = preprocessing.OneHotEncoder()
text_encoder.fit_transform(d[:, -1:]).toarray()[:5]
Out[9]:
array([[ 1.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.]])

How it works...

这里,编码器为每个分类变量创建了额外的特征,转变成一个稀疏矩阵。矩阵是这样定义的:每一行由0和1构成,对应的分类特征是1,其他都是0。用稀疏矩阵存储数据很合理。

text_encoder是一个标准的scikit-learn模型,可以重复使用:

In [12]:
text_encoder.transform(np.ones((3, 1))).toarray()
Out[12]:
array([[ 0.,  1.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  1.,  0.]])

There's more...

在scikit-learn和Python库中,还有一些方法可以创建分类变量。如果你更倾向于用scikit-learn,而且分类编码原则很简单,可以试试DictVectorizer。如果你需要处理更复杂的分类编码原则,patsy是很好的选择。

DictVectorizer

DictVectorizer可以将字符串转换成分类特征:

In [13]:
from sklearn.feature_extraction import DictVectorizer
dv = DictVectorizer()
my_dict = [{'species': iris.target_names[i]} for i in y]
dv.fit_transform(my_dict).toarray()[:5]
Out[13]:
array([[ 1.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.]])

Python的词典可以看成是一个稀疏矩阵,它们只包含非0值。

Pasty

patsy是另一个分类变量编码的包。经常和StatsModels一起用,patsy可以把一组字符串转换成一个矩阵。

这部分内容与 scikit-learn关系不大,跳过去也没关系。

例如,如果xy都是字符串,dm = patsy.design_matrix("x + y")将创建适当的列。如果不是,C(x)将生成一个分类变量。

例如,初看iris.target,可以把它当做是一个连续变量。因此,用下面的命令处理:

In [16]:
import patsy
patsy.dmatrix("0 + C(species)", {'species': iris.target})
Out[16]:
DesignMatrix with shape (150, 3)
  C(species)[0]  C(species)[1]  C(species)[2]
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
              1              0              0
  [120 rows omitted]
  Terms:
    'C(species)' (columns 0:3)
  (to view full data, use np.asarray(this_obj))