你是否曾经处理过具备一千多个特征的数据集?5万多个特征呢?我曾经有过,让我告诉你这是一项很是具备挑战性的任务,特别是若是你不知道从哪里开始的时候!拥有大量的变量既是好事,也是坏事。咱们有大量的数据用于分析,这很棒,但因为规模太大,它变得很是具备挑战性。算法
在微观层面分析每一个变量是不可行的。咱们可能须要几天或几个月才能进行任何有意义的分析,咱们将会为咱们的业务损失大量的时间和金钱!更不用说这将须要的计算能力。咱们须要一种更好的方法来处理高维数据,以便咱们可以快速从中提取模式和看法。那么咱们如何处理这样的数据集呢?编程
固然是使用降维技术。你可使用这个技术来减小数据集中的特征数量,而没必要丢失太多信息并保持(或改进)模型的性能。正如你将在本文中看到的,这是处理大型数据集的一种很是强大的方法。数组
这是一个能够在实际场景中使用的各类降维技术的综合指南。在深刻介绍我所涵盖的12种不一样技术以前,咱们将首先了解这个概念是什么以及为何要使用它。而且每种技术都有本身的Python实现代码,让你更好的熟悉它。安全
咱们天天都在生成大量的数据。事实上,世界上90%的数据都是在过去的3到4年中产生的!这些数字真的使人难以置信。如下是收集的数据的一些例子:数据结构
随着数据生成和收集量的不断增长,可视化和绘制分析变得愈来愈具备挑战性。进行可视化的最多见方法之一是经过图表。假设咱们有2个变量,年龄Age和身高Height。咱们可使用Age和Height之间的散点图或线图,并轻松地将它们的关系可视化:app
如今考虑咱们有100个变量(p = 100)的状况。在这种状况下,咱们能够有100(100-1)/ 2 = 5000个不一样的图。将它们分别可视化是没有多大意义的,对吧?在咱们有大量变量的状况下,最好选择这些变量的一个子集(p << 100),它获取的信息与原始变量集同样多。dom
让咱们用一个简单的例子来理解这一点。考虑下面的图像:机器学习
这里咱们有相似物体的重量,单位为Kg(X1)和磅(X2)。若是咱们使用这两个变量,它们将传达相相似的信息。所以,仅使用一个变量是有意义的。咱们能够将数据从2D(X1和X2)转换为1D(Y1),以下所示:分布式
相似地,咱们能够将数据的p维度减小为k维度的子集(k << n)。这称为降维。ide
如下是将降维应用于数据集的一些好处:
是时候深刻了解本文的关键 - 各类降维技术!咱们将使用一个实践问题:Big Mart Sales III中的数据集点击这里下载数据提取码为:fmk0 。
降维能够经过两种不一样的方式完成:
咱们如今将介绍各类降维技术以及如何在Python中实现它们。
假设你有一个数据集。你的第一步是什么?在构建模型以前,你应该会但愿先探索数据。在研究数据时,你会发现数据集中存在一些缺失值。怎么办?你将尝试找出这些缺失值的缘由,而后将输入它们或彻底删除具备缺失值的变量(使用适当的方法)。
若是咱们有太多的缺失值(好比说超过50%)怎么办?咱们应该输入这些缺失值仍是直接删除变量?我宁愿放弃变量,由于它没有太多的信息。然而,这不是一成不变的。咱们能够设置一个阈值,若是任何变量中缺失值的百分比大于该阈值,咱们将删除该变量。
让咱们在Python中实现这种方法。
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
正如你在上表中所看到的,并无太多的缺失值(实际上只有2个变量具备缺失值)。咱们可使用适当的方法来输入变量,或者咱们能够设置阈值,好比20%,并删除具备超过20%缺失值的变量。让咱们看看如何在Python中完成此操做:
a = train.isnull().sum()/len(train)*100
variables = train.columns
variable = [ ]
for i in range(0,12):
if a[i]<=20: #将阈值设置为20%
variable.append(variables[i])
所以,要使用的变量存储在“variables”中,它只包含哪些缺失值小于20%的特征
假设咱们的数据集中的一个变量,其中全部观察值都是相同的,例如1。若是咱们要使用此变量,你认为它能够改进咱们将要创建的模型么?答案固然是否认的,由于这个变量的方差为零。
所以,咱们须要计算给出的每一个变量的方差。而后删除与咱们的数据集中其余变量相比方差比较小的变量。如上所述,这样作的缘由是方差较小的变量不会影响目标变量。
让咱们首先使用已知ItemWeight观察值的中值来填充temWeight列中的缺失值。对于OutletSize列,咱们将使用已知OutletSize值的模式来填充缺失值:
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
嘿瞧!咱们都已经准备好了。如今让咱们计算全部数值变量的方差。
train.var()
如上面的输出所示,与其余变量相比,Item_Visibility的方差很是小。咱们能够安全地删除此列。这就是咱们应用低方差过滤器的方法。让咱们在Python中实现这个:
numeric = train[['Item_Weight', 'Item_Visibility', 'Item_MRP', 'Outlet_Establishment_Year']]
var = numeric.var()
numeric = numeric.columns
variable = [ ]
for i in range(0,len(var)):
if var[i]>=10: #将阈值设置为10%
variable.append(numeric[i+1])
上面的代码为咱们提供了方差大于10的变量列表。
两个变量之间的高度相关意味着它们具备类似的趋势,而且可能携带相似的信息。这能够大大下降某些模型的性能(例如线性回归和逻辑回归模型)。咱们能够计算出本质上是数值的独立数值变量之间的相关性。若是相关系数超过某个阈值,咱们能够删除其中一个变量(丢弃一个变量是很是主观的,而且应该始终记住该变量)。
做为通常准则,咱们应该保留那些与目标变量显示出良好或高相关性的变量。
让咱们在Python中执行相关计算。咱们将首先删除因变量(ItemOutletSales)并将剩余的变量保存在新的DataFrame(df)中。
df=train.drop('Item_Outlet_Sales', 1)
df.corr()
太棒了,咱们的数据集中没有任何具备高相关性的变量。一般,若是一对变量之间的相关性大于0.5-0.6,咱们真的应该认真的考虑丢弃其中的一个变量。
随机森林是最普遍使用的特征选择算法之一。它附带内置的重要功能,所以你无需单独编程。这有助于咱们选择较小的特征子集。
咱们须要经过应用一个热编码将数据转换为数字形式,由于随机森林(Scikit-Learn实现)仅采用数字输入。让咱们也删除ID变量(Item_Identifier和Outlet_Identifier),由于这些只是惟一的数字,目前对咱们来讲并不重要。
from sklearn.ensemble import RandomForestRegressor
df=df.drop(['Item_Identifier', 'Outlet_Identifier'], axis=1)
model = RandomForestRegressor(random_state=1, max_depth=10)
df=pd.get_dummies(df)
model.fit(df,train.Item_Outlet_Sales)
拟合模型后,绘制特征重要性图:
features = df.columns
importances = model.feature_importances_
indices = np.argsort(importances)[-9:] # top 10 features
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()
基于上图,咱们能够手动选择最顶层的特征来减小数据集中的维度。值得注意的是,咱们可使用sklearn的SelectFromModel来实现这一点。它根据权重的重要性来选择特征。
from sklearn.feature_selection import SelectFromModel
feature = SelectFromModel(model)
Fit = feature.fit_transform(df, train.Item_Outlet_Sales)
按照如下步骤来理解和使用“反向特征消除”技术:
在构建线性回归或逻辑回归模型时,可使用此方法。咱们来看看它的Python实现:
from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import RFE
from sklearn import datasets
lreg = LinearRegression()
rfe = RFE(lreg, 10)
rfe = rfe.fit_transform(df, train.Item_Outlet_Sales)
咱们须要指定算法和要选择的特征数量,并返回从反向特征消除中得到的变量列表。咱们还可使用“ rfe.ranking”命令检查变量的排名。
这与咱们在上面看到的反向特征消除的过程相反。咱们是尝试找到改善模型性能的最佳特征,而不是消除特征。该技术的工做原理以下:
让咱们用Python实现它:
from sklearn.feature_selection import f_regression
ffs = f_regression(df,train.Item_Outlet_Sales )
这将返回一个数组,其中包含变量的F值和与每一个F值对应的p值。为了咱们的目的,咱们将选择F值大于10的变量:
variable = [ ]
for i in range(0,len(df.columns)-1):
if ffs0 >=10:
variable.append(df.columns[i])
这为咱们提供了基于正向特征选择算法的最多变量。
注意:反向特征消除和正向特征选择都是很是耗时且计算成本高的。它们实际上仅用于具备少许输入变量的数据集。
到目前为止咱们看到的技术一般在咱们的数据集中没有太多变量时使用。这些或多或少的特征选择技术,在接下来的部分中,咱们将使用Fashion MNIST数据集,该数据集包含属于不一样类型服装的图像,例如T恤,裤子,包等。数据集可点击此处下载,提取码为:a708。
该数据集共有70,000张图像,其中60,000张在训练集中,其他10,000张是测试图像。在本文的范围中,咱们将仅处理训练图像。训练集文件采用zip格式。解压缩zip文件后,你将得到一个.csv文件和一个包含这60,000张图像的训练集文件夹。每一个图像的相应标签能够在'train.csv'文件中找到。
假设咱们有两个变量:收入和教育。这些变量可能具备高度相关性,由于具备较高教育水平的人每每具备显着较高的收入,反之亦然。
在因子分析技术中,变量按其相关性进行分组,即特定组内的全部变量之间具备高度相关性,但每每与其余组的变量之间相关性较低。在这里,每一个组都被称为一个因子。与原始数据维度相比,这些因子的数量不多。可是,这些因子每每很难观察到。
让咱们先读入训练集文件夹中包含的全部图像:
import pandas as pd
import numpy as np
from glob import glob
import cv2
images = [cv2.imread(file) for file in glob('train/*.png')]
注意:你必须使用train文件夹的路径替换glob函数内的路径。
如今咱们将这些图像转换为 numpy数组格式,以便咱们能够执行数学运算并绘制图像。
images = np.array(images)
images.shape
(60000,28,28,3)
如上所示,它是一个三维数组。咱们必须将它转换为一维的,由于全部即将出现的技术只须要一维输入。为此,咱们须要展平图像:
image = []
for i in range(0,60000):
img = images[i].flatten()
image.append(img)
image = np.array(image)
如今让咱们建立一个DataFrame,其中包含每一个图像中每一个像素的像素值,以及它们对应的标签(对于标签,咱们将使用train.csv文件)。
train = pd.read_csv("train.csv") # 给出你的train.csv文件的完整路径
feat_cols = [ 'pixel'+str(i) for i in range(image.shape[1]) ]
df = pd.DataFrame(image,columns=feat_cols)
df['label'] = train['label']
如今咱们将使用因子分析来分解数据集:
from sklearn.decomposition import FactorAnalysis
FA = FactorAnalysis(n_components = 3).fit_transform(df[feat_cols].values)
这里,n_components将决定转换数据中的因子数量。转换数据后,是时候可视化结果了:
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize=(12,8))
plt.title('Factor Analysis Components')
plt.scatter(FA[:,0], FA[:,1])
plt.scatter(FA[:,1], FA[:,2])
plt.scatter(FA[:,2],FA[:,0])
看起来很棒,不是吗?咱们能够在上图中看到全部不一样的因素。这里,x轴和y轴表示分解因子的值。正如我前面提到的,很难单独观察这些因素,但咱们已经可以成功地减小数据的维度。
PCA是一种技术,能够帮助咱们从现有的大量变量中提取一组新的变量。这些新提取的变量称为主成分。为了便于你快速学习PCA降维,如下是你在进一步处理以前应该了解的关于PCA的一些要点:
在继续以前,咱们将从咱们的数据集中随机绘制一些图像:
rndperm = np.random.permutation(df.shape[0])
plt.gray()
fig = plt.figure(figsize=(20,10))
for i in range(0,15):
ax = fig.add_subplot(3,5,i+1)
ax.matshow(df.loc[rndperm[i],feat_cols].values.reshape((28,28*3)).astype(float))
让咱们使用Python实现PCA降维并转换数据集:
from sklearn.decomposition import PCA
pca = PCA(n_components=4)
pca_result = pca.fit_transform(df[feat_cols].values)
在这种状况下,n_components将决定转换数据中的主要成分的数量。让咱们看一下使用这4个成分解释了多少差别。咱们将使用explainvarianceratio_来计算相同的内容。
plt.plot(range(4), pca.explained_variance_ratio_)
plt.plot(range(4), np.cumsum(pca.explained_variance_ratio_))
plt.title("Component-wise and Cumulative Explained Variance")
在上图中,蓝线表示按成分解释的方差,而橙线表示累积解释的方差。咱们只用四个组件就能够解释数据集中大约60%的方差变化。如今让咱们尝试可视化每一个分解的成分:
import seaborn as sns
plt.style.use('fivethirtyeight')
fig, axarr = plt.subplots(2, 2, figsize=(12, 8))
sns.heatmap(pca.components_[0, :].reshape(28, 84), ax=axarr0, cmap='gray_r')
sns.heatmap(pca.components_[1, :].reshape(28, 84), ax=axarr0, cmap='gray_r')
sns.heatmap(pca.components_[2, :].reshape(28, 84), ax=axarr1, cmap='gray_r')
sns.heatmap(pca.components_[3, :].reshape(28, 84), ax=axarr1, cmap='gray_r')
axarr0.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[0]*100),
fontsize=12
)
axarr0.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[1]*100),
fontsize=12
)
axarr1.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[2]*100),
fontsize=12
)
axarr1.set_title(
"{0:.2f}% Explained Variance".format(pca.explained_variance_ratio_[3]*100),
fontsize=12
)
axarr0.set_aspect('equal')
axarr0.set_aspect('equal')
axarr1.set_aspect('equal')
axarr1.set_aspect('equal')
plt.suptitle('4-Component PCA')
咱们添加到PCA技术中的每一个额外维度获取模型中的方差愈来愈少。第一个部分是最重要的成分,其次是第二个成分,而后是第三个成分,依此类推。
咱们还可使用奇异值分解 (SVD)将咱们的原始数据集分解为其成分,从而减小维数。
SVD将原始变量分解为三个组成矩阵。它主要用于从数据集中删除冗余的特征。它使用特征值和特征向量的概念来肯定这三个矩阵。因为本文的范围,咱们不会深刻研究它的理论,但让咱们坚持咱们的计划,即减小数据集中的维度。
让咱们实现SVD并分解咱们的原始变量:
from sklearn.decomposition import TruncatedSVD
svd = TruncatedSVD(n_components=3, random_state=42).fit_transform(df[feat_cols].values)
让咱们经过绘制前两个主成分来可视化变换后的变量:
plt.figure(figsize=(12,8))
plt.title('SVD Components')
plt.scatter(svd[:,0], svd[:,1])
plt.scatter(svd[:,1], svd[:,2])
plt.scatter(svd[:,2],svd[:,0])
上面的散点图很是清晰地向咱们展现了分解的成分。如前所述,这些组件之间没有太多相关性。
独立成分分析(ICA)是基于信息理论的,也是最普遍使用的降维技术之一。PCA和ICA之间的主要区别在于PCA寻找不相关的因素,而ICA寻找独立因素。
若是两个变量不相关,则意味着它们之间没有线性关系。若是它们是独立的,则意味着它们不依赖于任何其余变量。例如,一我的的年龄与该人吃什么或他/她看多少电视无关。
该算法假设给定变量是一些未知潜在变量的线性混合。它还假设这些潜在变量是相互独立的,即它们不依赖于其余变量,所以它们被称为观察数据的独立成分。
让咱们直观地比较一下PCA和ICA,以便更好地了解它们的不一样之处:
这里,图像(a)表示PCA结果,而图像(b)表示相同数据集上的ICA结果。
PCA的方程是x = W x。
如今咱们必须找到一个非混合矩阵,使成分尽量的独立。测量成分独立性的最经常使用方法是非高斯性:
上述分布是非高斯分布,这又使得各成分互相独立。让咱们尝试在Python中实现ICA:
from sklearn.decomposition import FastICA
ICA = FastICA(n_components=3, random_state=12)
X=ICA.fit_transform(df[feat_cols].values)
这里,n_components将决定转换数据中的成分数量。咱们使用ICA将数据转换为3个成分。让咱们看看它是如何改变数据的:
plt.figure(figsize=(12,8))
plt.title('ICA Components')
plt.scatter(X[:,0], X[:,1])
plt.scatter(X[:,1], X[:,2])
plt.scatter(X[:,2], X[:,0])
数据已经被分红不一样的独立成分,在上图中能够很是清楚地看到。X轴和Y轴表示分解的独立成分的值。
如今咱们将看到一些使用投影技术来减小数据维度的方法。
首先,咱们须要了解投影是什么。假设咱们有两个向量,矢量a和矢量b,以下所示:
咱们想求a在b上的投影。那么设a和b之间的角度为∅。投影(a1)看起来像:
a1是与b平行的向量。所以,咱们可使用如下等式获得向量a在向量b上的投影:
经过将一个矢量投影到另外一个矢量上,能够下降维度。
在投影技术中,能够经过将其点投影到较低维空间来表示多维数据。如今咱们将讨论不一样的预测方法:
曾几什么时候,人们认为地球是平的。不管你去哪里,它都会保持平坦(让咱们暂时忽视山脉)。可是,若是你继续向一个方向走,那么你最终会走向何方。若是地球是平坦的,那这就不会发生。地球只是看起来比较平坦,那是由于咱们看到的与地球相比是微不足道的。
地球看起来平坦的这些小部分是多方面的,若是咱们将全部这些方面组合在一块儿,咱们就能够得到地球的大尺度视图,也就是原始数据。相似地,对于n维曲线,小的平面快是流形,而且这些流形的组合将给出咱们原始的n维曲线。让咱们看看投影到流形上的步骤:
让咱们经过一个例子来理解流形投影技术。
若是一个流形连续可微缩到任意阶,则称为平滑流形或可微分流形。ISOMAP是一种旨在恢复非线性流形的完整低维表示的算法。它假设流形是平滑的。
它还假设对于流形上的任何一对点,两点之间的测地距离(曲面上两点之间的最短距离)等于欧几里德距离(直线上两点之间的最短距离)。让咱们首先形象化一对点之间的测地线和欧几里德距离:
ISOMAP假设这两个距离相等。如今让咱们看一下这种技术更详细的解释。如前所述,全部这些技术都采用三步法。咱们将详细介绍这些步骤:
让咱们用Python实现它,这样就更清楚的理解我在说什么了。咱们将经过等距映射进行非线性降维。对于可视化,咱们将只采用数据集的一个子集,由于在整个数据集上运行它将须要花费大量时间。
from sklearn import manifold
trans_data = manifold.Isomap(n_neighbors=5, n_components=3, n_jobs=-1).fit_transform(dffeat_cols.values)
使用的参数:
可视化转换后的数据:
plt.figure(figsize=(12,8))
plt.title('Decomposition using ISOMAP')
plt.scatter(trans_data[:,0], trans_data[:,1])
plt.scatter(trans_data[:,1], trans_data[:,2])
plt.scatter(trans_data[:,2], trans_data[:,0])
你能够在上面看到这些成分之间的相关性很是低。实际上,与咱们以前使用SVD得到的成分相比,它们的相关性更小!
到目前为止,咱们已经了解到PCA对于具备大量变量的数据集的降维和可视化是一个很好的选择。可是,若是咱们可使用更高级的东西呢?若是咱们能够轻松地以非线性方式搜索呢?t-SNE就是这样一种技术。咱们可使用两种方法来映射数据点:
xi和xj是数据点,|| xi-xj || 表示这些数据点之间的欧几里德距离,σi是高维空间中数据点的方差
其中:|| yi-yj || 表示yi和yj之间的欧几里德距离
如今咱们将用Python实现它,并将结果可视化:
from sklearn.manifold import TSNE
tsne = TSNE(n_components=3, n_iter=300).fit_transform(dffeat_cols.values)
n_components将决定转换数据中的成分数量。是时候查看可视化转换后的数据:
plt.figure(figsize=(12,8))
plt.title('t-SNE components')
plt.scatter(tsne[:,0], tsne[:,1])
plt.scatter(tsne[:,1], tsne[:,2])
plt.scatter(tsne[:,2], tsne[:,0])
在这里,你能够清楚地看到使用强大的t-SNE技术转换的不一样成分。
t-SNE在大型数据集上工做表现很好,但它也有它的局限性,例如丢失大型的信息,计算时间慢,没法有意义地表示很是大的数据集。统一流形近似和投影(UMAP)是一种降维技术,与t-SNE相比,能够保留尽量多的本地数据结构和全局数据结构,而且运行时间更短。听起来颇有趣,对吧。
UMAP的一些主要优点是:
该方法使用k-近邻的概念,并使用随机梯度降低来优化结果。它首先计算高维空间中的点之间的距离,将它们投影到低维空间,并计算该低维空间中的点之间的距离。而后,它使用随机梯度降低来最小化这些距离之间的差别。
咱们如今将在Python中实现它:
import umap
umap_data = umap.UMAP(n_neighbors=5, min_dist=0.3, n_components=3).fit_transform(dffeat_cols.values)
让咱们可视化一下这个变换:
plt.figure(figsize=(12,8))
plt.title('Decomposition using UMAP')
plt.scatter(umap_data[:,0], umap_data[:,1])
plt.scatter(umap_data[:,1], umap_data[:,2])
plt.scatter(umap_data[:,2], umap_data[:,0])
维度已经减小了,咱们能够想象不一样的变换成分。变换后的变量之间的相关性很是小。让咱们比较UMAP和t-SNE的结果:
咱们能够看到,与从t-SNE得到的成分之间的相关性相比,从UMAP得到的成分之间的相关性很是小。所以,UMAP倾向于提供更好的结果。
正如UMAP的GitHub代码库中所提到的,与t-SNE相比,它在保留数据全局结构方面的表现更好。这意味着它一般能够提供更好的“全局”数据视图以及保留本地邻居关系。
深呼吸。咱们已经学习了至关多的降维技术。让咱们简要总结一下在那里可使用它们。
在本节中,咱们将简要总结咱们所涵盖的每种降维技术的使用案例。了解在什么地方可使用什么样的技术,由于它有助于节省时间,精力和计算能力。
这是一篇关于降维的全面文章,你能够在任何地方用到它!在编写过程当中我得到了不少的乐趣,并找到了一些我以前历来没用使用过的新方法(好比UMAP)。
处理成千上万的特征是任何数据科学家必备的技能。咱们天天生成的数据量是史无前例的,咱们须要找到不一样的方法来肯定如何使用它。降维是一种很是有用的方法,对我来讲,不管是在专业的应用中,仍是在机器学习的比赛中,它都产生了奇妙的效果。
The Ultimate Guide to 12 Dimensionality Reduction Techniques (with Python codes)