归一化 vs 标准化 定量的分析
共 8913字,需浏览 18分钟
·
2021-04-25 10:27
点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
不要再用sklearn中的StandarScaler作为默认的特征缩放方法了,别的方法可以给你7%的准确率提升!
每个搞机器学习的人都知道特征尺度是一个重要的问题。参考之前的文章。
讨论最多的两种缩放方法是归一化和标准化。归一化通常意味着将值重新划分为[0,1]的范围。标准化通常意味着缩放数据的均值为0,标准差为1(单位方差)。
在这个博客中,我做了一些实验,希望能够回答以下问题:
我们应该在所有情况下都做缩放吗?
有没有一种最好的缩放技术?
不同的缩放技术如何影响不同的分类器?
我们是否应该将缩放技术作为模型的一个重要超参数?
我将分析在多个实验设置中对特征应用不同缩放方法的实证结果。
0. 为什么么要讨论两者的区别?
首先,我试图理解归一化和标准化之间的区别。
因此,我遇到了Sebastian Raschka写的这个优秀的blog:https://sebastianraschka.com/Articles/2014aboutfeature_scaling.html,它提供了一个数学背景,满足了我的好奇心。如果您不熟悉归一化或标准化概念,请花5分钟阅读这个博客。
在处理由著名的Hinton使用梯度下降方法(如神经网络)训练的分类器时,也需要很好的对特征缩放进行解释。
我们学了一些数学,就这样?不完全是。
当我检查流行的机器学习库Sklearn时,我发现有许多不同的缩放方法。可以很好地可视化不同的标量对具有异常值的数据的影响。但是他们没有展示它如何影响不同分类器的分类任务。
我看到很多机器学习工作流教程使用StandardScaler (通常称为Z-score标准化)或MinMaxScaler (通常称为最小-最大归一化)来缩放特征。为什么没有人使用其他缩放技术进行分类?有没有可能StandardScaler或MinMaxScaler就是最好的缩放方法了?
我在教程中没有看到任何关于为什么或者什么时候使用它们的解释,所以我想我应该通过运行一些实验来研究这些技术的性能。这就是这篇文章的全部内容。
项目细节
像许多数据科学项目一样,让我们读取一些数据并使用一些开箱即用的分类器进行试验。
数据集
Sonar数据集。它包含208行和60个特征列。这是一个分类任务,以区分声纳信号是通过金属圆筒还是粗略圆柱形岩石反弹的。
这是一个均衡的数据集:
sonar[60].value_counts() # 60 is the label column name
M 111
R 97
这个数据集中的所有特征都在0到1之间,但是不能确保每个特征中1是最大值或0是最小值。
我选择这个数据集是因为,一方面,它很小,所以我可以很快地进行实验。另一方面,这是一个困难的问题,没有一个分类器可以达到接近100%的准确率,所以我们可以比较有意义的结果。
在最后一节中,我们将试验更多的数据集。
代码
在预处理阶段,我已经计算了所有的结果(这需要一些时间)。所以我们只加载结果文件并处理它。
产生结果的代码可以在我的GitHub中找到:
https://github.com/shaygeller/NormalizationvsStandardization.git
我从Sklearn中选取了一些最流行的分类模型,记为:
(MLP是多层感知器,神经网络)
我使用的缩放方法记为:
不要将上面列表中的最后一个Normalizer与我之前讨论过的min-max normalization技术混淆。min-max归一化是列表中的第二个,名为MinMaxScaler。Sklearn中的Normalizer类将样本单独归一化为单位长度。它不是基于列的,而是基于行的归一化技术。
实验细节:
当需要重现性时使用相同的种子。
随机将数据分成训练测试集,分别为80%-20%。
所有结果都是训练集的10-fold随机交叉验证的准确性得分。
我不在这里讨论测试集的结果。通常,测试集应该是隐藏的,我们关于分类器的所有结论应该只从交叉验证分数中得出。
在第4部分中,我执行了嵌套交叉验证。一个内部交叉验证包含5个随机分割用于超参数调优,另一个外部CV包含10个随机分割用于使用最佳参数获得模型的分数。同样在这一部分,所有的数据都是从训练集上获取的。一图胜千言:
读取结果文件
import os
import pandas as pd
results_file = "sonar_results.csv"
results_df = pd.read_csv(os.path.join("..","data","processed",results_file)).dropna().round(3)
results_df
1. 开箱即用的分类器
import operator
results_df.loc[operator.and_(results_df["Classifier_Name"].str.startswith("_"), ~results_df["Classifier_Name"].str.endswith("PCA"))].dropna()
不错的结果。通过查看CV_mean列,我们可以看到,目前MLP处于领先地位。SVM的性能最差。
标准差基本相同,所以我们主要可以通过均值来判断。下面的所有结果将是10-fold交叉验证随机分割的平均得分。
现在,让我们看看不同的缩放方法如何改变每个分类器的分数
2. 分类器+缩放
import operator
temp = results_df.loc[~results_df["Classifier_Name"].str.endswith("PCA")].dropna()
temp["model"] = results_df["Classifier_Name"].apply(lambda sen: sen.split("_")[1])
temp["scaler"] = results_df["Classifier_Name"].apply(lambda sen: sen.split("_")[0])
def df_style(val):
return 'font-weight: 800'
pivot_t = pd.pivot_table(temp, values='CV_mean', index=["scaler"], columns=['model'], aggfunc=np.sum)
pivot_t_bold = pivot_t.style.applymap(df_style,
subset=pd.IndexSlice[pivot_t["CART"].idxmax(),"CART"])
for col in list(pivot_t):
pivot_t_bold = pivot_t_bold.applymap(df_style,
subset=pd.IndexSlice[pivot_t[col].idxmax(),col])
pivot_t_bold
第一行没有索引名,是没有应用任何缩放方法的算法。
import operator
cols_max_vals = {}
cols_max_row_names = {}
for col in list(pivot_t):
row_name = pivot_t[col].idxmax()
cell_val = pivot_t[col].max()
cols_max_vals[col] = cell_val
cols_max_row_names[col] = row_name
sorted_cols_max_vals = sorted(cols_max_vals.items(), key=lambda kv: kv[1], reverse=True)
print("Best classifiers sorted:\n")
counter = 1
for model, score in sorted_cols_max_vals:
print(str(counter) + ". " + model + " + " +cols_max_row_names[model] + " : " +str(score))
counter +=1
各模型的最佳分类器:
SVM + StandardScaler : 0.849
MLP + PowerTransformer-Yeo-Johnson : 0.839
KNN + MinMaxScaler : 0.813
LR + QuantileTransformer-Uniform : 0.808
NB + PowerTransformer-Yeo-Johnson : 0.752
LDA + PowerTransformer-Yeo-Johnson : 0.747
CART + QuantileTransformer-Uniform : 0.74
RF + Normalizer : 0.723
分析一下结果
没有一种单一的缩放方法可以全部管用
我们可以看到缩放改进了结果。支持向量机、MLP、KNN和NB在不同尺度下均有显著提高。
注意NB, RF, LDA, CART不受某些缩放方法的影响。当然,这与每个分类器的工作方式有关。树不受尺度的影响,因为分裂准则首先对每个特征的值进行排序,然后计算分裂的基尼熵。某些缩放方法保持这个排序,所以精度分数没有变化。NB不受影响,因为模型的先验由每个类中的计数决定,而不是由实际值决定。线性判别分析(LDA)使用类之间的变化来得到它的系数,因此缩放也不重要。
有些缩放方法,比如QuantileTransformer-Uniform,并不能保持每个特征中值的精确顺序,因此即使在上面的分类器中,得分的变化也与其他缩放方法无关。
3. 分类器+缩放+PCA
我们知道一些著名的机器学习方法,比如PCA,可以从缩放中获益。我们尝试向工作流中添加PCA(n_components=4)并分析结果。
import operator
temp = results_df.copy()
temp["model"] = results_df["Classifier_Name"].apply(lambda sen: sen.split("_")[1])
temp["scaler"] = results_df["Classifier_Name"].apply(lambda sen: sen.split("_")[0])
def df_style(val):
return 'font-weight: 800'
pivot_t = pd.pivot_table(temp, values='CV_mean', index=["scaler"], columns=['model'], aggfunc=np.sum)
pivot_t_bold = pivot_t.style.applymap(df_style,
subset=pd.IndexSlice[pivot_t["CART"].idxmax(),"CART"])
for col in list(pivot_t):
pivot_t_bold = pivot_t_bold.applymap(df_style,
subset=pd.IndexSlice[pivot_t[col].idxmax(),col])
pivot_t_bold
分析一下结果
大多数的缩放方法使用PCA对模型都有改进,但是并不针对具体的缩放方法。
让我们来看看“QuantileTransformer-Uniform”,这是得分最高的方法。
在LDA-PCA中,它将结果从0.704提高到0.783(准确率提高了8% !),但是在RF-PCA中,它使情况变得更糟,从0.711降到0.668(准确率下降了4.35% !)
另一方面,使用RF-PCA与“QuantileTransformer-Normal”,提高精度到0.766(5%的精度提升!)
我们可以看到PCA只改善了LDA和RF,所以PCA并不是一个神奇的解决方案。
这样很好。我们没有调试n_components参数,即使我们调参了,PCA也不能保证改进预测。
我们可以看到StandardScaler和MinMaxScaler在16个案例中只有4个获得了最好的分数。所以我们应该仔细考虑选择什么样的缩放方法,即使是默认的。
我们可以得出结论,虽然PCA是一个已知的组件,可以从缩放中获益,但是没有一种缩放方法总是能够改善我们的结果,其中一些方法甚至会造成伤害(带standard - scaler的RF-PCA).
数据集也是一个重要因素。为了更好地理解缩放方法对PCA的影响,我们应该对更多不同的数据集进行实验(类不平衡、不同尺度的特征以及具有数值和分类特征的数据集)。我在第5部分做这个分析
4. 分类器+缩放+PCA+超参数调参
对于给定的分类器,不同缩放方法的精度评分存在较大差异。我们可以假设,当超参数调优之后,缩放技术之间的差别会变小,我们可以使用StandardScaler或MinMaxScaler,就像网上上许多教程中使用的那样。
让我们看看是不是这样!
首先,NB不在这里,因为NB没有参数可调。
我们可以看到,几乎所有的算法都从超参数调优中获益,与前面步骤的结果相比。一个有趣的例外是MLP,它的结果变差了。这可能是因为神经网络很容易对数据进行过拟合(尤其是当参数的数量远远大于训练样本的数量时),我们没有很小心的进行提前停止以避免它,也没有应用任何正则化。
然而,即使对超参数进行了调优,使用不同缩放方法得到的结果仍然存在很大差异。如果我们将不同的缩放技术与广泛使用的标准缩放技术进行比较,在使用其他技术时,我们可以获得高达7%的精确度提升 (KNN列)。
这一步的主要结论是,即使超参数被调优,改变缩放方法也会显著影响结果。因此,我们应该将缩放方法作为模型的一个重要超参数。
第5部分包含对更多不同数据集的更深入分析。如果你不想深入研究,可以直接跳到结论部分。
5. 在更多的数据集上再做一遍
为了更好地理解和得出更一般化的结论,我们应该使用更多的数据集进行实验。
我们将像第3节一样,对几个具有不同特征的数据集应用分类器+缩放+PCA,并分析结果。所有数据集均取自Kaggel。
为了方便起见,我只从每个数据集中选择了数值列。在多元数据集(数值和分类特性)中,关于如何缩放特征一直存在争论。
我没有超调任何分类器的参数。
5.1 澳大利亚降雨数据集
链接:https://www.kaggle.com/jsphyg/weather-dataset-rattle-package#weatherAUS.csv
分类任务: 预测会不会下雨?
度量: 准确率
数据集大小: (56420, 18)
每个类别包含: No 43993 Yes 12427
dataset.describe()
我们会怀疑,由于特征的尺度不同,缩放会改善分类结果(查看上表中的最小最大值,其他一些特征甚至会变得更糟)。
结果
结果分析
我们可以看到StandardScaler从来没有得到最高的分数,也没有得到最低的分数。
我们可以看到StandardScaler和其他方法之间的差异高达20%。(CART-PCA列)
我们可以看到缩放通常会改善结果。以支持向量机为例,支持向量机从78%跳到了99%。
5.2 银行市场数据集
链接:https://www.kaggle.com/henriqueyamahata/bank-marketing
分类任务: 预测客户会不会存款?
度量: AUC (数据集是不均衡的)
数据集大小: (41188, 11)
每个类别的数量: no 36548 yes 4640
dataset.describe()
结果
结果分析
我们可以看到,在这个数据集中,即使特征具有不同的尺度,缩放时使用PCA并不总是改善结果。然而,在每个PCA列中第二好的分数与最好的分数非常接近。这可能表明,对PCA的成分的数量进行超调和使用缩放将比完全不缩放得到更好的结果。
同样,没有一个单一的缩放方法脱颖而出。
另一个有趣的结果是,在大多数模型中,所有的缩放方法都没有产生太大的影响(通常是1%-3%的改进)。让我们记住这是一个不平衡的数据集,我们没有调超参数。另一个原因是AUC的分数已经很高(约90%),所以很难看到明显的改善。
5.3 天体监测数据集
链接:https://www.kaggle.com/lucidlenn/sloan-digital-sky-survey
分类任务: 预测一个天体是星系,恒星还是类星体
度量: 准确率(多类)
数据集大小: (10000, 18)
每个类别的数量: GALAXY 4998 STAR 4152 QSO 850
dataset.describe()
结果
结果分析
我们可以看到缩放大大改善了结果。我们可以期待它,因为它包含不同尺度的特征。
我们可以看到,当我们使用PCA的时候,RobustScaler几乎总是赢家。这可能是由于这个数据集中有许多异常值导致了PCA特征向量有所变化。另一方面,当我们不使用PCA时,这些异常值不会产生这样的影响。我们应该做一些数据研究来验证这一点。
如果我们将StandardScaler与其他缩放方法进行比较,其准确度会有高达5%的差异。所以这是另一个需要用多种缩放技术进行实验的指标。
主成分分析几乎总是受益于缩放。
5.4 收入分类数据集
链接:https://www.kaggle.com/lodetomasi1995/income-classification
分类任务: 预测收入大于50k还是小于50k
度量: AUC (不平衡数据集)
数据集大小: (32561, 7)
每个类别的数量: <=50K 24720 >50K 7841
dataset.describe()
结果
结果分析
这里,我们有一个不平衡的数据集,但我们可以看到,缩放在改善结果方面做得很好(高达20%!)这可能是因为与银行营销数据集相比,AUC评分较低(约80%),因此更容易看到重大改进。
尽管StandardScaler没有突出显示(我只突出显示了每个列中的第一个最佳得分),但在许多列中,它可以获得与最佳相同的结果,但并不总是如此。从运行时间上看(这里没有出现),我可以告诉你,运行StandatdScaler要比许多其他缩放方法快得多。所以,如果你急于得到一些结果,这可能是一个很好的起点。但是如果你想从你的模型中挤出每一个百分比,你可能想要体验多种缩放方法。
同样,没有单一的最佳缩放方法。
PCA几乎总是受益于缩放
结论
尝试多种缩放方法可以显著提高你在分类任务上的得分,即使你调整了超参数。因此,你应该将缩放方法视为模型的一个重要超参数。
缩放方法对不同分类器的影响不同。基于距离的分类器,如SVM、KNN和MLP(神经网络),极大地受益于缩放。但是,即使树(CART、RF)对某些缩放方法是不可知的,也可以从其他方法中获益。
了解模型预处理方法背后的数学原理是理解结果的最佳方法。(例如,树是如何工作的,以及为什么一些缩放方法没有影响它们)。如果你的模型是随机森林,而你不知道如何应用StandardScaler,那么它还可以为您节省大量时间。
像PCA这样的预处理方法已知可以从缩放中获益,确实也是这样。当没有的时候,可能是由于PCA的分量参数个数设置不当、数据中的异常值或缩放方法选择不当。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~