用scikit-learn做数据预处理

数据预处理是进行机器学习的必要环节,对原始数据进行加工,比如标准化、归一化、二进制化、特征编码、插补缺失值、生成多项式特征等。

scikit-learn 是 Python 下的机器学习工具包,集成了预处理、降维、聚类、分类等方法。我们用此工具来介绍数据预处理。

主要应用的是 preprocessing 类。

标准化 Standardization

常用的标准化方法为 z-score 法,目的是将传入的矩阵变为每列均值为0、方差为1的标准型,因为机器学习中的函数许多是以0为中心的,例如 sigmoid 函数,方差为1可以使数据分布均匀,防止某个特征数据过大影响模型的训练。

z-score 公式

我们用 sklearn 中的 preprocessing 类中的 scale 方法简单进行标准化。

>>> from sklearn import preprocessing
>>> import numpy as np
>>> X = np.array([[ 1., -1.,  2.],
...               [ 2.,  0.,  0.],
...               [ 0.,  1., -1.]])
>>> X_scaled = preprocessing.scale(X)

>>> X_scaled                                          
array([[ 0.  ..., -1.22...,  1.33...],
       [ 1.22...,  0.  ..., -0.26...],
       [-1.22...,  1.22..., -1.06...]])

或者可以将计算均值和方差与转换的步骤分开。

>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)

>>> scaler.transform(X)                               
array([[ 0.  ..., -1.22...,  1.33...],
       [ 1.22...,  0.  ..., -0.26...],
       [-1.22...,  1.22..., -1.06...]])

fit 是计算过程,transform 是转换过程。transform 的一个好处是可以继续使用 fit 的数据,例如 transform 训练数据之后之后可以直接 transform 测试数据。

有时标准化时要求把数据缩放到某一个范围中,preprocessing 类也提供了 MinMaxScaler 方法,设置 MinMaxScaler 的参数 feature_range=(min, max) 。
当然最常用的就是(0,1)范围。

>>> X_train = np.array([[ 1., -1.,  2.],
...                     [ 2.,  0.,  0.],
...                     [ 0.,  1., -1.]])
...
>>> min_max_scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))
>>> X_train_minmax = min_max_scaler.fit_transform(X_train)
>>> X_train_minmax
array([[ 0.5       ,  0.        ,  1.        ],
       [ 1.        ,  0.5       ,  0.33333333],
       [ 0.        ,  1.        ,  0.        ]])
归一化 Normalization

归一化是将每个样本缩放到单位范数(可以粗略地理解为向量的函数)的过程。如果后面要使用如二次型(点积)或者其它核方法计算两个样本之间的相似性这个方法会很有用。归一化的计算方法是 1除以p-范数。归一化之后的样本的 p-范数等于1。

用scikit-learn做数据预处理_第1张图片
向量的p-范数

preprocessing 类下的 normalize 方法可以直接归一化,并可以选择 l1 范数与 l2 范数,默认是 l2 范数。

>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]
>>> X_normalized = preprocessing.normalize(X, norm='l2')

>>> X_normalized                                      
array([[ 0.40..., -0.40...,  0.81...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.  ...,  0.70..., -0.70...]])

normalize 也同样有 fit 方法与 transform 方法。

>>> normalizer = preprocessing.Normalizer().fit(X)  # fit does nothing
>>> normalizer
Normalizer(copy=True, norm='l2')

>>> normalizer.transform(X)                            
array([[ 0.40..., -0.40...,  0.81...],
       [ 1.  ...,  0.  ...,  0.  ...],
       [ 0.  ...,  0.70..., -0.70...]])
.
>>> normalizer.transform([[-1.,  1., 0.]])             
array([[-0.70...,  0.70...,  0.  ...]])
二进制化 Binarization

二进制化的方法是设定一个阈值,样本值比阈值大的为1,小的为0。

文本处理领域愿意使用二进制化,虽然归一化和 TF-IDF 加工的特征表现得更好,但使用二进制化来简化数据更为普遍(可能简化概率推理)。

