在Scikit-learn中的sklearn.preprocessing包提供了一些公共的实用函数和转换类来将特征行向量转换成更适合于接下来的估计的表示。
对于Scikit-learn中实现的许多机器学习估计来说,对数据集进行规范化是一个通用的需求。如果个别的特征或多或少的不服从与通常的数据分布:例如标准正态分布(均值为0,方差为1),这时算法的效果可能会表现得很差。
实际应用中,我们经常忽略数据分布的形状而仅仅将数据在每个维度特征的均值去除以使其数据集中,然后通过除以某个非常量的方差进行比例化。
例如,在一个机器学习的目标函数中使用的许多元素被假设为以零为中心并且在相同的阶上具有相同的方差。如果某一特征的幅值方差大于其它的特征,他可能会支配目标函数并且使得算法不能够按照我们期望的从其他的特征维度进行学习。
>>> 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...]])
比例化后的数据方差为0,均值为1
>>> X_scaled.mean(axis=0)
array([ 0., 0., 0.])
>>> X_scaled.std(axis=0)
array([ 1., 1., 1.])
preprocessing 模块进一步提供了一个实用类 StandardScaler 它实现了 Transformer 接口来在训练集上计算均值和方差,这样我们就可以在后来的测试数据集上应用相同的方法对数据进行转换。
>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.mean_
array([ 1. ..., 0. ..., 0.33...])
>>> scaler.scale_
array([ 0.81..., 0.81..., 1.24...])
>>> scaler.transform(X)
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
变量 scaler 能够对新数据以在训练数据相同的转化方法进行操作:
>>> scaler.transform([[-1., 1., 0.]])
array([[-2.44..., 1.22..., -0.26...]])
一个可供选择的标准化方法是缩放特征到一个给定最大值和最小值之间,经常这个给定的最大值和最小值取值为 0 和 1,或者对每个特征的最大值得绝对值进行归一化。这两种操作可以由MinMaxScaler 和 MaxAbsScaler 来实现。
下面的代码就是将数据缩放到[0, 1] :
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
...
>>> min_max_scaler = preprocessing.MinMaxScaler()
>>> 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. ]])
接下来,对于新数据
>>> X_test = np.array([[ -3., -1., 4.]])
>>> X_test_minmax = min_max_scaler.transform(X_test)
>>> X_test_minmax
array([[-1.5 , 0. , 1.66666667]])
>>> min_max_scaler.scale_
array([ 0.5 , 0.5 , 0.33...])
>>> min_max_scaler.min_
array([ 0. , 0.5 , 0.33...])
如果 MinMaxScaler 被指定一个确切的范围 [ min , max ],完整的计算公式如下:
X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std / (max - min) + min
MaxAbsScaler 以一个非常相似的方式工作,但是它通过在每个特征维度上除以该维度上的最大值把训练数据缩放到区间[-1 , 1],它意味着数据以0为中心或者是稀疏数据。
>>> X_train = np.array([[ 1., -1., 2.],
... [ 2., 0., 0.],
... [ 0., 1., -1.]])
...
>>> max_abs_scaler = preprocessing.MaxAbsScaler()
>>> X_train_maxabs = max_abs_scaler.fit_transform(X_train)
>>> X_train_maxabs # doctest +NORMALIZE_WHITESPACE^
array([[ 0.5, -1. , 1. ],
[ 1. , 0. , 0. ],
[ 0. , 1. , -0.5]])
>>> X_test = np.array([[ -3., -1., 4.]])
>>> X_test_maxabs = max_abs_scaler.transform(X_test)
>>> X_test_maxabs
array([[-1.5, -1. , 2. ]])
>>> max_abs_scaler.scale_
array([ 2., 1., 2.])
中心化稀疏数据将会破坏数据的稀疏性,因此这是一件敏感的事情。然而,缩放稀疏输入是有意义的,尤其是特征在不同的尺度上时。
MaxAbsScaler 和 maxabs_scale 是专门为缩放稀疏数据设计的,并且这是被推荐的方法。然而, scale 和 StandardScaler可以接受scipy.sparse矩阵作为输入,只要with_mean=False显试的传递给了构造函数。否则一个ValueError异常将会被抛出。注意,缩放类既接受被压缩的行稀疏矩阵又接受被压缩的列稀疏的矩阵结构(参看scipy.sparse.csr_matrix 和 scipy.sparse.csc_matrix)。任何其它的稀疏输入都会被转化成压缩的行表示。为了避免不必要的内存复制,推荐选择CSR 或者 CSC 表示输入流。
最后,如果希望中心化的数据足够小,那么一个可选的方案就是可以使用稀疏矩阵的toarray方法来将输入转化成一个矩阵。
如果你的数据包含很多异常点,那么使用均值和方差来缩放数据似乎效果不是很好。在这种情况下,你可以使用 robust_scale 和 RobustScaler 来替代。他们使用更鲁棒的方法来估计数据的中心和范围。
归一化是将单个的样本缩放到统一规范的处理过程。如果你想使用二次形式例如点积或者任何其他的核来度量两个样本的相似性的话,这个处理过程非常有用。
这个假设是基于向量空间模型经常被使用于文本分类或者聚类的环境中。函数 normalize 提供了一个快速和简单的方法在一个类数组的数据集上来执行该操作,使用 l1 或者 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...]])
preprocessing 模块进一步提供了一个有用的类 Normalizer 来使用 Transformer API(尽管它的fit方法在这种情况下是没有用的)来实现相同的操作。因此该类适合于在 sklearn.pipeline.Pipeline 之前的步骤使用。
>>> 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. ...]])
未完待续。。。
对机器学习,人工智能感兴趣的小伙伴,请关注我的公众号: