数据是机器学习模型的燃料。也许你有很多ML技术可以选择并应用于特定问题,但如果你没有很多好的数据,你就无法做的深入。数据通常是机器学习应用程序中改善性能的最大驱动因素。
有时,数据可能很复杂。你有这么多的数据想要理解这一切意味着什么以及数据的哪些部分真正重要很有挑战性。维度降低是一种技术,它可以帮助我们更好地了解我们的数据。它减少了我们数据集的特征数量,使我们只留下最重要的部分。
主成分分析(PCA)是一种简单而强大的降维技术。通过它,我们可以直接减少特征变量的数量,进而缩小重要特征并节省计算量。从高层次来看,PCA有三个主要步骤:
(1)计算数据的协方差矩阵
(2)计算该协方差矩阵的特征值和向量
(3)使用特征值和向量选择最重要的特征向量,然后将数据转换为这些向量以降低维数!
PCA产生一个特征子空间,使特征向量的方差最大化。因此,为了正确测量这些特征向量的方差,必须对它们进行适当的平衡。为实现此目的,我们首先将数据标准化为零均值和单位方差,以便在我们的计算中对每个特性进行平均加权。假设我们的数据集名为X:
from sklearn.preprocessing import StandardScaler
X = StandardScaler().fit_transform(X)
import numpy as np
# Compute the mean of the data
mean_vec = np.mean(X, axis=0)
# Compute the covariance matrix
cov_mat = (X - mean_vec).T.dot((X - mean_vec)) / (X.shape[0]-1)
# OR we can do this with one line of numpy:
cov_mat = np.cov(X.T)
我们协方差矩阵的特征向量(主成分)表示新特征空间的向量方向,而特征值表示这些向量的大小。由于我们正在研究协方差矩阵,因此可以认为特征值量化了每个向量所贡献出的方差。
如果特征向量具有相应的高量级的特征值,则意味着我们的数据在特征空间中沿着该向量具有高方差。因此,该向量包含有关我们数据的大量信息,因为沿着该向量的任何移动都会导致大的方差。另一方面,具有小特征值的矢量具有低方差,也就是说当沿着该矢量移动时,我们的数据不会有很大变化。因为沿着特定特征向量移动时没有多大变化,即改变该特征向量的值不会对我们的数据产生很大影响,那么我们可以说这个特征不是很重要,我们可以删除它而不会承担多大的损失。
这是PCA中特征值和向量的全部本质。找到在表示数据时最重要的向量,并丢弃其余的向量。在numpy中,计算协方差矩阵的特征向量和特征值是非常简单的。计算之后,我们将根据它们的特征值按降序对特征向量进行排序。
# Compute the eigen values and vectors using numpy
eig_vals, eig_vecs = np.linalg.eig(cov_mat)
# Make a list of (eigenvalue, eigenvector) tuples
eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:,i]) for i in range(len(eig_vals))]
# Sort the (eigenvalue, eigenvector) tuples from high to low
eig_pairs.sort(key=lambda x: x[0], reverse=True)
此时,我们有一个根据特征值对数据集的“重要性”排序的特征向量列表。现在我们要做的是选择我们需要的最重要的特征向量,然后舍弃剩下的向量。我们可以通过查看向量解释方差(explained variance)的百分比以做到这一点。这个百分比量化了在全部100%的主成分中,每个主成分所包含的信息(方差)。
我们举一个例子来说明。假设我们有一个数据集最初有10个特征向量。在计算协方差矩阵之后,我们发现特征值是:
[12,10,8,7,5,1,0.1,0.03,0.005,0.0009]
该数组的总和= 43.1359。但前6个 值代表:
42 / 43.1359 =总数的99.68%!这意味着我们的前6个特征向量有效地保有了关于数据集的99.68%的方差或者说信息。因此,我们可以舍弃最后4个特征向量,因为它们只包含0.32%的信息,为了节省40%的计算,值得牺牲它们!
因此,我们可以简单地定义一个阈值,我们可以用这个阈值决定每个特征向量是保留还是丢弃。在下面的代码中,我们简单地根据选择的97%的阈值来计算希望保留的特征向量的数量。
# Only keep a certain number of eigen vectors based on
# the "explained variance percentage" which tells us how
# much information (variance) can be attributed to each
# of the principal components
exp_var_percentage = 0.97 # Threshold of 97% explained variance
tot = sum(eig_vals)
var_exp = [(i / tot)*100 for i in sorted(eig_vals, reverse=True)]
cum_var_exp = np.cumsum(var_exp)
num_vec_to_keep = 0
for index, percentage in enumerate(cum_var_exp):
if percentage > exp_var_percentage:
num_vec_to_keep = index + 1
break
# Compute the projection matrix based on the top eigen vectors
num_features = X.shape[1]
proj_mat = eig_pairs[0][1].reshape(num_features,1)
for eig_vec_idx in range(1, num_vec_to_keep):
proj_mat = np.hstack((proj_mat, eig_pairs[eig_vec_idx][1].reshape(num_features,1)))
# Project the data
pca_data = X.dot(proj_mat)