机器学习算法原理实现——pca降维

pca降维的通俗理解

PCA降维可以被通俗地理解为一个“信息压缩”的过程。假设你有一个多维的数据集,每个维度都包含一些信息。但是,这些维度之间可能存在一些关联,这就意味着一些信息是被重复的。PCA就是要找出这些重复的信息,并尽可能地去除它们,从而降低数据的维度。

举个例子,假设你在一个水果店里,你有苹果的重量和大小两个维度的数据。这两个维度可能高度相关,因为一般来说,苹果越大,重量也越重。在这种情况下,你其实可以只用一个维度(比如重量)来表示这个苹果,而不需要两个维度。这就是PCA降维的基本思想。

在实际操作中,PCA通过计算数据的协方差矩阵和该矩阵的特征值和特征向量来实现降维。特征值大的特征向量对应的是数据中变化大(信息多)的方向,而特征值小的特征向量对应的是数据中变化小(信息少)的方向。PCA降维就是保留那些特征值大的特征向量,去掉特征值小的特征向量,从而实现降维。(至于为什么,看后面的推导)

 

矩阵特征值和特征向量是如何定义的?

特征值和特征向量是矩阵的重要属性,它们描述了矩阵对向量空间的变换特性。

对于一个n阶方阵A,如果存在一个非零向量v,使得Av=λv,那么我们就称λ是矩阵A的一个特征值,v是对应于特征值λ的一个特征向量。

特征值和特征向量是描述矩阵变换特性的重要工具。我们可以通过一个简单的例子来理解它们。

假设你有一个向量v,你用一个矩阵A对它进行线性变换,得到一个新的向量Av。大部分情况下,Av和v的方向是不同的,也就是说,矩阵A的变换改变了v的方向。但是,有一些特殊的向量,它们在经过矩阵A的变换后,方向并没有改变,只是长度发生了变化,这些向量就是矩阵A的特征向量,变化的长度就是对应的特征值。

举个例子,假设你有一个拉伸机,它可以把物体在某个方向上拉伸或者压缩。你把一个橡皮筋放进去,橡皮筋的方向并没有改变,只是长度变长了,那么你可以说,这个橡皮筋的方向就是拉伸机的一个特征向量,变长的倍数就是对应的特征值。

 


PCA(主成分分析)的理论推导主要基于线性代数和统计学的知识。以下是一个简单的推导过程:

假设我们有一个n维的数据集X,我们希望找到一个k维的子空间(k<n),使得当X投影到这个子空间上时,能够保留最多的信息。这个问题可以转化为最大化投影后的方差(理由见后)。

假设投影矩阵为P,那么投影后的数据为Y=XP,我们希望最大化Y的方差,即最大化Var(Y)。由于Var(Y)=Var(XP)=P^TVar(X)P,其中Var(X)是X的协方差矩阵,因此我们的目标就是最大化P^TVar(X)P。

由于我们希望得到的是一个标准的投影矩阵,即P^TP=I,因此这就变成了一个带约束的优化问题。我们可以使用拉格朗日乘数法来求解这个问题,得到的结果就是:P应该是协方差矩阵Var(X)的前k个最大特征值对应的特征向量。==》详细展开推导如下:
我们的目标是最大化P^TVar(X)P,其中Var(X)是X的协方差矩阵,P是我们要求的投影矩阵,同时满足P^TP=I。这是一个带约束的优化问题。

我们可以构造拉格朗日函数来求解这个问题:

L(P, λ) = P^TVar(X)P - λ(P^TP-I)

其中λ是拉格朗日乘数。我们的目标是找到P和λ使得L(P, λ)取得最大值。这等价于求解以下方程:

∂L/∂P = 2Var(X)P - 2λP = 0
∂L/∂λ = P^TP - I = 0

从第一个方程我们可以得到:

Var(X)P = λP (是不是整个过程非常优雅!)

这就是一个特征值问题,我们需要求解的P就是协方差矩阵Var(X)的特征向量,对应的λ就是特征值。

由于我们希望最大化P^TVar(X)P,因此我们应该选择最大的λ对应的特征向量。如果我们需要降维到k维,那么我们就选择最大的k个λ对应的特征向量。

 

 

上面推导的过程中提到,希望最大化Y的方差,为什么?

在PCA中,我们希望最大化投影后的方差,主要是因为方差代表了数据的分散程度,也就是数据的变化量。在很多情况下,数据的变化量可以被视为数据的信息量。因此,最大化方差就意味着最大化我们保留的信息量。

具体来说,如果我们选择的投影方向使得投影后的方差很小,那么说明在这个方向上,所有的数据点都非常接近,几乎没有什么变化,也就是说这个方向上的信息量很小。反之,如果投影后的方差很大,那么说明在这个方向上,数据点的分布非常分散,存在很大的变化,也就是说这个方向上的信息量很大。

因此,PCA的目标就是找到一个可以最大化投影后方差的投影方向,也就是找到一个可以最大化保留信息量的低维子空间。

 

具体做法:

CA(主成分分析)的步骤主要包括以下几点:

1. 标准化数据:如果数据的各个特征的量纲(单位)不同,那么需要先进行标准化处理,使得各个特征的均值为0,标准差为1。

2. 计算协方差矩阵:协方差矩阵可以反映各个特征之间的相关性。在numpy中,可以使用np.cov()函数来计算协方差矩阵。

