由于标准化和归一化这两个词经常混用, 曾面试的时候, 有的面试官问标准化和归一化俩的区别. 在这里记录一下规范化, 标准化, 归一化, 中心化的区别, 以及项目中的使用.
1. 为什么大多数算法要进行规范化或标准化或归一化的处理
下面从 3 个角度简单的了解一下.
1.1 收敛速度
举个吴恩达老师, 讲的例子. x1 的取值为 0-2000, 而 x2 的取值为 1-5, 假如只有这两个特征, 对其进行优化时, 会得到一个窄长的椭圆形, 导致在梯度下降时, 梯度的方向为垂直等高线的方向而走之字形路线, 这样会使迭代很慢, 相比之下, 右图的迭代就会很快. 在特征不是很多, 数据量几十万的情况下, 收敛速度可能区别不大, 在特征较多和千万级别的数据时, 效果较为明显.
2019042502.PNG
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.]]
来源: http://www.jianshu.com/p/7a8aa50a0236