- 1. 概要
- 2. 规范化
- 3. 协方差矩阵的特征分解方法
- 5. 数据矩阵的奇异值分解方法
- 6. Sklearn API
- 7. 总结
主成分分析是一种无监督算法,主要思想是利用正交变换将线性相关变量表示的观测数据转换为少数几个由线性无关变量表示的数据,线性无关变量称为主成分。
主要方法有:协方差矩阵的特征值分解方法和数据矩阵的奇异值分解方法
PCA的本质:寻找方差最大的坐标轴作为主轴
用途:数据可视化、噪声过滤、特征抽取和特征工程等领域
说明:《统计学习方法》中行为特征维度m,列为样本维度n,这里使用了常规的理解方式(nxm),因此公式与书本不同
2. 规范化输入:n x m 样本矩阵 X X X.
输出:n x m 样本矩阵 X X X(规范化结果)
- 计算m个均值以及方差
- 每个特征维度减去对应均值和方差得到结果
import numpy as np X = np.arange(12).reshape(3, 4) # 样本矩阵 x_mean = X.mean(axis=0) # 一个随机变量一个方差 x_var = np.var(X, axis=0, ddof=1) # 规范化 X = (X - x_mean) / (np.sqrt(x_var)+1e-19)
3. 协方差矩阵的特征分解方法注意:计算方差ddof=1,指的是样本方差需要除以n-1,为什么呢?可以从自由度的角度进行考虑,因为这里计算样本方差时使用了样本均值,所以自由度降低了1,举例:1+2+3 = 6,在知道均值与其中两个样本后,其实已经确定了所有样本,所以自由度降低了1
算法流程:
输入:n x m 样本矩阵 X X X(默认已经规范化)
输出:样本主成分矩阵 Y Y Y(n x m).
- 计算协方差矩阵 S S S(m x m)或者计算样本相关矩阵 R = 1 n − 1 X T X R=frac{1}{n-1}X^{rm{T}}X R=n−11XTX
- 计算协方差矩阵的特征值和单位特征向量eigen, eigen_vector
- 按特征值从大到小排序,选取前k个特征值对应的特征向量作为k个主成分V
- Y = X V Y=XV Y=XV,V(m x k),Y(n x k)
# 1. 计算协方差矩阵 S = np.cov(X, rowvar=False) # 协方差是关于特征维度的,一个特征是一个随机变量 # 2. 计算特征值,单位特征向量 eigenvalue, featurevector = np.linalg.eig(S) # 得到的就是单位特征向量 # a = np.linalg.norm(featurevector, axis=0) # single_featurevector = featurevector / np.linalg.norm(featurevector, axis=0) # 3. 排序,取前k个主成分,也可以计算占比情况 sort_eigenvalue = sorted(eigenvalue, reverse=True) precent = 0.7 * 100 # 70%信息 temp_value = np.percentile(sort_eigenvalue, precent) # 返回的是70%分位的数 temp_index = np.where(eigenvalue >= temp_value) # 选择大于等于70%元素的位置 V = featurevector[:, temp_index].squeeze() # 变换矩阵 # 4. 得到降维矩阵 Y = X.dot(V)
# 1. 计算相关矩阵 R = 1/(X.shape[0]-1) * X.T.dot(X) # X:[n, m]->R:[m, m] # 2. 计算特征值,单位特征向量 eigenvalue, eigenvector = np.linalg.eig(R) # 特征值,单位特征向量 # 3. 排序,取前k个主成分 sort_eigenvalue = sorted(eigenvalue, reverse=True) precent = 0.7 * 100 # 70%信息 temp_value = np.percentile(sort_eigenvalue, 70) temp_index = np.where(eigenvalue >= temp_value) V = featurevector[:, temp_index].squeeze() # 变换矩阵 # 4. 得到降维矩阵 Y = X.dot(V)
5. 数据矩阵的奇异值分解方法协方差矩阵和样本相关矩阵,但是使用样本相关矩阵会更快些,都可以得到结果
算法流程:
输入:n x m 样本矩阵 X X X(默认已经规范化)
输出:样本主成分矩阵 Y Y Y(n x k)
- X ′ = 1 n − 1 X X^prime=frac{1}{sqrt{n-1}}X X′=n−1 1X, X ′ X^prime X′(n x m)
- X ′ = U S V T X^{prime}=USV^{rm{T}} X′=USVT,进行奇异值分解,保留k个奇异值和奇异向量,U(n x n),S(n x m),V(m x m),V的每一列队以一个主成分,选择对应(m x k)作为变换矩阵
- Y = X V Y=XV Y=XV,这里的V已经保留了k个主成分即(m x k),Y(n x k)
# 1. 样本矩阵进行修改 X_ = 1 / np.sqrt(X.shape[0]-1) * X # 2. svd分解 U, S, V = np.linalg.svd(X_) # 3. 排序找百分位置,其实svd分解中S已经排序了,从大到小 temp_value = np.percentile(S, 50) temp_index = np.where(S >= temp_value) V_k = V[:, temp_index].squeeze() # 变换矩阵 # 4. 样本主成分矩阵 Y = X.dot(V_k)6. Sklearn API
temp = PCA(n_components=1) Y = temp.fit_transform(X) # 样本主成分矩阵
7. 总结注意使用sklearn api 默认是没有规范化操作
为什么要使用奇异值分解?
数据特别大,方便计算,进行分解保留重要信息,进行实验过程中发现,特征维度较小时使用特征值分解较好(相关矩阵比协方差矩阵快),当特征维度很大时,奇异值分解更快
参考链接:《统计学习方法》、《机器学习》



