今天这篇还是讲特征工程那一堆事,准确点说是数据预处理范畴内的,在做PCA降维时,我发现利用方差过滤出的主成分和利用PCA降维得到的主成分对应位置的方差有些不同:

VarianceThreshold:[90370.21684180899, 55277.04960170764, 51395.858083599174]
PCA:[176251.93379431,74196.48270488,55716.27982124]

之前说过PCA降维可以将原来高维的数据投影到某个低维的空间上并使得其方差尽量大。如果数据其中某一特征的数值特别大的话,那么它在整个误差计算的比重上就很大。所以将数据投影到低维空间之后,整个投影会去努力逼近数值最大的那一个特征,而忽略数值比较小的特征。

在建模前我们不知道每个特征的重要性,这很可能导致了大量的信息缺失。为了“公平”起见,防止过分捕捉某些数值大的特征,我们就可以先对每个特征先进行标准化处理,使得它们的大小都在相同的范围内,然后再进行PCA。

我们要处理的数据往往有着不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,为了消除特征之间的量纲影响,需要进行数据标准化处理。原始数据经过数据标准化处理后,数据集中每个特征就处于同一数量级,适合进行综合对比评价。

上面文字叙述可能相对抽象,就先通过一个简单的例子深入了解一下标准化和归一化的重要性。假如一个人的健康状况可以根据一个公式计算:

python xgboost回归模型贝叶斯调优_数据

现在我们有一份数据集,有身高和体重两个特征,身高的单位为米,体重的单位为斤:

身高(米)

体重(斤)

健康状况

1.7

120

245.1

1.6

200

404.8

2.0

140

286

即使在公式中身高所占权重要大于体重,但是由于这两个特征数值之间出现了两极化,所以最后一个人的健康状况很大程度向体重倾斜,所以若想正确的评判一个人的健康状况,那么需要中和一下两类数值,可以将其映射至[0,1]区间内,也就是进行归一化处理:

身高(米)

体重(斤)

健康状况

0.25

0

0.5

0

1

2

1

0.25

3.5

处理之后再预测时,就不会出现向某个特征倾斜的状况,两个特征的重要性就取决于公式中系数的大小。

归一化

归一化就是将训练集中某一列数值特征的值缩放到0和1之间,公式如下:

python xgboost回归模型贝叶斯调优_数据_02

其中python xgboost回归模型贝叶斯调优_机器学习_03为样本最大值,python xgboost回归模型贝叶斯调优_标准化_04为样本最小值。可以看到每个样本的归一化都是要依据数据中最大值和最小值进行的,所以归一化对数据集中的异常点是比较敏感的。因为异常点通常是离群点,那么它的值可能就过大或者过小,如果归一化依据异常点进行的话,最后的结果就会产生很大的偏差。所以在归一化很适合精确且规模相对小一些的数据集,一般在归一化之前可以先检查数据,排除异常点的影响。

利用numpy实现归一化的代码如下:

def normalization(data):
    M_m = np.max(data)-np.min(data)
    return (data-np.min(data)) / M_m

标准化

标准化就是将训练集中某一列数值特征的值缩放成均值为0,方差为1的状态。公式如下:

python xgboost回归模型贝叶斯调优_数据_05

其中python xgboost回归模型贝叶斯调优_标准化_06为样本均值、python xgboost回归模型贝叶斯调优_归一化_07为样本标准差,python xgboost回归模型贝叶斯调优_归一化_07也考量了数据稳定性。每一个样本的归一化仅和最大值、最小值和它本身有关,这点和标准化是有一些出入的,标准化的缩放处理和每一个样本点都有关系,因为均值和标准差是数据集整体的,与归一化相比,标准化更加注重数据集中样本的分布状况。由于具有一定的样本个数,所以出现少量的异常点对于平均值和标准差的影响较小,因此标准化的结果也不会具有很大的偏差。

利用numpy实现标准的代码如下:

def standardization(data):
    mu = np.mean(data, axis=0)
    sigma = np.std(data, axis=0)
    return (data - mu) / sigma

综上很容易推断出归一化和标准化本质上都是对原始数据进行缩放和平移,只是着重点不同。

在sklearn库中也有归一化和标准化对应的API,应用起来也很简单,归一化应用方法:

from sklearn.preprocessing import MinMaxScaler
import numpy as np
X = [[83,2,10],
     [60,3,15],
     [75,4,13]]
X = np.array(X)
Mm = MinMaxScaler()
data = Mm.fit_transform(X)
print(data)

归一化输出对应结果:

[[1.         0.         0.        ]
 [0.         0.5        1.        ]
 [0.65217391 1.         0.6       ]]

标准化应用方法:

from sklearn.preprocessing import StandardScaler
import numpy as np

X = [[83,2,10],
     [60,3,15],
     [75,4,13]]
X = np.array(X)
Mm = StandardScaler()
data = Mm.fit_transform(X)
print(data)

标准化输出对应结果:

[[ 1.08388958 -1.22474487 -1.29777137]
 [-1.32863884  0.          1.13554995]
 [ 0.24474926  1.22474487  0.16222142]]

那么是所有的机器学习算法建模之前都需要对相应的数据进行标准化和归一化处理吗?肯定不是的。其中KNN算法、支持向量机、线性回归、神经网络是需要进行标准化或归一化处理的,不难发现这几种算法都与"距离"相关,所以在进行计算时为了避免预测结果向数值大的特征倾斜,所以标准化处理是必要的,可以很大程度提高模型的精度。

而逻辑回归是否要标准化则取决于是否应用正则化,标准化可以很好的提高收敛速度,这很好的体现在梯度下降法和梯度上升法中,如下图:

python xgboost回归模型贝叶斯调优_标准化_09

左图为标准化之前,右图为标准化之后,可以看到标准化可以让模型少走很多弯路,从而加快收敛速度,这一点也很容易想象,毕竟个位数与千位数、个位数与个位数之间的"距离"差距还是很大的。

决策树和朴素贝叶斯算法是不需要进行标准化的,因为前者是通过信息增益进行决策,后者是通过概率进行评判,这类模型不关心变量的取值,而是关心变量的分布和变量之间的条件概率,与"距离"计算无关,继而以决策树为基础构建的随机森林、AdaBoost等等也不需要标准化,但是需要注意的是,在应用这些算法之前若要使用PCA降维则需要进行标准化。

那么归一化和标准化如何选择呢?这个没有准确的答案,如果时间允许,可以尝试两种处理方法择最优。如果时间不允许,可以根据数据和要求选择:

  • 如果数据集小而稳定,可以选择归一化
  • 如果数据集中含有噪声和异常值,可以选择标准化,标准化更加适合嘈杂的大数据集。