Write a Python function that performs Principal Component Analysis (PCA) from scratch. The function should take a 2D NumPy array as input, where each row represents a data sample and each column represents a feature. The function should standardize the dataset, compute the covariance matrix, find the eigenvalues and eigenvectors, and return the principal components (the eigenvectors corresponding to the largest eigenvalues). The function should also take an integer k as input, representing the number of principal components to return.

Example:

  • Input:data = np.array([[1, 2], [3, 4], [5, 6]]), k = 1
  • Output:[[0.7071], [0.7071]]

这道题要实现主成分分析PCA,其推导在《生物医学信号数据分析与应用》一书中有讲到。

经过推导之后,问题就变成了,计算协方差矩阵作特征值分解。

协方差矩阵

首先计算数据的协方差矩阵(Covariance Matrix),记为矩阵A。

具体计算可参考《10. Calculate Covariance Matrix》。

协方差矩阵反映了数据各特征之间的线性关系。

特征值和特征向量是协方差矩阵的重要属性,满足以下关系:

Av=λv

其中:

  • A 是协方差矩阵,
  • v 是特征向量,
  • λ 是对应的特征值。

特征向量 v 表示数据的主要变化方向,而特征值 λ 表示在该方向上的方差大小。

特征值的计算

特征值是通过求解协方差矩阵的特征方程得到的:

det(A−λI)=0

特征值的计算,可参考《6. 计算一个矩阵的特征值》。

特征向量的计算

有了特征值之后,那么由:

Av=λv

就可以得到:

(A-λI)v = 0

代入进去,就可以求得v了。

特征值在PCA中的作用

在PCA中,特征值的大小直接反映了数据在对应特征向量方向上的方差。具体来说:

  • 较大的特征值:对应的特征向量方向上的方差较大,意味着该方向包含更多的数据信息。
  • 较小的特征值:对应的特征向量方向上的方差较小,意味着该方向包含的信息较少,可能是噪声或冗余信息。

通过选择特征值较大的特征向量,我们可以保留数据的主要结构,同时减少维度。 解这个方程可以得到所有特征值,每个特征值对应一个特征向量。

这道题的求解就只需要这些知识,其中的计算,大多数在之前的题目中都有涉及到,这里直接调用numpy包来计算。

代码如下:

import numpy as np   
def pca(data: np.ndarray, k: int) -> np.ndarray:  
 data2 = (data - np.mean(data, axis=0)) / np.std(data, axis = 0)  
 A = np.cov(data2, rowvar=False)  
 eigenvalues, eigenvectors = np.linalg.eig(A)  
 i = np.argsort(eigenvalues)[::-1]  
 eigenvalues_sorted = eigenvalues[i]  
 eigenvectors_sorted = eigenvectors[:, i]  
  
 principal_components = eigenvectors_sorted[:, :k]  
 return np.round(principal_components, 4)

一个完整的PCA过程包括以下5个步骤:

  1. 标准化数据:将每个特征的均值调整为0,标准差调整为1,以消除量纲的影响。
  2. 计算协方差矩阵:反映特征之间的线性关系。
  3. 求解特征值和特征向量:通过特征方程找到协方差矩阵的特征值和特征向量。
  4. 选择主成分:根据特征值的大小,选择前k个最大的特征值对应的特征向量,作为新的坐标轴(主成分)。
  5. 投影数据:将原始数据投影到选定的主成分上,得到降维后的数据。

在这道题里基本上都涉及到了,包括前面解说没有讲的标准化数据,也在《16. Feature Scaling Implementation》中也有实现过,当然在这道题中,也用了z-score标准化。

我们没有涉及到的是第5步,事实上就是把得到的特征向量组成一个矩阵w,原始数据记为x的话,那么投影干的事情就是wTx,作这样的线性变换。这样整个PCA的过程就完整了。