0%

Scikit-learn Preprocessing data

一些算法(如神经网络和SVM)对数据缩放非常敏感。因此通常的做法是对特征进行调节,使得数据更适合于这些算法 #### Standardization, or mean removal and variance scaling

数据的标准化是预处理中很常见的一个步骤,使得所有特征值都处于均值为0且齐方差的分布;比如单独的对某个数据集做scale处理的话,可以用preprocessing.scale函数

X_scaled = preprocessing.scale(X_train)

如果想对训练集和测试集做相同的scale处理,则可以用StandardScaler

scaler = preprocessing.StandardScaler().fit(X_train)
X_train_new = scaler.transform(X_train)
X_test_new = scaler.transform(X_test)

另一种高效的写法(但注意不要同时独立地对训练集和测试机都进行fit_transform方法,这样相当于两者的标准化方式是不同的):

scaler = preprocessing.StandardScaler()
X_train_new = scaler.fit_transform(X_train)

有时我们会要求将数据scale到[0,1]之间(这种需求一般在为了在方差很小的数据集中仍保持较好的robustness,以及在稀疏矩阵中保留0元素),这时可以用preprocessing.MinMaxScaler(其默认feature_range=(0, 1)

min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train)
X_test_minmax = min_max_scaler.transform(X_test)

如果训练集已经是0中心化或者稀疏矩阵,则可用MaxAbsScaler将数据除以其最大值,使得其标准化到[-1,1]区间内

对于稀疏矩阵,常规的默认参数的标准化方法会破坏其sparseness,但稀疏矩阵的某几个特征的在不同的数量级,这时标准化也是必须要做的

  • 首先可以使用MaxAbsScalermaxabs_scale方法
  • 如果要使用StandardScalerscale方法,则需要参数with_mean=False
  • RobustScaler无法fit稀疏矩阵,但可以用transform方法

对于有较多离群值的数据集,常规的中心化缩放方法可能不太有效,因此可以考虑用上述提到的RobustScaler方法

Scaling vs Whitening:
有时独立地进行中心化标准化数据是不够的,因为下游的机器学习模型会做些特征值之间线性独立的假设,因此这时可以考虑用sklearn.decomposition.PCA并指定参数whiten=True来消除特征值的线性相关

对于核矩阵(kernel matrix)的中心化,可以考虑下KernelCenterer方法

Non-linear transformation

有时为了保持特征值的秩不变,QuantileTransformer 以及quantile_transform提供了一个基于分位数函数的无参数转换,将数据映射到了零到一的均匀分布上,然后这些特征值

比如iris数据集中的sepal length特征,经QuantileTransformer后,其分布接近于之前定义的百分位数

X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
quantile_transformer = preprocessing.QuantileTransformer(random_state=0)
X_train_trans = quantile_transformer.fit_transform(X_train)
X_test_trans = quantile_transformer.transform(X_test)

如果想将任意分布尽可能的转化为高斯分布,并具有稳定的方差和偏态最小化,可以考虑PowerTransformer提供的两种幂转化的方法:Yeo-Johnson transformBox-Cox transform;注:Box-Cox transform只用于正数数据(其中standardize=False表示不进行0均值化和方差标准化)

pt = preprocessing.PowerTransformer(method='box-cox', standardize=False)
pt.fit_transform(X_train)

并需要注意的是:有时PowerTransformer对于一些分布能很好的转化为高斯分布,但是有些分布却不太行,这时需要分布可视化来检查。。。

除了PowerTransformerQuantileTransformer也可将数据map到高斯分布上,只需要加个output_distribution='normal'参数

Normalization

Normalization(归一化)我曾经一度认为是跟Standardization是一样的,但是其是属于Transformer中的一种;normalize函数提供L1/L2范式的归一化操作

X_normalized = preprocessing.normalize(X, norm='l2')

也可通过Normalizer类的Transformer API方法来调用,如:

normalizer = preprocessing.Normalizer().fit(X)  # fit does nothing
normalizer
normalizer.transform(X)
normalizer.transform([[-1.,  1., 0.]])

以上normalizeNormalizer均可适用于密集数组及稀疏矩阵

Encoding categorical features

之前我们处理的一般都是连续特征,而对于分类特征则需要通过一种方式来表示数据;目前最常用的方法是使用one-hot编码(one-hot-encoding)或者N取一编码(one-hot-of-N encoding),也叫虚拟变量(dummy variable)

以OneHotEncoder类(one-hot编码)为例,其是将N个分类的特征转化为N个的新特征,其中某个特征取1,则其他都为0(这也是为啥叫做N取一编码的原因)

将参数设定为handle_unknown='ignore',可以避免遇到未知的分类时所产生的报错,其会自动将编码赋值为0

from sklearn.preprocessing import OneHotEncoder

X = [['male', 'from US', 'uses Safari'], ['female', 'from Europe', 'uses Firefox']]
enc = OneHotEncoder(handle_unknown='ignore').fit(X)
print(enc.get_feature_names())
enc.transform(X).toarray()
>>array([[0., 1., 0., 1., 0., 1.],
         [1., 0., 1., 0., 1., 0.]])

其实平时对于one-hot编码处理,用Pandas包的get_dummies函数更加方便些,如下所示,结果跟OneHotEncoder方法是一样的

import pandas as pd

data = pd.DataFrame(X)
data_dummies = pd.get_dummies(data)
print(data_dummies.columns)
# 提取Numpy数组
data_dummies.values
>>array([[0, 1, 0, 1, 0, 1],
         [1, 0, 1, 0, 1, 0]], dtype=uint8)

Discretization

数据表示的最佳方法不仅取决于数据的语义,还取决于所使用的模型种类

离散化 (Discretization) (有些时候叫quantization 或 binning(分箱))),能够将连续特征划分为离散特征值的方法;例如,用离散化预处理能够向线性模型引入非线性,比如用于决策树

KBinsDiscretizer(K-bins discretization,K-bins离散化)有几个主要参数(了解默认参数,才能看得懂例子):

  • n_bins,分箱数,默认值为5,如果是列表则表示各个特征值的分箱数
  • encode,编码方式,默认值为onehot
    • onehot:返回稀疏矩阵
    • onehot-dense:返回密集矩阵
    • ordinal:返回分箱序号
  • strategy,分箱策略,默认是quantile
    • uniform:等宽分箱
    • quantile:采取quantiled values,因此每个分箱中拥有相同数量的数据点
    • kmeans:每个分箱中的数据点具有相同的1D k均值簇的聚类中心

示例如下:

import numpy as np
X = np.array([[ -3., 5., 15 ],
              [  0., 6., 14 ],
              [  6., 3., 11 ]])
est = KBinsDiscretizer(n_bins=[3, 2, 2], encode='ordinal').fit(X)
est.fit_transform(X)
>>array([[0., 1., 1.],
         [1., 1., 1.],
         [2., 0., 0.]])

上述中,第一个特征值是按照quantile策略分成3等分,那么其间隔np.quantile([-3,0,6],[0,0.333,0.666,1])相当于-1和2,与官方例子解释一致

还有用于binarization(二值化)的Binarizer(有利于下游的概率模型,如伯努利分布(Bernoulli distribution) ),其默认阈值是0,可通过threshold参数定义

binarizer = Binarizer(threshold=5.5)
binarizer.transform(X)
>>array([[0., 0., 1.],
         [0., 1., 1.],
         [1., 0., 1.]])

Generating polynomial features

想要丰富特征表示,特别是对于线性模型而言,可以通过添加原始数据的交互特征(interaction feature)和多项式特征(polynomial feature);但是两者可能在线性模型上对于性能有较大的提升,但是在复杂模型,如SVM和RF中,可能效果并不明显

PolynomialFeatures可以将特征值变成N的多项式(如下则是2次二项式,如果有两个特征[a,b],则对应的多项式特征则是[1, a, b, a^2, ab, b^2]

from sklearn.preprocessing import PolynomialFeatures

X = np.arange(6).reshape(3, 2)
poly = PolynomialFeatures(2)
poly.fit_transform(X)

Custom transformers

对于一些自定义的转化器,比如将输入数据进行log1plog1p = log(x+1))转化,使偏差较大的数据集在转化后更好地符合高斯分布

import numpy as np
from sklearn.preprocessing import FunctionTransformer
transformer = FunctionTransformer(np.log1p, validate=True)
X = np.array([[0, 1], [2, 3]])
transformer.transform(X)

参考资料:
Preprocessing data
《Python机器学习基础教程》

本文出自于http://www.bioinfo-scrounger.com转载请注明出处