3. 计算协方差矩阵的特征值和特征向量:特征值和特征向量反映了数据的主要变化方向。在numpy中,可以使用np.linalg.eig()函数来计算特征值和特征向量。

4. 选择主成分:按照特征值从大到小的顺序,选择前k个最大的特征值对应的特征向量,构成一个新的矩阵。k的选择依赖于具体的需求,如果希望尽可能保留原始数据的信息,那么k应该选择得大一些;如果希望尽可能降低数据的维度,那么k应该选择得小一些。

5. 得到降维后的数据:将原始数据与新的矩阵相乘,得到的就是降维后的数据。

以上就是PCA的基本步骤。在实际使用中,我们通常会使用sklearn库的PCA类来进行主成分分析,这个类已经内置了上述所有步骤,使用起来非常方便。

 

import numpy as np
from sklearn.decomposition import PCA

# 假设我们有以下10x3的数据集
X = np.array([[2.5, 2.4, 3.4], [0.5, 0.7, 1.7], [2.2, 2.9, 3.9], [1.9, 2.2, 3.2], [3.1, 3.0, 4.0], [2.3, 2.7, 3.7], [2, 1.6, 2.6], [1, 1.1, 2.1], [1.5, 1.6, 2.6], [1.1, 0.9, 1.9]])

# 1. 标准化数据
X_normalized = X - np.mean(X, axis=0)

# 2. 计算协方差矩阵
cov_matrix = np.cov(X_normalized, rowvar=False)

# 3. 计算协方差矩阵的特征值和特征向量
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)

# 4. 对特征值进行排序,并保留前k个特征向量
k = 2
idx = eigenvalues.argsort()[::-1]
eigenvectors = eigenvectors[:,idx]
eigenvectors = eigenvectors[:, :k]

# 5. 得到降维后的数据
X_pca = np.dot(X_normalized, eigenvectors)
print(X_pca)
print("original shape:   ", X.shape)
print("transformed shape:", X_pca.shape)

# 创建PCA对象,n_components指定要保留的主成分数量
pca = PCA(n_components=2)

# 对原始数据进行降维
X_pca = pca.fit_transform(X)
print(X_pca)

print("original shape:   ", X.shape)
print("transformed shape:", X_pca.shape)

  

输出结果:

[[ 0.9549377  -0.21069883]
 [-2.1468599   0.18786321]
 [ 1.39083663  0.42175047]
 [ 0.39441466  0.14400375]
 [ 1.99290104 -0.26200274]
 [ 1.2057503   0.18565081]
 [-0.26811199 -0.39549458]
 [-1.40125052  0.06926028]
 [-0.53628106  0.02650702]
 [-1.58633686 -0.16683938]]
original shape:    (10, 3)
transformed shape: (10, 2)
[[-0.9549377  -0.21069883]
 [ 2.1468599   0.18786321]
 [-1.39083663  0.42175047]
 [-0.39441466  0.14400375]
 [-1.99290104 -0.26200274]
 [-1.2057503   0.18565081]
 [ 0.26811199 -0.39549458]
 [ 1.40125052  0.06926028]
 [ 0.53628106  0.02650702]
 [ 1.58633686 -0.16683938]]
original shape:    (10, 3)
transformed shape: (10, 2)

  

可以看到我们的结果和sklearn的结果是一致的 !

 

 

选择前k个最大的特征值对应的特征向量,构成一个新的矩阵。这会不会造成信息丢失?

是的,选择前k个最大的特征值对应的特征向量进行降维,确实会造成一些信息的丢失。这是因为在降维过程中,我们舍弃了一部分特征向量,这些特征向量对应的方向上的信息就被丢失了。

然而,PCA的目标就是要找到一种能够最大程度保留原始数据信息的降维方法。通过选择特征值最大(即数据方差最大)的特征向量,我们能够保留最重要的、包含最多信息的数据特性。

在实际应用中,我们通常会选择一个合适的k值,使得保留的主成分能够解释原始数据的大部分方差。例如,我们可能会选择k使得保留的主成分能够解释原始数据90%的方差。这样,虽然丢失了一部分信息,但是保留了最重要的、包含最多信息的部分,同时大大降低了数据的维度,简化了后续的数据处理和分析过程。


选择k使得保留的主成分能够解释原始数据90%的方差,具体如何做呢?
选择k使得保留的主成分能够解释原始数据90%的方差,可以通过以下步骤实现:
1. 计算所有特征值的总和。
2. 按照特征值从大到小的顺序,逐个累加特征值,直到累加的特征值之和占总和的90%为止。
3. 记录下你需要累加的特征值的个数,这个数就是k。

以下是一个Python代码示例:
 
# 计算所有特征值的总和
total = sum(eigenvalues)
 
# 计算累积方差解释率
var_exp = [(i / total) for i in sorted(eigenvalues, reverse=True)]
cum_var_exp = np.cumsum(var_exp)
 
# 找到第一个满足累积方差解释率大于0.9的特征值,其索引+1就是需要保留的主成分个数
k = np.where(cum_var_exp >= 0.9)[0][0] + 1
 
 
在这段代码中,var_exp是各个主成分的方差解释率,cum_var_exp是各个主成分的累积方差解释率。我们找到第一个使得累积方差解释率大于0.9的主成分,其索引+1就是我们需要保留的主成分个数k。


posted @ 2023-09-22 00:40  bonelee  阅读(120)  评论(0编辑  收藏  举报