极客时间已完结课程限时免费阅读

29 | 归一化和标准化:各种特征如何综合才是最合理的?

29 | 归一化和标准化:各种特征如何综合才是最合理的?-极客时间

29 | 归一化和标准化:各种特征如何综合才是最合理的?

讲述:黄申

时长12:21大小11.28M

你好,我是黄申,今天我来说说特征值的变换。
上一节我讲了如何在众多的特征中,选取更有价值的特征,以提升模型的效率。特征选择是特征工程中的重要步骤,但不是全部。今天,我来说说特征工程中的另一块内容,数值变换。也就是说,我们可以使用统计中的数据分布,对连续型的数值特征进行转换,让多个特征的结合更有效。具体怎么理解呢?我下面就来详细讲一讲。

为什么需要特征变换?

我们在很多机器学习算法中都会使用特征变换。我使用其中一种算法线性回归作为例子,来解释为什么要进行数值型特征的变换。
我们之前介绍的监督式学习会根据某个样本的一系列特征,最后判定它应该属于哪个分类,并给出一个离散的分类标签。除此之外,还有一类监督式学习算法,会根据一系列的特征输入,给出连续的预测值。
举个例子,房地产市场可以根据销售的历史数据,预估待售楼盘在未来的销售情况。如果只是预估卖得“好”还是“不好”,那么这个粒度明显就太粗了。如果我们能做到预估这些房屋的售价,那么这个事情就变得有价值了。想要达成这个预测目的的过程,就需要最基本的因变量连续回归分析
因变量连续回归的训练和预测,和分类的相应流程大体类似,不过具体采用的技术有一些不同。它采用的是研究一个或多个随机变量 ,…, 与另一些变量 ,…, 之间关系的统计方法,又称多重回归分析
我们将 ,…, 称为因变量,,…, 称为自变量。通常情况下,因变量的值可以分解为两部分,一部分是受自变量影响的,即表示为自变量相关的函数,其中函数形式已知,可能是线性也可能是非线性函数,但包含一些未知参数;另一部分是由于其他未被考虑的因素和随机性的影响,即随机误差。
如果因变量和自变量为线性关系时,就称为线性回归模型;如果因变量和自变量为非线性关系,则称为非线性回归分析模型。今天我们要说的是回归中常用的多元线性回归,它的基本形式是:
其中,,…, 是自变量, 是因变量, 是随机误差,通常假定随机误差的均值为 0。而 w0 是截距,,…, 是每个自变量的系数,表示每个自变量对最终结果的影响是正面还是负面,以及影响的程度。如果某个系数大于 0,表示对应的自变量对结果是正面影响,这个自变量越大,结果就越大。否则就是负面影响,这个自变量越大,结果就越小。而系数的绝对值表示了影响程度的大小,如果绝对值趋于 0,表示基本没有影响。
线性回归也是统计概率中常用的算法。不过它的实现通常会涉及很多线性代数的知识,所以下一个模块的时候,我会再详细介绍这个算法。这一节,你只需要知道线性回归所要达到的目标,以及怎么使用它就可以了。
线性回归和其他算法相比,有很强的可解释性。我们可以通过回归后为每个自变量确定的系数,来判断哪些自变量对最终的因变量影响更大。可是,在正式开始线性回归分析之前,还有一个问题,那就是不同字段的数据没有可比性。
比如,房屋的面积和建造的年份,它们分别代表了不同的含义,也有不一样的取值范围。在线性回归中,如果直接将没有可比性的数字型特征线性加和,那么模型最终的解释肯定会受影响。
这里我用 Boston Housing 数据集对房价数据进行回归分析,这个数据来自 70 年代美国波士顿周边地区的房价,是用于机器学习的经典数据集,你可以在 Kaggle 的网站(https://www.kaggle.com/c/boston-housing#description)下载到它。这个数据一共有 14 个特征或者说自变量,而有 1 个目标值或者说因变量。
这里,我只使用其中的 train.csv。使用一小段 Python 代码,我们就能很快的得到一个线性回归的结果。
import pandas as pd
from sklearn.linear_model import LinearRegression
df = pd.read_csv("/Users/shenhuang/Data/boston-housing/train.csv") #读取Boston Housing中的train.csv
df_features = df.drop(['medv'], axis=1) #Dataframe中除了最后一列,其余列都是特征,或者说自变量
df_targets = df['medv'] #Dataframe最后一列是目标变量,或者说因变量
regression = LinearRegression().fit(df_features, df_targets) #使用特征和目标数据,拟合线性回归模型
print(regression.score(df_features, df_targets)) #拟合程度的好坏
print(regression.coef_) #各个特征所对应的系
使用上述代码之前,请确保你已经按照了 Python 中的 sklearn 和 pandas 包。运行这段代码,你可以得到如下的结果:
0.735578647853312
[-4.54789253e-03 -5.17062363e-02 4.93344687e-02 5.34084254e-02
3.78011391e+00 -1.54106687e+01 3.87910457e+00 -9.51042267e-03
-1.60411361e+00 3.61780090e-01 -1.14966409e-02 -8.48538613e-01
1.18853164e-02 -6.01842329e-01]
因为不是所有的数据都是可以使用线性回归模型来表示,所以我们需要使用 regression.score 函数,来看拟合的程度。如果完美拟合,这个函数就会输出 1;如果拟合效果很差,这个函数的输出可能就是一个负数。
这里 regression.score 函数的输出大约为 0.74,接近于 1.0。它表示这个数据集使用线性模型拟合的效果还是不错的。如果你还是不理解,不用担心,具体的我们会在线性代数部分详细解答。这里你可以简单的理解为,0.74 仅仅表示我们可以使用线性回归来解决 Boston Housing 这个问题。
这里,你更需要关注的是每个特征所对应的权重,因为它们可以帮助我们解释哪个特征对最终房价的中位值有更大的影响。参看 train.csv 中的数据,你会发现最主要的两个正相关特征是 nox(系数为 3.78011391e+00)和 age(系数为 3.87910457e+00)。其中 nox 表示空气污染浓度,age 表示老房子占比,也就是说空气污染越多、房龄越高,房价中位数越高,这好像不太合乎常理。我们再来看看最主要的负相关特征 rm(系数为 -1.54106687e+01),也就是房间数量。房间数量越多,房价中位数越低,越不合理。
造成这些现象最重要的原因是,不同类型的特征值没有转换到同一个可比较的范围内,所以线性回归后所得到的系数不具有可比性,因此我们无法直接对这些权重加以解释。

两种常见的特征变换方法

该怎么解决这个问题呢?我们就需要对特征值进行转换。今天我介绍两种最常见的变换方法:归一化和标准化。

归一化

我们先来看最常用的方法,归一化(Normalization)。它其实就是获取原始数据的最大值和最小值,然后把原始值线性变换到[0,1]之间,具体的变换函数为:
其中 是原始值, 为样本数据的最大值, 为样本数据的最小值, 是变换后的值。这种方法有个不足最大值与最小值非常容易受噪音数据的影响。
这里面需要注意的是,“归一化”这个词在不同的领域的含义可能不同。这里我们特指基于最大和最小值的变换。
接下来,我们来看看在 Python 中如何实现归一化,以及归一化对回归后系数的影响。
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
minMaxScaler = MinMaxScaler() #基于min和max值的归一化
df_normalized = minMaxScaler.fit_transform(df) #对原始数据进行归一化,包括特征值和目标变量
df_features_normalized = df_normalized[:, 0:-1] #获取归一化之后的特征值
df_targets_normalized = df_normalized[:, -1] #获取归一化之后的目标值
#再次进行线性回归
regression_normalized = LinearRegression().fit(df_features_normalized, df_targets_normalized)
print(regression_normalized.score(df_features_normalized, df_targets_normalized))
print(regression_normalized.coef
其中,df 还是之前加载的 dataframe。运行这段代码,你可以得到如下结果:
0.7355786478533118
[-0.05103746 -0.08448544 0.10963215 0.03204506 0.08400253 -0.16643522
0.4451488 -0.01986622 -0.34152292 0.18490982 -0.13361651 -0.16216516
0.10390408 -0.48468369]
你可以看到,表示拟合程度的分数没有变,但是每个特征对应的系数或者说权重,发生了比较大的变化。仔细观察一下,你会发现,这次最主要的正相关特征是 age(0.4451488)和 tax(0.18490982),也就是老房子占比和房产税的税率,其中至少房产税的税率是比较合理的,因为高房价的地区普遍税率也比较高。而最主要的负相关特征是 rad(-0.34152292)和 lstat(-0.48468369),rad 表示高速交通的便利程度,它的值越大表示离高速越远,房价中位数越低。而 lstat 表示低收入人群的占比,这个值越大房价中位数越低,这两点都是合理的。

标准化

另一种常见的方法是基于正态分布的 z 分数(z-score)标准化(Standardization)。该方法假设数据呈现标准正态分布。
什么是标准正态分布呢?我们之前介绍过,正态分布是连续随机变量概率分布的一种。在现实生活中,大量随机现象的数据分布都近似于正态分布。
我这里再快速回顾一下这种分布的特点。
它以经过平均数的垂线为轴,左右对称展开,中间点最高,然后逐渐向两侧下降,分布曲线和 x 轴组成的面积为 1,表示不同事件出现的概率和为 1。平均数和标准差是正态分布的关键参数,它们会决定分布的具体形态。而标准正态分布是正态分布的一种,平均数为 0,标准差为 1。
理解了什么是标准正态分布,我们来看看 z 分数这个方法是如何运作的。实际上,z 分数标准化是利用标准正态分布的特点,计算一个给定分数距离平均数有多少个标准差。它的具体转换公式如下:
其中 为原始值, 为均值, 为标准差, 是变换后的值。
经过 z 分数的转换,高于平均数的分数会得到一个正的标准分,而低于平均数的分数会得到一个负的标准分数。更重要的是,转换后的数据是符合标准正态分布的。你通过理论或者具体的数值来推导一下,就会发现转换后的数据均值为 0,标准差为 1。
和归一化相比,z 分数这样的标准化不容易受到噪音数据的影响,并且保留了各维特征对目标函数的影响权重。
下面我们来看看,在 Python 中如何实现标准化,以及标准化对回归后系数的影响。
standardScaler = StandardScaler() #基于Z分数的标准化
standardScaler.fit(df)
df_standardized = standardScaler.transform(df) #对原始数据进行标准化,包括特征值和目标变量
df_features_standardized = df_standardized[:, 0:-1] #获取标准化之后的特征值
df_targets_standardized = df_standardized[:, -1] #获取标准化之后的特征值
#再次进行线性回归
regression_standardized = LinearRegression().fit(df_features_standardized, df_targets_standardized)
print(regression_standardized.score(df_features_standardized, df_targets_standardized))
print(regression_standardized.coef
其中,df 还是之前加载的 dataframe。运行这段代码,这次你得到的结果如下:
0.7355786478533118
[-0.07330367 -0.04144107 0.12194378 0.04074345 0.09805446 -0.19311408
0.29767387 -0.02916672 -0.34642803 0.34477088 -0.21410757 -0.19904179
0.11218058 -0.46369483]
表示拟合程度的分数仍然没有变。再次对比不同特征所对应的系数,你会发现这次最主要的正相关特征还是 age(0.29767387)和 tax(0.34477088),但是相比之前,明显房产税的税率占了更高的权重,更加合理。而最主要的负相关特征还是 rad(-0.34152292)和 lstat(-0.48468369),这两点都是合理的。

总结

今天我介绍了在机器学习领域里,如何使用统计里的数据分布来进行特征值的转换。这里,我帮你梳理了几个要点,便于你的记忆。
第一点,为什么有时候需要转换特征值?因为不同类型的特征取值范围不同,分布也不同,相互之间没有可比性。因此在线性回归中,通过这些原始值分析得到的权重,并不能代表每个特征实际的重要性。
第二点,如何使用归一化进行特征值转换?这里的归一化是指使用特征取值范围中的最大值和最小值,把原始值转换为 0 到 1 之间的值。这样处理的好处在于简单易行,便于理解。不过,它的缺点也很明显,由于只考虑了最大最小值,因此很容易受到异常数据点的干扰。
第三点,如何使用标准化进行转换?经过标准化处理之后,每种特征的取值都会变成一个标准正态分布,以 0 为均值,1 为标准差。和归一化相比,标准化使用了数据是正态分布的假设,不容易受到过大或过小值的干扰。
掌握了上面几个点,你就能很好的理解这一节的内容了。在实际的数据分析或者是统计建模的项目中,对于数值型的特征要保持敏感,看到它们的时候都要考虑一下,是不是需要进行特征值的转换?这样就能避免由于多种特征的不同分布而产生的误导性结论。

思考题

今天我们使用了三种方式处理 Boston Housing 的数据,并训练出三种线性回归的模型。请尝试使用这些模型的 predict 方法,对 test.csv 数据进行预测,看看每种模型的预测效果。(提示:如果你在 train.csv 上使用了某种特征值的转换,那么相应的 test.csv 数据也需要经过同样的处理。)
欢迎留言和我分享,也欢迎你在留言区写下今天的学习笔记。你也可以把今天的内容分享给你的好友,和他一起在实战中重新理解数学。
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 3

提建议

上一篇
28 | 熵、信息增益和卡方:如何寻找关键特征?
下一篇
30 | 统计意义(上):如何通过显著性检验,判断你的A/B测试结果是不是巧合?
unpreview
 写留言

精选留言(16)

  • 拉欧
    2019-02-20
    标准化和归一化未必能提高模型的准确度,但是会提高可解释性,是不是这个意思?

    作者回复: 是的。因为有些机器学习算法内部会根据输入数据自动调整值,所以对于算法效果而言,标准化和归一化不一定是必须的。

    8
  • Joe
    2019-02-27
    之前做机器学习算法的时候,采用特征缩放处理特征,能有效提高学习收敛效果。公式:x’=(x-x_mean)/(xmax-xmin)。不是单纯的归一,也保留了不同类别x之间的权重。

    作者回复: 也是一种可尝试的方法👍

    共 2 条评论
    6
  • 灰太狼
    2020-03-28
    归一化和标准化在使用中分别适合什么场景呢

    作者回复: 这是个好问题,最主要是和数据分布有关系。如果数据采样的分布接近于正态分布,建议Z分数标准化,让不同的数据组可比,否则建议归一化,将不同的数据统一到同样的区间便于处理

    共 2 条评论
    5
  • 骑行的掌柜J
    2020-06-11
    黄老师终于讲了理论后 上代码了 😂不过黄老师 我还了解到有种叫PCA降维的方法 他跟标准化之间有联系吗?是需要先标准话再PCA降维?谢谢

    作者回复: 巧了,我们之后会讲解PCA。虽然标准化不是PCA的必备预处理,但是通常我们还是会先进行标准化,再进行PCA降维。这是为了让不同的特征具有可比性,同时加速算法求解时的收敛速度

    3
  • 追梦
    2020-01-12
    老师,这如果是部署到线上模型,这些预处理应该怎么变化呢

    作者回复: 好问题,我想你说的线上模型是指某些机器学习中的predict或者叫scoring,就是指针对新的数据,进行分类或者回归的预测。可以根据线下训练数据的平均值和标准差来,如果新的数据远远超出了训练数据的均值和标准,可以看做outlier,根据合理的数值限制其范围

    3
  • Paul Shan
    2019-09-13
    归一化是按比例变化到[0,1]的区间里。 标准化是假设分布为正态分布,将数据变换为均值为0,方差为1的正态分布。 将所有数据按照统一尺度处理,有利于比较模型中的权重大小。
    3
  • 大熊
    2019-05-23
    以前用归一的时候都没考虑噪音的影响,今天get到了,nice

    作者回复: 很高兴对你有帮助

    2
  • qinggeouye
    2019-03-10
    思考题: """ 测试数据集 test.csv 测试数据的目标值 submission_example.csv """ df_test = pd.read_csv("/Users/qinggeouye/Desktop/GeekTime/MathematicProgrammer/29_featureTrans/test.csv") expected_test = pd.read_csv("/Users/qinggeouye/Desktop/GeekTime/MathematicProgrammer/29_featureTrans" "/submission_example.csv")['medv'] # 归一化 预测结果 minMaxScaler_test = MinMaxScaler() df_test_normalized = minMaxScaler_test.fit_transform(df_test.astype(dtype=float)) df_test_features_normalized = df_test_normalized[:, :] predicted_normalized = regression_normalized.predict(df_test_features_normalized) print("归一化预测结果与实际值的均方根误差:%s" % np.sqrt(np.mean((predicted_normalized - expected_test) ** 2))) # 标准化 预测结果 standardScaler_test = StandardScaler() standardScaler_test.fit(df_test.astype(dtype=float)) df_test_standardized = standardScaler_test.transform(df_test.astype(dtype=float)) df_test_features_standardized = df_test_standardized[:, :] predicted_standardized = regression_standardized.predict(df_test_features_standardized) print("标准化预测结果与实际值的均方根误差:%s" % np.sqrt(np.mean((predicted_standardized - expected_test) ** 2))) # 预测结果,两种特征转换预测结果相差无几,但与实际值相差较大 归一化预测结果与实际值的均方根误差:22.40003520184502 标准化预测结果与实际值的均方根误差:22.785218713879576
    展开

    作者回复: 确实,线性拟合程度不太好

    2
  • Geek_a50e46
    2020-02-07
    老师,那是不是标准化就没有缺点了?是不是可以完全用标准化替代归一化了呢?

    作者回复: 也不一定,如果样本量小的时候,可能归一化就够了。

    1
  • 阿信
    2019-07-05
    特征值处理,能加快收敛速度、降噪、标准化输出,这种好理解。但为什么会影响分析结果

    作者回复: 这要看具体的处理方式和模型,从处理方式的角度来看,有的时候特征工程可能会去掉一些不重要的特征,就会提升或者降低准确度。从模型的角度而言,有些比如线性回归模型需要量化地解释每个特征的重要程度,那么需要把不同特征统一化

    1
  • 013923
    2022-09-05 来自上海
    学习了,谢谢老师!
  • 春节十二响
    2021-04-07
    我对特征标准化的理解是,初始的特征数据不是纯数字,而是有量纲的,直接进行运算会搞出类似5m+6kg这样逻辑意义错误的操作。所以特征标准化实现的第一个效果是去量纲,把特征变成纯数字;第二个效果就是把不同特征投射到相近的数量级上,好做比较,也避免一些算法需要计算距离时,某个特征占得权重过大

    作者回复: 对,量纲的转换也是必要的

  • A君
    2020-07-26
    权重原来指的是衡量自变量对因变量产生正影响还负影响,权重的绝对值越大,表示该自变量对因变量的影响也越大。

    作者回复: 是的

  • 郭俊杰
    2020-05-21
    讲的很明白,thanks.

    作者回复: 很高兴对你有价值

  • 罗耀龙@坐忘
    2020-04-21
    茶艺师学编程 今天讲了特征变换的其中两种操作,一个是归一法,另一个是Z分数标准化(基于正态分布)。 我试着这么理解: 前者是把自变量变换在[0,1]之间,后者则是把自变量按照距离“平均值”的远近重新“排位”。 我感觉归一法就好像是对一张图片进行拉伸操作。而Z分数标准化,就是在放着铁粉的纸下面放上一根磁铁,轻轻抖动几下,看着原本散落的铁粉在磁铁的作用下排列出“磁感线”的图案。 ……不知道我这么理解对不对,请大家指点。
    展开
  • teddytyy
    2019-12-19
    为啥age一直是正相关特征?

    作者回复: 这点确实有点反常识,可能有些潜在的因素并未被发掘。例如老房子都在好地段,而新房多数建在偏远的地方,所以有时数据本身并不能说明一切,还需要人的理解,进行合理的解释