>>> X = [[ 1., -1.,  2.],
...      [ 2.,  0.,  0.],
...      [ 0.,  1., -1.]]

>>> binarizer = preprocessing.Binarizer().fit(X)  # fit does nothing
>>> binarizer
Binarizer(copy=True, threshold=0.0)

>>> binarizer.transform(X)
array([[ 1.,  0.,  1.],
       [ 1.,  0.,  0.],
       [ 0.,  1.,  0.]])

阈值调整需要设置 threshold 参数,下面代码是设置阈值1.1的情况。

>>> binarizer = preprocessing.Binarizer(threshold=1.1)
>>> binarizer.transform(X)
array([[ 0.,  0.,  1.],
       [ 1.,  0.,  0.],
       [ 0.,  0.,  0.]])
类别特征编码 Encoding categorical features

比如现在有特征 ["male", "female"] ["from Europe", "from US", "from Asia"],
["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"],
平常我们将特征进行整数编码.

["male", "from US", "uses Internet Explorer"] 编码应该是 [0, 1, 3]

["female", "from Asia", "uses Chrome"]的编码应该是[1,2,1]

但是 scikit-learn 估计器不能直接使用这种整数型的编码,它的输入最好是连续型的,估计器也可能把整数编码特征特征误解为有序的数据,这会有害于模型训练。

类别特征编码用的是 OneHotEncoder 方法,占第几位的特征值就是1,其余为0。例如 ["male", "female"] 有两个特征,male 占第1个位置,剩下的0,male 就是 [1,0],female 就是 [0,1]; ["from Europe", "from US", "from Asia"]有3个特征,"from Europe"就是 [1,0,0],"from US" 就是 [0,1,0],"from Asia"就是 [0,0,1],以此类推。

["male", "from US", "uses Internet Explorer"]的整数编码[0,1,3]的二进制编码就是
[1,0, 0,1,0, 0,0,0,1]。

代码实现用的是 preprocessing 类下的 OneHotEncoder 方法。

>>> enc = preprocessing.OneHotEncoder()
>>> enc.fit([[0, 0, 3], [1, 1, 0], [0, 2, 1], [1, 0, 2]])  
OneHotEncoder(categorical_features='all', dtype=<... 'numpy.float64'>,
       handle_unknown='error', n_values='auto', sparse=True)
>>> enc.transform([[0, 1, 3]]).toarray()
array([[ 1.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  1.]])
插补缺失值 Imputation of missing values

以往对于数据中有丢失值的情况,做法是把该数据所在行和列都删掉,这样的后果是容易丢失重要的数据。

imputer 的方法利用平均值、中位数或出现频率最高的数据对缺失的数据进行填补。代码如下,NaN 即位丢失的值。

>>> import numpy as np
>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
Imputer(axis=0, copy=True, missing_values='NaN', strategy='mean', verbose=0)
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))                           
[[ 4.          2.        ]
 [ 6.          3.666...]
 [ 7.          6.        ]]

strategy 告诉了本代码用 mean 平均值找补,fit 是用它括号里的数据计算平均值,transform 是应用变换。

生成多项式特征 Generating polynomial features

生成多项式的预处理方式是为了给输入数据增加复杂性。处理后的特征会获得高阶的数据和交叉的数据。

用到的是 preprocessing 下的 PolynomialFeatures 方法。

>>> import numpy as np
>>> from sklearn.preprocessing import PolynomialFeatures
>>> X = np.arange(6).reshape(3, 2)
>>> X                                                 
array([[0, 1],
       [2, 3],
       [4, 5]])
>>> poly = PolynomialFeatures(2)
>>> poly.fit_transform(X)                             
array([[  1.,   0.,   1.,   0.,   0.,   1.],
       [  1.,   2.,   3.,   4.,   6.,   9.],
       [  1.,   4.,   5.,  16.,  20.,  25.]])

PolynomialFeatures(2) 指的是最多生成二次项。
X的特征值由(X1,X2)变成了(1,X1,X2,X12,X1X2,X22)。

你可能感兴趣的:(用scikit-learn做数据预处理)