PCA降維原理

PCA 簡介

主成分分析(PCA)是最流行的降維算法,通過把數據從高維映射到低維來降低特徵維度,同時保留儘可能多的信息。

在進行圖像識別以及高維度數據降維處理中有很強的應用性,算法主要通過計算,選擇特徵值較大的特徵向量來對原始數據進行基變換,不僅可以去除無用的噪聲,還能減少計算量;廣泛應用於降維、有損數據壓縮、特徵提取、數據可視化等領域。

三個數學概念

方差:衡量變量的離散程度。
方差
協方差:衡量兩個變量的相關度,協方差爲正時說明 X 和 Y 是正相關關係,協方差爲負時 X 和 Y 是負相關關係,協方差爲 0 時 X 和 Y 相互獨立。
協方差
由於只能使用樣本均值代替總體均值,所以分母除以 m-1,纔是總體方差/協方差的無偏估計。其實,數據集樣本量大的話,除以 m-1 和除以 m 區別不大。
協方差矩陣:協方差矩陣是包含與多個變量相關的方差和協方差的方陣。矩陣的對角元素爲變量的方差,而非對角元素爲所有變量對之間的協方差。
協方差矩陣

PCA 降維原理

以二維降一維爲例:
降維原理
PCA 降維的本質是,儘量保證數據在空間中的相對位置不變,通過旋轉座標系,換一個在某些維度能表達更多數據信息的座標系去刻畫數據。如上圖所示,在新的座標系下,主元2對應的維度,對刻畫數據不起任何作用,可以直接把這個維度去掉,達到降維的目的。
有損降維
降維後,如果數據的相對位置完全不變,就是無損降維;如果數據的相對位置稍稍改變,就是有損降維。

降維的數學描述

座標系變換的數學語言描述是基變換,座標系對應的基爲一組兩兩正交的單位向量。
以二維數據爲例,下面是一個座標系變換(基變換)的例子:
基變換
旋轉座標系到什麼時候爲止呢?
用數學語言表述:將一組 N 維向量降爲 K 維,PCA 的做法是選擇 K 個單位正交基,使得原始數據變換到這組基上後,變量之間的協方差都爲 0,變量自身的方差儘可能大。

爲什麼要變量的方差儘可能的大?
方差越大,說明數據越分散,包含的信息量越多;方差越小,說明數據越緊密,越難區分。甚至方差小到一定程度,數據會重疊消失。

爲什麼要變量間的協方差都爲 0?
協方差表示兩個變量的相關性,相關性意味着兩個變量不完全獨立,必然存在重複表示的信息。而協方差爲 0,表示兩變量相互獨立,表示的信息最大。

去均值化:讓每個變量都減去自己的均值。
簡化書寫
去均值化的目的是簡化協方差的表達,最終目的是簡化協方差矩陣的表達。

假設我們只有 a 和 b 兩個變量,將它們按行組成矩陣 X:
原始數據矩陣
則:
協方差矩陣的計算
可知,1m1XXT\frac{1}{m-1}XX^T 就是矩陣 X 的協方差矩陣。

設 X 是原始數據,Y 是對 X 做基變換後的數據:
XY關係
Y 的協方差矩陣爲:
Y的協方差矩陣
上式表達的其實是 Y 的協方差矩陣和 X 的協方差矩陣之間的關係。我們現在的目標就是:尋找一個矩陣 P,使得 D 是一個對角陣。所以 C 對應特徵值最大的前 K 個特徵向量就是我們要找的基。(這中間涉及到一點線性代數的知識,C 是一個對稱陣,要讓 D 對角化,求 C 的特徵值和特徵向量即可,用 C 的特徵向量組成 P,得到的 D 就是對角陣,且對角線上的元素就是 C 的特徵值。)

PCA 降維的流程:流程

SVD(奇異值分解)

SVD
PCA 與 SVD 的奇異向量的壓縮效果相同。至於是與左奇異向量壓縮效果相同,還是與右奇異向量壓縮效果相同,取決於你的原始矩陣是用行表示樣本還是用列表示樣本。如果用列表示樣本,行表示樣本維度,那麼PCA 就與 SVD 的右奇異向量的壓縮效果相同。反之,與左奇異向量的壓縮效果相同。

由於 SVD 有更高效的方法求解,所以實際中經常會使用 SVD 求解 PCA,比如 sklearn 就是這樣做的。

注意 SVD 本身與 PCA 的原理無關!

代碼實操

導入 python sklearn.decomposition 下的 PCA 包。
包內:
fit_transform(X):用 X 來訓練 PCA 模型,同時返回降維後的數據。
inverse_transform(newData):將降維後的數據轉換爲原始維度數據,可能和原始數據有些許差別。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

# 原始數據
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]);

# pca降維
pca = PCA(n_components = 1)
X1 = pca.fit_transform(X)
Y = pca.inverse_transform(X1)
print('原始數據:')
print(X)
print('降維後的數據:')
print(X1)
print('還原的數據:')
print(Y)


# 繪製散點圖,可視化數據
fig = plt.figure()
ax1 = fig.add_subplot(121)
plt.xlabel('X')
plt.ylabel('Y')
ax1.scatter(X[:,0],X[:,1],c='r',marker='o')
# 繪製還原後的數據
ax2 = fig.add_subplot(122)
plt.xlabel('X')
ax2.scatter(Y[:,0],Y[:,1],c='b',marker='x')
plt.show()

運行結果:
運行結果

參考文獻:
https://zhuanlan.zhihu.com/p/77151308
https://www.zhihu.com/question/41120789/answer/481966094

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章