由于标准化和归一化这两个词经常混用,曾面试的时候,有的面试官问标准化和归一化俩的区别。在这里记录一下规范化,标准化,归一化,中心化的区别,以及项目中的使用。
1. 为什么大多数算法要进行规范化或标准化或归一化的处理
- 下面从3个角度简单的了解一下。
1.1 收敛速度
-
举个吴恩达老师,讲的例子。x1的取值为0-2000,而x2的取值为1-5,假如只有这两个特征,对其进行优化时,会得到一个窄长的椭圆形,导致在梯度下降时,梯度的方向为垂直等高线的方向而走之字形路线,这样会使迭代很慢,相比之下,右图的迭代就会很快。在特征不是很多,数据量几十万的情况下,收敛速度可能区别不大,在特征较多和千万级别的数据时,效果较为明显。
1.2 精度
- 实际工作中,往往问题要比教学案例复杂指数倍。比如教材上的数据分布有两个特征,身高和年龄,大多数身高在100-200cm,体重40-150kg(随便举的例子,没有具体统计,但是也大致差不多)。而在企业级项目时,比如车险理赔中,汽车的保险费用小到几百元,达到近千万元,该特征内数据差距有近1千多倍。汽车的报案时间,也就往往在24小时内。这两个字段差距很大(也就是不在一个数量级上),如果不进行特殊处理(函数映射),往往效果很差。因为两列数据的数值差距近万倍,假设两列数据对模型的效果,影响程度一样,也就是权重一样,那么保险费字段的系数可能是1,报案时间的系数为10000,此时使用第一范式正则化时,正则系数稍微大些,保险费字段就去掉了。在实际业务中,这个字段很重要。因此不进行处理,我们的算法调整参数,效果很不理想。
1.3 量纲
- 从数学的角度,的确消除了量纲,标准化是如何消除量纲的呢?不知道还记得标准化的公式不? (x-mean)/std ,假如已知身高字段的均值是170cm,方差是,则标准差是1cm,如果输入x为180cm,那么标准化后是.
- 但是对分析数据没有影响。为什么会这样说呢?因为计算机识别的是二进制的,只识别0和1,这时数据进去的是一个阿拉伯数字,或者有个字符型,再转化为机器语言,肯定不会带着量纲(体重:kg,身高:cm),还有就是机器学习算法输入的也是数值,根本不可能把量纲输入进去,量纲只是便于人们认识和理解实际的含义。
2. 规范化,标准化,归一化 区别与联系
- 现在,对于这三个概念没有明显的区分,大家都混用,但是面试官问你的时候,你总不能不回答,或者没区别吧,那会造成印象分降低,严重了直接被PASS。我的理解还是从名字的角度区分,毕竟名字也不是随便起。
- 个人理解不要太当真,片面理解,不喜勿喷。
- 规范化:规范化包含标准化,归一化。就是画一个区域,其值在这个区域里。也就是无规矩不成方圆。
- 标准化:我觉得标准二字出处标准正态分布,也就是z-score的处理手段。
- 归一化:归一化中的归一 重点还是一,也就是原数据映射到【0,1】区间,也就是min-max*的处理手段。
2.1 规范化的定义及策略
- 规范化:数据规范化是将原来的度量值转换为无量纲的值。通过将属性数据按比例缩放,通过一个函数将给定属性的整个值域映射到一个新的值域中,即每个旧的值都被一个新的值替代。
- 有3 种规范化策略,具体如下;
- 最小-最大(min-max)规范化。最小-最大规范化保持原有数据之间的联系。如果今后的输入落在A的原始数据值域之外,该方法将面临“越界错误”。因此此方法需要知道数据的最大值和最小值,才能保证所有的数据映射到[0,1]区间里.
- z-score规范化。当某特征的实际最大和最小值未知,或异常点左右了最小-最大规范化时,该方法是有用的。该方法映射的数据会服从正态分布,大多数值在均值附近波动。
- 小数定标规范化。小数定标规范化通过移动的小数点位置进行规范化。这个太抽象,举个例子,如果一个字段的数据在[-9,8]区间内,进行小数定标后,abs = 9,abs距离(n>0)最近时,n = 1,因此该字段的所有数据除以10,映射到[-0.9,0.8]区间内。区别最大—最小规范化。
2.2 标准化
- z-score标准化(或零-均值标准化),这是最常见的特征预处理方式,基本所有的线性模型在拟合的时候都会做 z-score标准化。标准化后特征就变成了均值为0,方差为1了,一般标准正态分布比较常用。如果我们不想让均值为零,可以在分子的时候进行加减。
y=(x-X的平均值)/X的标准差=(x-mean)/std
- 优点:当X的最大值和最小值未知,或孤立点(可以理解为异常点,但是还是有区别的)左右了最大-最小规范化时,该方法有用。
- 看到优点,大家应该知道了为什么z-score标准化,比较常用。因为数据时源源不断产生的,我们不能保证以往和当前数据中的最大值,一定比未来数据的最大值还要大。如果最小-最大(min-max)规范化,未来数据的最大值更大些,会造成数据落在[0,1]区间外,这就违背了min-max的目的。
2.3 归一化
- max-min标准化:也称为离差标准化,预处理后使特征值映射到[0,1]之间。具体的方法是求出样本特征x的最大值max和最小值min,然后用(x-min)/(max-min)来代替原特征。如果我们希望将数据映射到任意一个区间[a,b],而不是[0,1],那么也很简单。用(x-min)(b-a)/(max-min)+a来代替原特征即可。
y=(x-min)/(max-min)
3. 中心化
- 中心化, 是指变量减去它的均值(即数学期望值)。对于样本数据,将一个变量的每个观测值减去该变量的样本平均值,变换后的变量就是中心化的。关于为什么中心化,此处不在介绍,会在以后的PCA中详细介绍,以及推理。
y=(x-X的平均值)=(x-mean)
4. 其他方法
- 虽然标准化比较常用,但是我们还有其他的方法;
4.1 log函数
- 该字段的数据都要大于等于1,或者都要大于0且小于1。
4.2 atan函数
- 该字段的数据都要大于等于0。
4.3 Logistic/Softmax变换
- 该字段的数据可以为任何数值。
4.4 模糊量化模式
- 其中,
- :该字段的极大值;
- :该字段的极小值;
- X为原数据反余切函数转换,表达式如下:
- 区别最大值与极大值,最小值和极小值同理,不再罗列
- 最大值是函数中最大的值,而极大值不是。
- 最大值一定高于函数中其他的值,极大值可以小于极小值。
- 最大值的值只有一个,而极大值的值可以有无限个。
- 此方法涉及到求极值点,往往需要保证该字段是连续的,或者含有有限个间断点。求出来的极值点是多个的情况下,需要固定一个。缺点比较多,几乎不用。
5. 代码
- 生成数组
from sklearn import preprocessing
import numpy as np
X_train = np.array([[ 1., -1., -2.],
[ 2., 0., 0.],
[ 3., 1., 1.],
[ 4., 0., -1.]])
X_test = [[-1., 1., 0.]]
print(X_train)
- 打印输出
[[ 1. -1. -2.]
[ 2. 0. 0.]
[ 3. 1. 1.]
[ 4. 0. -1.]]
5.1 z-score标准化
scaler = preprocessing.StandardScaler().fit(X_train) # 计算均值和方差
print('StandardScaler:',scaler )
print('标准化前均值:',scaler.mean_ )
print('标准化前方差:',scaler.var_ )
print('缩放比例:',scaler.scale_ )
# 通过尺度去处理另一个数据集,当然另一个数据集仍然可以是自己。
X_scaled = scaler.transform(X_train)
print('标准化后均值:',X_scaled.mean(axis=0)) # transform会转化数据集为均值为0
print('标准化后方差:',X_scaled.std(axis=0)) # transform会转化数据集为方差为1
# 上面两步的综合:缩放样本,
X_scaled = preprocessing.scale(X_train,axis=0)
print('标准化后均值:',X_scaled.mean(axis=0))
print('标准化后方差:',X_scaled.std(axis=0))
- 打印输出
StandardScaler: StandardScaler(copy=True, with_mean=True, with_std=True)
标准化前均值: [ 2.5 0. -0.5]
标准化前方差: [1.25 0.5 1.25]
缩放比例: [1.11803399 0.70710678 1.11803399]
标准化后均值: [ 0.00000000e+00 0.00000000e+00 -1.38777878e-17]
标准化后方差: [1. 1. 1.]
标准化后均值: [ 0.00000000e+00 0.00000000e+00 -1.38777878e-17]
标准化后方差: [1. 1. 1.]
5.2 MinMaxScaler
# MinMaxScaler将特征缩放至特定范围内(默认为0-1)
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax = min_max_scaler.fit_transform(X_train) # 训练同时转换
print('缩放后每列最大值:',X_train_minmax.max(axis=0)) # 每列最大值为1
print('缩放后每列最小值:',X_train_minmax.min(axis=0)) # 每列最小值为0
# 缩放对象是记录了,平移距离和缩放大小,再对数据进行的操作
print('缩放后的最小值偏移量:',min_max_scaler.min_)
print('缩放比例:',min_max_scaler.scale_)
print('数据最小值:',min_max_scaler.data_min_)
print('数据最大值:',min_max_scaler.data_max_)
print('数据最大最小范围的长度:',min_max_scaler.data_range_)
X_test_minmax = min_max_scaler.transform(X_test) # 转换实例应用到测试数据:实现和训练数据一致的缩放和移位操作:
- 打印输出
缩放后每列最大值: [1. 1. 1.]
缩放后每列最小值: [0. 0. 0.]
缩放后的最小值偏移量: [-0.33333333 0.5 0.66666667]
缩放比例: [0.33333333 0.5 0.33333333]
数据最小值: [ 1. -1. -2.]
数据最大值: [4. 1. 1.]
数据最大最小范围的长度: [3. 2. 3.]
5.3 MaxAbsScaler
# MaxAbsScaler通过除以每个特征的最大值将训练数据特征缩放至 [-1, 1] 范围内。可以应用在稀疏矩阵上保留矩阵的稀疏性。
max_abs_scaler = preprocessing.MaxAbsScaler()
X_train_maxabs = max_abs_scaler.fit_transform(X_train)
print('每列最大值:',X_train_maxabs.max(axis=0)) # 每列最大值为1
print('每列最小值:',X_train_maxabs.min(axis=0)) # 每列最小值不低于-1
print('缩放比例:',max_abs_scaler.scale_)
print('绝对值最大值:',max_abs_scaler.max_abs_)
print('样本个数:',max_abs_scaler.n_samples_seen_)
X_test_maxabs = max_abs_scaler.transform(X_test) # 转换实例应用到测试数据:实现和训练数据一致的缩放和移位操作:
print('缩放后的矩阵仍然具有稀疏性:\n',X_train_maxabs)
- 打印输出
每列最大值: [1. 1. 0.5]
每列最小值: [ 0.25 -1. -1. ]
缩放比例: [4. 1. 2.]
绝对值最大值: [4. 1. 2.]
样本个数: 4
缩放后的矩阵仍然具有稀疏性:
[[ 0.25 -1. -1. ]
[ 0.5 0. 0. ]
[ 0.75 1. 0.5 ]
[ 1. 0. -0.5 ]]
5.3 RobustScale(离群值缩放)
robust_scale = preprocessing.RobustScaler()
X_train_robust = robust_scale.fit_transform(X_train) # 训练同时转换
print('原数据中心点:\n',robust_scale.center_)
print('缩放比例:\n',robust_scale.scale_)
print('缩放后的矩阵离群点被处理了:\n',X_train_robust)
- 打印输出
原数据中心点:
[ 2.5 0. -0.5]
缩放比例:
[1.5 0.5 1.5]
缩放后的矩阵离群点被处理了:
[[-1. -2. -1. ]
[-0.33333333 0. 0.33333333]
[ 0.33333333 2. 1. ]
[ 1. 0. -0.33333333]]
5.4 QuantileTransformer(非线性转换)
quantile_transformer = preprocessing.QuantileTransformer(random_state=0) # 将数据映射到了零到一的均匀分布上(默认是均匀分布)
X_train_trans = quantile_transformer.fit_transform(X_train)
print('原分位数情况:',np.percentile(X_train[:, 0], [0, 25, 50, 75, 100]))
print('均匀化,分位数情况:',np.percentile(X_train_trans[:, 0], [0, 25, 50, 75, 100]))
# 下面将数据映射到了零到一的正态分布上:输入的中值称为输出的平均值,并且以0为中心。
quantile_transformer = preprocessing.QuantileTransformer(output_distribution='normal',random_state=0)
X_train_trans = quantile_transformer.fit_transform(X_train)
print('标准正态,分位数情况:',np.percentile(X_train_trans[:, 0], [0, 25, 50, 75, 100]))
- 打印输出
原分位数情况: [1. 1.5 2. 2.5 3. ]
均匀化,分位数情况: [9.99999998e-08 2.50000050e-01 5.00000000e-01 7.49999950e-01
9.99999900e-01]
标准正态,分位数情况: [-5.19933758 -2.59966879 0. 2.59966879 5.19933758]
5.5 l1 或 l2 范式
# 使用 l1 或 l2 范式。缩放使每个样本(每行)的一范数或二范数为1
# l1范式:向量各元素的绝对值和 l2范式:向量各元素的平方和然后求平方根
X_normalized = preprocessing.normalize(X_train, norm='l2')
print('样本 l2 归一化:\n',X_normalized)
# 或者
normalizer = preprocessing.Normalizer().fit(X_train)
X_normalized = normalizer.transform(X_train)
print('样本 l2 归一化:\n',X_normalized)
- 打印输出
样本 l2 归一化:
[[ 0.40824829 -0.40824829 -0.81649658]
[ 1. 0. 0. ]
[ 0.90453403 0.30151134 -0.30151134]]
样本 l2 归一化:
[[ 0.40824829 -0.40824829 -0.81649658]
[ 1. 0. 0. ]
[ 0.90453403 0.30151134 -0.30151134]]
5.6 特征二值化
# 获取转换模型,生成的门限,默认为0(大于0为1,否则为0)
binarizer = preprocessing.Binarizer().fit(X_train)
# binarizer = preprocessing.Binarizer(threshold=1) # 自定义转换器。门限以上为1,门限(包含)以下为0
X_normalized = binarizer.transform(X_train)
print('特征二值化:\n',X_normalized)
- 打印输出
特征二值化:
[[1. 0. 0.]
[1. 0. 0.]
[1. 1. 1.]
[1. 0. 0.]]
5.7 多项式特征
from sklearn.preprocessing import PolynomialFeatures
X = np.array([[0, 1],
[2, 3],
[4, 5]])
poly = PolynomialFeatures(2,interaction_only=False) # 最大二次方。interaction_only参数设置为True,则会只保留交互项
print('生成多项式:\n',poly.fit_transform(X)) # 从 (X_1, X_2) 转换为 (1, X_1, X_2, X_1^2, X_1X_2, X_2^2)
- 打印输出
生成多项式:
[[ 1. 0. 1. 0. 0. 1.]
[ 1. 2. 3. 4. 6. 9.]
[ 1. 4. 5. 16. 20. 25.]]