理解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()
從三維降到二維效果顯示: