彻底掌握 PCA 降维
PCA 这类的降维算法, 我算是接触好几年了有, 从我学营销的时候, 市场研究方面就经常会用到,相关的还有 "因子分析" 比如, 商品形象认知, 客户细分等场景.
其实多年前我就能够推导了. 当时还从看多元统计的时候, 参数化, 最优化, 引入拉格朗日乘子, 矩阵分解啥的....蛮学术化的, 因为我是学文科的, 理解起来, 真的非常缓慢, 经常去图书馆查资料...而且涉及知识也蛮多.. 差不多大半年我才有所理解哦, 也是真的感慨:
故余虽愚, 卒获有所未闻.
耐心和恒心, 总会获得回报的.
真正理解 PCA 是理解 矩阵的本质是线性变换, 然后工作一段时间后, 才真正对这些概念从认识上, 实践上, 加入认知, 现在倒是随便玩都行.
- 降维;
- 协方差矩阵;
- 特征分解;
前面有一张图, 写的是如何从不那么学术的视角, 从可编程的视角来理解 PCA 的, 当然默认大家是对 矩阵特别熟, 不熟那就没办法了. 就像我小伙伴说, 它想写个软件, 但他说他不会编程.. 那就根本不具备条件, 没办法玩下去了..
PCA 理解
从线性代数的角度, 真的, 很多问题, 会很容易理解, 不要总是试图从微积分来认识.世界是很大的哦.
PCA 实现
从栗子的角度来实现, 我觉得这样算是非常通俗易懂了.
import numpy as np
# 原始数据
X = np.array([
[90, 60, 90],
[90, 90, 30],
[60, 60, 60],
[60, 60, 90],
[30, 30, 30]
])
# 该数据有 3个特征, 我想降维到 2个特征
# 约束是 方差尽可能大(保留更多的原始信息)
1. 随机向量的中心: \(E(X_i - \mu_i)\) i=1...p个特征, 即随机矩阵的每个分量, 的中心, 所组成的向量
# 1. 求随机向量的 X 的中心(向量) (每列的均值)
center = np.average(X, axis=0)
print('随机向量的中心为:', center)
随机向量的中心为: [66. 60. 60.]
2. 对样本矩阵 X 进行中心化 ( 每个值到 各自(列) 中心的距离)
# 2. 对 X 进行中心化
ret = []
for i in range(X.shape[1]):
ret.append(X[:, i] - center[i])
# 垂直拼接
X_center = np.vstack(ret).T
print('中心化后的样本:\n', X_center)
中心化后的样本:
[[ 24. 0. 30.]
[ 24. 30. -30.]
[ -6. 0. 0.]
[ -6. 0. 30.]
[-36. -30. -30.]]
3. 计算随机向量 X 的协方差矩阵: \(\Sigma = \frac{1}{n-1} XX^T\) (X 是已经 中心化 后的)
随机向量 X, 其实就是一个矩阵呀
# 3. 计算协方差
X_cov = X_center.T.dot(X_center) / (X.shape[0] -1)
print("中心化后的样本的协方差矩阵为:\n", X_cov)
中心化后的样本的协方差矩阵为:
[[630. 450. 225.]
[450. 450. 0.]
[225. 0. 900.]]
4. 对协方差矩阵进行 特征分解
# 特征分解
特征值, 特征向量 = np.linalg.eig(X_cov)
print('协方差阵的特征值为:', 特征值)
print("特征值对应-特征向量为:\n", 特征向量)
协方差阵的特征值为: [ 56.02457535 1137.5874413 786.38798335]
特征值对应-特征向量为:
[[ 0.6487899 -0.65580225 -0.3859988 ]
[-0.74104991 -0.4291978 -0.51636642]
[-0.17296443 -0.62105769 0.7644414 ]]
假设特征值是升序排列, 真实不是, 暂时没写, 然后降维
# 5. 坐标旋转, 假设这里是从 3维降到 2 维
# 旋转矩阵
rotate_matrix = 特征向量[:, 1:3]
# 降维
print('从3维降到2维:\n', X.dot(rotate_matrix))
从3维降到2维:
[[-140.6692628 3.07784927]
[-116.28173533 -58.27962721]
[-102.36346447 -8.27542884]
[-120.99519515 14.65781313]
[ -51.18173223 -4.13771442]]
小结: PCA 降维的核心, 其实就是 "坐标轴旋转", 然后这个过程, 可以用 一个 旋转矩阵 来描述. 然后是一通推导, 得出 这个旋转矩阵, 恰好是 协方差矩阵的特征分解后的, 特征向量组成的 矩阵, 构成的. 或者说是, 选择 特征较大 的特征向量方向进行投影, 一样道理.
推导过程, 从矩阵变换, 矩阵分解的本质上, 来推导, 会比通过, 参数化, 然后最优化问题来解, 更直观和可编程. 起码不用思考, 怎么去代码实现 拉格朗日乘子...