2. 机器学习之数据规范化,标准化,归一化,中心化

由于标准化和归一化这两个词经常混用,曾面试的时候,有的面试官问标准化和归一化俩的区别。在这里记录一下规范化,标准化,归一化,中心化的区别,以及项目中的使用。


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^2,则标准差是1cm,如果输入x为180cm,那么标准化后是(180cm-170cm)/1cm = 10cm/1cm = 10.
  • 但是对分析数据没有影响。为什么会这样说呢?因为计算机识别的是二进制的,只识别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距离10^n(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函数

log_{10}(x)/log_{10}((max(x)))

  • 该字段的数据都要大于等于1,或者都要大于0且小于1。

4.2 atan函数

atan(x)*2/\pi

  • 该字段的数据都要大于等于0。

4.3 Logistic/Softmax变换

f(x) = 1/(1+exp(-x))

  • 该字段的数据可以为任何数值。

4.4 模糊量化模式

1/2+1/2sin[\pi/(X_{1}-X_{2})*(X-(X_{1}-X_{2})/2)]

  • 其中,
  1. X_{1}:该字段的极大值;
  2. X_{2}:该字段的极小值;
  3. X为原数据反余切函数转换,表达式如下:atan(x)*2/\pi
  4. 区别最大值与极大值,最小值和极小值同理,不再罗列
    • 最大值是函数中最大的值,而极大值不是。
    • 最大值一定高于函数中其他的值,极大值可以小于极小值。
    • 最大值的值只有一个,而极大值的值可以有无限个。
  5. 此方法涉及到求极值点,往往需要保证该字段是连续的,或者含有有限个间断点。求出来的极值点是多个的情况下,需要固定一个。缺点比较多,几乎不用。

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.]]
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容