大家好,我是稀饭。今天给大家分享一下标准化在降维中的应用,内容源于毕业论文中的一部分研究拓展。
对于标准化,相信大家已经不陌生了,一组数据中的某个数,减掉它所在的这组数据的均值,再除以这组数据的标准差,就可以得到对应的标准化分数,也叫z分数。z分数可以回答这样一个问题:“一个给定分数距离平均数多少个标准差”。在平均数之上的分数会得到一个正的标准分数,在平均数之下的分数会得到一个负的标准分数。z分数是一种可以看出某分数在分布中相对位置的方法。
在降维过程中,标准化也非常重要,很多降维算法的前提要求就是数据进行标准化,去除量纲的影响,从而更好地完成降维的过程。以PCA(主成分分析)为例,PCA可以将原来高维的数据投影到某个低维的空间上并使得其方差尽量大。如果数据其中某一特征(矩阵的某一列)的数值特别大,那么它在整个误差计算的比重上就很大,那么可以想象在投影到低维空间之后,为了使低秩分解逼近原数据,整个投影会去努力逼近最大的那一个特征,而忽略数值比较小的特征。因为在建模前我们并不知道每个特征的重要性,这很可能导致了大量的信息缺失。为了“公平”起见,防止过分捕捉某些数值大的特征,我们会对每个特征先进行标准化处理,使得它们的大小都在相同的范围内,然后再进行PCA。
还是以PCA为例,我们来看一下标准化后的数据和未标准化后的数据的降维结果对比。
Step 1 我们模拟生成一组数据,这里使用python来构建,代码如下:
# 导入常用的基本库
import numpy as np
import pandas as pd
import scipy as sp
import matplotlib.pyplot as plt
dt_use = np.ones((300,300)) # 生成一个300×300的数据矩阵
for i in range(0,100): # 设定前100行为0-0.1的均匀分布随机数
for j in range(0,300):
dt_use[i,j] = random.uniform(0,0.1)
for i in range(100,200): # 设定100-200行为0.1-0.2的均匀分布随机数
for j in range(0,300):
dt_use[i,j] = random.uniform(0.1,0.2)
for i in range(200,300): # 设定200-300为0.2-0.3的均匀分布随机数
for j in range(0,300):
dt_use[i,j] = random.uniform(0.2,0.3)
现在生成的是一个300×300的矩阵,分为3组,第一组是取值在0-0.1之间的均匀分布随机数(前100行),第二组是取值在0.1-0.2之间的均匀分布随机数(第100-200行),第三组是取值在0.2-0.3之间的均匀分布随机数(第200-300行)。降维的目的是便于区分数据,从设定条件中我们知道,目前是有3组不同的数,降维后应该尽量保证原有的数据信息不丢失太多,且能很好地作区分,才有助于之后开展分类或聚类。
现在的数据点之间差异很小,都是0-1内的量级,所以我们直接使用PCA降维(设定降维目标为2维),依然可以得到比较好的降维结果,代码和结果如下所示:
from sklearn.decomposition import PCA # 导入降维需要的函数
dt_pca = PCA(2).fit_transform(dt_use)
plt.scatter(dt_pca[:, 0], dt_pca[:, 1])
plt.title('基于PCA的降维结果(未标准化)')
Step 2 现在我们把数据进行修改,让它的数值存在较明显的量纲差异:
for i in range(0,300): # 将每1列的某一个值改为很大
j = random.randint(0,299) # 随机调整j的值
dt_use[i,j] = random.uniform(1000,2000) # 选取一个相对很大的数
我们把每一行中任意一个的数据改为1000-2000的均匀分布随机数,使得每行数据都有一个明显过大的值(对于该行其他数据来说,是10000倍左右)。由于只改动了每行的1个值,剩下的(300-1)= 299个值未变动,所以近似来看还是能分为三组(去掉该极端值)。
现在我们依旧不进行标准化,来使用PCA降维,看得到的结果是否还能明显区分三组数据:
从图中可以看到,我们降维后的数据可视化结果发生了变化,从图中我们能看出区分度,但似乎很难说这能区分三组数据,我可以认为它有很多组区分。
然后我们进行标准化,再看看降维的结果如何:
dt_use = scale(dt_use) # 数据标准化
在标准化之后,我们又得到了比较易于观察出区分度的降维结果,这是因为标准化尽可能地弱化了量纲带来的影响。
但这种标准化的效果不是绝对的,下面我们来看两种特殊情况:
(1)将主对角线上的数据转为量纲较大的值
for i in range(0,300): # 将每1列的主对角线上额 改为很大
j = i # 调整j的值为i
dt_use[i,j] = random.uniform(1000,2000) # 选取一个很大的数
在这种情况下,我们可以看到,标准化后的降维效果并不理想,可能区分度还不如不标准化。
(2)将某一列的数据转为量纲较大的值,而不是每一行的随机某一列
j = random.randint(0,299) # 随机调整j的值
for i in range(0,300): # 将每1列的某一个值改为很大
dt_use[i,j] = random.uniform(1000,2000) # 选取一个很大的数
在这种情况下,我们可以看到,标准化的作用微乎其微,不标准化也能得到较好的降维结果。
最后做一个总结,标准化在降维中的应用是有意义的,但需要注意以下两种情况:
(1)量纲差异较大的数据点集中在某一个或少数几个特征上。标准化对降维的效果微乎其微,因为标准化是针对特征来进行的,如果仅仅是某一列(或少数几列)数值较大,而不是分散在多个列里,对降维的效果没有多少影响(“不公平”远弱于“公平”)。
(2)量纲差异较大的数据点过于分散在绝大多数特征上。标准化对降维的效果可能倒退,因为在这种极端情况下,相当于绝大多数的特征里面都存在量纲差异较大的“异常值”,标准化的目的是使各个列都有相近的取值水平,但某一列中的异常值,在标准化后它依旧是异常值,使用标准化并不能解决绝大多数列都存在异常值这个问题,此时使用一些普通的降维算法可能还不如不标准化得到的效果好(“不公平”内生化)。
数据分析手册



