理解PCA:what? why? how?
当我们拿到一个数据集的时候,往往数据集中每一个样本的描述是多维的,多维的特征空间不便于我们或者计算机对其进行分析和处理,所以我们希望用低维度的特征向量来表述样本的特征,此时我们需要对其进行降维
假设矩阵 X 在多维空间中有 n 个样本点:
我们希望它们投影到一个方向 u 上,使得投影范围最大,这个方向称为主方向(主成分PCA),可以用方差度量一个随机变量离散程度,即可用方差度量样本点在一个方向上投影之后得离散程度
样本 X(150x4) 投影到 u(4x1) 方向上,即 X•u,得到一个一维的向量 Z(150x1)
对 Z 求方差,而使得方差最大的那个 u 就是主方向,所以我们需要对z = X•u求方差,并且求方差的极值
一、求方差:
对 X 进行中心化:
中心化后的方差为:
线性代数表示方差 [ z12 + z22 + z32 + … + zn2 ] = zT•z,而 z = X•u
二、拉格朗日乘子法求 zT•z 极值(方差最大值)
u 是单位向量,约束条件为:uT•u = 1, 即 uT•u - 1 = 0
由于 (XT•A•X)’ = 2•A•X , 则L(u, λ) 对 u 求偏导得:
XT 是4x150矩阵,X 是150x4的矩阵,点乘得到4x4的协方差矩阵 XT•X,对 XT•X 求得特征值 λ 和特征向量 u
而最大特征值 λ 所对应的 u 就是主方向!
PCA就是样本投影之后方差最大的方向即主方向
次方向就是垂直于主方向的剩下的最大的 λ 所对应的 u …
(特征向量 u 中的所有方向互相垂直)
前k个主方向的选取:
有时候降到一维(只选取一个主方向)并不是最优,所以我们可以选取 k 个主方向
对λ和u排序,计算 (λ1+λ2+λ3+λ4)x85% 得到一个值 w
如果发现前k个λ的和大于 w 就选取对应k个u作为前k个主向量
(85%只是一个可接受的能量比例)
反过来选取k个主方向,算出掌握多大能量和损失多大能量
python实现代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 对矩阵进行中心化
def centralization(mat):
for j in range(mat.shape[1]):
m = np.mean(mat[:, j:j+1])
for i in range(mat.shape[0]):
mat[i][j] -= m
return mat
# 对特征值和对应的特征向量进行排序(选择排序算法)
def v_sort(egv, ftv):
for i in range(egv.__len__()):
for j in range(i+1, egv.__len__()):
if egv[j]>egv[i]:
tmp1 = egv[i]
egv[i] = egv[j]
egv[j] = tmp1
tmp2 = ftv[i]
ftv[i] = ftv[j]
ftv[j] = tmp2
return egv, ftv
# 降维
def PCA(mat, k, ctl=0):
if ctl==1:
# 对样本数据进行中心化
mat = centralization(mat)
# 求协方差矩阵
cov_mat = np.dot(mat.T, mat)
# 求解协方差矩阵的特征值和特征向量
egv, ftv = np.linalg.eig(cov_mat)
# 对特征值排序,同时对相应特征向量改变
egv, ftv = v_sort(egv, ftv)
# 取前 k 个主方向
headv = ftv[:k]
# 把多维特征投影到主方向上
x = np.zeros((k, mat.shape[0]))
for i in range(k):
x[i] = np.dot(mat, headv[i])
return x
if __name__=="__main__":
# 从 Advertising.csv 读取数据
data = pd.read_csv("../../Dataset/Advertising.csv").drop('Unnamed: 0', axis=1)
# 将DataFrame型数据转化成矩阵
mat = data.as_matrix(columns=None)[:, :-1]
# PCA降维
x = PCA(mat, 2, ctl=1)
# 图形显示
x1 = data['TV']
x2 = data['radio']
x3 = data['newspaper']
y = data['sales']
fig = plt.figure('三维特征')
ax = Axes3D(fig)
ax.scatter(x1, x2, x3)
fig = plt.figure('二维特征')
plt.plot(x[0], x[1], 'yo')
plt.title('PCA')
plt.show()
从三维降到二维效果显示: