一些算法(如神经网络和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,但稀疏矩阵的某几个特征的在不同的数量级,这时标准化也是必须要做的
- 首先可以使用
MaxAbsScaler
和maxabs_scale
方法 - 如果要使用
StandardScaler
和scale
方法,则需要参数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 transform
和Box-Cox transform
;注:Box-Cox transform只用于正数数据(其中standardize=False
表示不进行0均值化和方差标准化)
pt = preprocessing.PowerTransformer(method='box-cox', standardize=False)
pt.fit_transform(X_train)
并需要注意的是:有时PowerTransformer对于一些分布能很好的转化为高斯分布,但是有些分布却不太行,这时需要分布可视化来检查。。。
除了PowerTransformer
,QuantileTransformer
也可将数据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.]])
以上normalize
和Normalizer
均可适用于密集数组及稀疏矩阵
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
对于一些自定义的转化器,比如将输入数据进行log1p
(log1p = 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转载请注明出处