你遇到过特征超过1000个的数据集吗?超过5万个的呢?我遇到过。降维是一个非常具有挑战性的任务,尤其是当你不知道该从哪里开始的时候。拥有这么多变量既是一个恩惠——数据量越大,分析结果越可信;也是一种诅咒——你真的会感到一片茫然,无从下手。
面对这么多特征,在微观层面分析每个变量显然不可行,因为这至少要几天甚至几个月,而这背后的时间成本是难以估计的。为此,我们需要一种更好的方法来处理高维数据,比如本文介绍的降维:一种能在减少数据集中特征数量的同时,避免丢失太多信息并保持/改进模型性能的方法。
每天,我们都会生成大量数据,而事实上,现在世界上约90%的数据都是在过去3到4年中产生的,这是个令人难以置信的现实。如果你不信,下面是收集数据的几个示例:
● 智能手机中的各类应用会收集大量关于你的个人信息,比如你所在的地点。
● 淘宝会收集你在其网站上购买、查看、点击的内容等数据。
● 赌场会跟踪每位客户的每一步行动。
随着数据的生成和数据收集量的不断增加,可视化和绘制推理图变得越来越困难。一般情况下,我们经常会通过绘制图表来可视化数据,比如假设我们手头有两个变量,一个年龄,一个身高。我们就可以绘制散点图或折线图,轻松反映它们之间的关系。
下图是一个简单的例子:
其中横坐标X1的单位为“千克”,纵坐标X2的单位为“磅”。可以发现,虽然是两个变量,但它们传达的信息是一致的,即物体的重量。所以我们只需选用其中的一个就能保留原始意义,把2维数据压缩到1维(Y1)后,上图就变成:
类似地,我们可以把数据从原本的p维转变为一系列k维的子集(k<<n),这就是降维。
为什么要降维?
以下是在数据集中应用降维的用处:
● 低维数据有助于减少计算/训练用时。
● 一些算法在高维度数据上容易表现不佳,降维可提高算法可用性。
● 降维可以用删除冗余特征解决多重共线性问题。比如我们有两个变量:“一段时间内在跑步机上的耗时”和“卡路里消耗量”。这两个变量高度相关,在跑步机上花的时间越长,燃烧的卡路里自然就越多。因此,同时存储这两个数据意义不大,只需一个就够了。
● 降维有助于数据可视化。如前所述,如果数据维度很高,可视化会变得相当困难,而绘制二维三维数据的图表非常简单。
数据集1:Big Mart Sales III
降维技术一览
数据维度的降低方法主要有两种:
● 寻找一组较小的新变量,其中每个变量都是输入变量的组合,包含与输入变量基本相同的信息(降维)。
1. 缺失值比率(Missing Value Ratio)
假设你有一个数据集,你第一步会做什么?在构建模型前,对数据进行探索性分析必不可少。但在浏览数据的过程中,有时候我们会发现其中包含不少缺失值。如果缺失值少,我们可以填补缺失值或直接删除这个变量;如果缺失值过多,你会怎么办呢?
当缺失值在数据集中的占比过高时,一般我会选择直接删除这个变量,因为它包含的信息太少了。但具体删不删、怎么删需要视情况而定,我们可以设置一个阈值,如果缺失值占比高于阈值,删除它所在的列。阈值越高,降维方法越积极。
下面是具体代码:
-
# 导入需要的库
-
import pandas as pd
-
import numpy as np
-
import matplotlib.pyplot as plt
加载数据:
-
# 读取数据
-
train=pd.read_csv("Train_UWu5bXk.csv")
[注]:应在读取数据时添加文件的路径。
用.isnull().sum()
检查每个变量中缺失值的占比:
-
train.isnull().sum()/len(train)*100
如上表所示,缺失值很少。我们设阈值为20%:
-
# 保存变量中的缺失值
-
a = train.isnull().sum()/len(train)*100
-
# 保存列名
-
variables = train.columns
-
variable = [ ]
-
for i in range(0,12):
-
if a[i]<=20: #setting the threshold as 20%
-
variable.append(variables[i])
2. 低方差滤波(Low Variance Filter)
如果我们有一个数据集,其中某列的数值基本一致,也就是它的方差非常低,那么这个变量还有价值吗?和上一种方法的思路一致,我们通常认为低方差变量携带的信息量也很少,所以可以把它直接删除。
放到实践中,就是先计算所有变量的方差大小,然后删去其中最小的几个。需要注意的一点是:方差与数据范围相关的,因此在采用该方法前需要对数据做归一化处理。
放在示例中,我们先估算缺失值:
-
train['Item_Weight'].fillna(train['Item_Weight'].median, inplace=True)
-
train['Outlet_Size'].fillna(train['Outlet_Size'].mode()[0], inplace=True)
检查缺失值是否已经被填充:
-
train.isnull().sum()/len(train)*100
![4674cf27993aa99c09e6c08d0636726fc303b193](https://i-blog.csdnimg.cn/blog_migrate/7c700bcb1dd8bf35f796dde35b3732ab.png)
再计算所有数值变量的方差:
-
train.var()
![2621e7796e37d122b2c371c0e713964dca4e4996](https://i-blog.csdnimg.cn/blog_migrate/47f7ef077ff370640bd8131ad506e5cf.png)
如上图所示,和其他变量相比,Item_Visibility的方差非常小,因此可以把它直接删除。