写在前面
之前,写过一篇文章,叫做真的明白数据归一化(MinMaxScaler)和数据标准化(StandardScaler)吗?。这里面搞清楚了归一化和标准化的区别,但是在实用中发现,在数据标准化中,又存在两种方式可以实现,在这里总结一下两者的区别吧。
标准化是怎么回事来?
-
什么是标准化
在机器学习中,我们可能要处理不同种类的资料,例如,音讯和图片上的像素值,这些资料可能是高维度的,资料标准化后会使每个特征中的数值平均变为0(将每个特征的值都减掉原始资料中该特征的平均)、标准差变为1,这个方法被广泛的使用在许多机器学习算法中(例如:支持向量机、逻辑回归和类神经网络)。 -
标准化的特点:
对不同特征维度的伸缩变换的目的是使得不同度量之间的特征具有可比性。同时不改变原始数据的分布。
好处:
- 使得不同度量之间的特征具有可比性,对目标函数的影响体现在几何分布上,而不是数值上
- 不改变原始数据的分布
举个例子:
根据人的身高和体重预测人的健康指数
假设有如下原始样本数据是四维的
标准化是这样做的:
从上面两个坐标图可以看出,样本在数据值上的分布差距是不一样的,但是其几何距离是一致的。而标准化就是一种对样本数据在不同维度上进行一个伸缩变化(而不改变数据的几何距离),也就是不改变原始数据的信息(分布)。这样的好处就是在进行特征提取时,忽略掉不同特征之间的一个度量,而保留样本在各个维度上的信息(分布)。
- 如何进行标准化
公式为:(X-mean)/std 计算时对每个属性/每列分别进行。
有两种实现方式:
- 使用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...]])
>>>#处理后数据的均值和方差
>>> X_scaled.mean(axis=0)
array([ 0., 0., 0.])
>>> X_scaled.std(axis=0)
array([ 1., 1., 1.])
- 使用sklearn.preprocessing.StandardScaler类,使用该类的好处在于可以保存训练集中的参数(均值、方差)直接使用其对象转换测试集数据。
>>> scaler = preprocessing.StandardScaler().fit(X)
>>> scaler
StandardScaler(copy=True, with_mean=True, with_std=True)
>>> scaler.mean_
array([ 1. ..., 0. ..., 0.33...])
>>> scaler.std_
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.transform([[-1., 1., 0.]])
array([[-2.44..., 1.22..., -0.26...]])
实现标准化两种方式的区别
- sklearn.preprocessing.scale可以沿着特定的坐标轴对数据集进行标准化,在均值附近集中化数据并缩放至单位方差.
sklearn.preprocessing.scale(X, axis = 0, with_mean=True, with_std=True, copy=True)
- X:需要进行集中化和缩放的数据,类似于数组,稀疏矩阵
- axis:整数(默认是 0 )用来计算均值和标准差的轴. 当 axis=0 时,对各个特征进行标准化;当 axis=1 时,会对每个样本进行标准化
- with_mean:boolean,布尔型,默认是 True,即在缩放之前对数据进行集中化
- with_std:boolean,布尔型,默认是 True,即缩放数据至单位方差( 或单位标准差)
- copy:boolean,布尔型,默认是 True,可选填. 设置为 False 的时候即在原数据行上进行标准化,并禁止复制( 如果输入是 numpy 数组或是 scipy.sparse CSC 矩阵并且 axis = 1)
这个是preprocessing提供的函数。
在机器学习数据预处理中,这个函数把训练集和测试集放在一块进行标准化处理,求出共同的均值和方差,然后X减去均值再除以方差。处理成均值为0, 方差为1的数据。 参考了测试集本身。
- Preprocessing 模块还提供实用程序类 StandardScaler 执行转换器 API 来计算训练集的均值和标准差,然后应用同样的转换方法对测试集进行转换. 移除特征的均值并进行缩放,根据样本集上的每一个特征的各项统计值来进行集中化和缩放. 这个类也由此可以适用于 sklearn.pipeline.Pipeline 的早期步骤:
class.sklearn.preprocessing.StandardScaler(copy = True, with_mean = True, with_std = True )
- copy:boolean,布尔型,可选填,默认为 True,设置为 False 时则会在原数据上进行缩放并且禁止副本. 然而这并不保证一直在原数据上操作,例外情况比如数据不是 numpy 的数组或者scipy.sparse CSR 矩阵,依然会返回一个副本
- with_mean:boolean,布尔型,默认为 True,即在缩放前集中化数据
- with_std:boolean,布尔型,默认为 True,即缩放数据至单位方差( 或单位标准差)
- Attributes 包括:scale_ 每个特征的相对标度,mean_训练集中每个特征的均值,var_训练集中每个特征的方差
这个是preprocessing提供的类。
在机器学习数据预处理中,这个函数把是把训练集的数据进行特征缩放之后,然后应用到测试集上去。 也就是只求出训练集的均值和方差,然后让训练集和测试集的X都减去这个均值然后除以方差。 均值和方差的计算没有参考测试集。
看下面的使用例子:
>>> scaler = preprocessing.StandardScaler().fit(X_train)
>>> 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_train)
array([[ 0. ..., -1.22..., 1.33...],
[ 1.22..., 0. ..., -0.26...],
[-1.22..., 1.22..., -1.06...]])
得到的 scaler 就可以用同样的方法去转换新的数据集了:
>>> X_test = [[-1., 1., 0.]]
>>> scaler.transform(X_test)
array([[-2.44..., 1.22..., -0.26...]])
总结一下:
scale()函数和StandardScaler()函数都可以把数据标准化,处理的过程都是 (X-mean) / std。
但是又有点不同,scale()不能迁移到新的数据集,如果是处理训练集和测试集,只能是把训练集和测试集合起来, 计算出共同的mean和std, 然后 (X-mean) / std,再分成训练集和测试集。这里的mean和std的计算涉及到了测试集,是训练集和测试集共同的期望和方差
而StandardScaler()可以迁移到新的数据集,只需要处理训练集,拿训练集的数据计算出均值x_train_mean, x_train_std和方差,然后训练集的X_train和测试集的X_test都执行标准化。 这里注意:测试集的标准化是利用的训练集的均值和方差。 也就是假设训练集的期望和测试集的期望是一样的,这样只需要计算出训练集的期望之后,直接用于测试集就可以了,这里只是训练集的期望和方差,没有涉及测试集
在机器学习中,我们是从整体中采用抽样的方式抽出训练集,这意味着我们默认,这部分训练集可以代替整体,也就是训练集的期望就是整体的期望,测试集标准化的时候,它的期望采用的正是训练集的期望.
所以StandardScaler()才是我们经常用的方式。