矩阵的特征:主成分分析(PCA)
我們先從主成分分析PCA開始看。在解釋這個方法之前,我們先快速回顧一下什么是特征的降維。在機器學習領域中,我們要進行大量的特征工程,將物品的特征轉換成計算機所能處理的各種數據。通常,如果我們增加物品的特征,就有可能提升機器學習的效果。可是,隨著特征數量不斷增加,特征向量的維數也會不斷升高。這不僅會加大機器學習的難度,還會形成過擬合,影響最終的準確度。針對這種情形,我們需要過濾掉一些不重要的特征,或者是將某些相關的特征合并起來,最終達到在降低特征維數的同時,盡量保留原始數據所包含的信息。了解了這些背景信息,我們再來看PCA方法。本節先從它的運算步驟入手講清楚每一步,再解釋其背后的核心思想。
14.1.1 PCA的主要步驟
和協同過濾的案例一樣,我們使用一個矩陣來表示數據集。我們假設數據集中有
?
個樣本、
維特征,而這些特征都是數值型的,那么這個集合可以按照如表14-1所示的方式來展示。
表14-1 數據記錄及其特征
| 樣本ID | 特征1 | 特征2 | 特征3 | ... | 特征 ? | 特征 ? |
| 1 | 1 | 3 | ?7 | ... | ?10.5 | ?8.2 |
| 2 | 2 | 5 | ?14 | ... | 2.7 | 4 |
| ... | ... | ... | ... | ... | ... | ... |
? | ?3 | ?7 | 2 | ... | 55 | 13.6 |
那么這個樣本集的矩陣形式就是這樣的:
?
這個矩陣是
?
維的,其中每一行表示一個樣本,每一列表示一維特征。我們將這個矩陣稱為樣本矩陣,現在我們的問題是能不能通過某種方法找到一種變換,其可以減少這個矩陣的列數,也就是特征的維數,并且盡可能保留原始數據中的有用信息?針對這個問題,PCA方法提出了一種可行的解決方案。它包括以下4個主要的步驟。
(1)標準化樣本矩陣中的原始數據。
(2)獲取標準化數據的協方差矩陣。
(3)計算協方差矩陣的特征值和特征向量。
(4)依照特征值的大小挑選主要的特征向量,以轉換原始數據并生成新的特征。
1.標準化樣本矩陣中的原始數據
之前我們已經介紹過基于Z分數的特征標準化,這里我們需要進行同樣的處理才能讓每維特征的重要性具有可比性。需要注意的是,這里標準化的數據是針對同一種特征,也是在同一個特征維度之內。不同維度的特征不能放在一起進行標準化。
2.獲取標準化數據的協方差矩陣
首先,我們來看一下什么是協方差(covariance),以及協方差矩陣。協方差用于衡量兩個變量的總體誤差。假設兩個變量分別是
?
和
?
,而它們的采樣數量都是
?
,那么協方差的計算公式就是如下這種形式:
?
其中,
?
表示變量
?
的第
?
個采樣數據,
?
表示這
?
個采樣的均值。當兩個變量是同一個變量時,協方差就變成了方差。
那么,協方差矩陣又是什么呢?我們剛剛提到了樣本矩陣,假設
?
表示樣本矩陣
?
的第1列,
?
表示樣本矩陣
?
的第2列,依次類推。
?
表示第1列向量和自身的協方差,
?
表示第1列向量和第2列向量之間的協方差。結合之前協方差的定義,我們可以得知:
?
其中,
?
表示矩陣中第
?
行、第
?
列的元素。
?
表示第
?
列的均值。有了這些符號表示,我們就可以生成下面這種協方差矩陣:
?
從協方差的定義可以看出,
?
,所以
?
是個對稱矩陣。另外,我們剛剛提到,對
?
而言,如果
?
,那么
?
也就是
?
這組數的方差。所以這個對稱矩陣的主對角線上的值就是各維特征的方差。
3.計算協方差矩陣的特征值和特征向量
這里所說的矩陣的特征向量(eigenvector)和機器學習中的特征向量(feature vector)完全是兩回事。矩陣的特征值和特征向量是線性代數中兩個非常重要的概念。對于一個矩陣
?
,如果能找到向量
?
和標量
?
,使得下面這個式子成立:
?
那么,我們就說
?
是矩陣
?
的特征向量,而
?
是矩陣
?
的特征值。矩陣的特征向量和特征值可能不止一個。說到這里,你可能會好奇,特征向量和特征值表示什么意思呢?我們為什么要關心這兩個概念呢?簡單來說,我們可以將向量
?
左乘一個矩陣
?
看作對
?
進行旋轉或伸縮,如我們之前所介紹的,這種旋轉和伸縮都是由于左乘矩陣
?
后產生的“運動”導致的。特征向量
?
表示矩陣
?
運動的方向,特征值
?
表示運動的幅度,這兩者結合就能描述左乘矩陣X所帶來的效果,因此被看作矩陣的“特征”。PCA中的主成分就是指特征向量,對應的特征值的大小就表示這個特征向量或者說主成分的重要程度。特征值越大,重要程度越高,越要優先使用這個主成分,并利用這個主成分對原始數據進行轉換。
我們先來看看給定一個矩陣,如何計算它的特征值和特征向量,并完成PCA的剩余步驟。計算特征值的推導過程如下:
?
?
?
?
其中,
?
是單位矩陣。對于上面推導中的最后一步,需要計算矩陣的行列式:
?
?
最后,通過解這個方程式,我們就能求得各種
?
的解,而這些解就是特征值。計算完特征值,我們可以將不同的
?
值代入
?
來獲取特征向量。
4.依照特征值的大小挑選主要的特征向量
假設我們獲得了
?
個特征值和對應的特征向量,就會有:
?
?
?
?
按照所對應的
?
數值的大小,對這
?
組的
?
排序。排名靠前的
?
就是最重要的特征向量。假設我們只取
?
個特征中前
?
個最重要的特征,那么我們使用這
?
個特征向量,組成一個
?
維的矩陣
?
。將包含原始數據的
?
維矩陣
?
左乘矩陣
?
,就能重新獲得一個
?
維的矩陣,從而達到降維的目的。
有的時候,我們無法確定
?
取多少合適。一種常見的做法是,看前
?
個特征值的和占所有特征值總和的百分比。假設一共有10個特征值,總和是100,最大的特征值是80,那么第一大特征值占整個特征值總和的80%,我們就認為它能表示80%的信息量,如果還不夠多,我們就繼續看第二大的特征值,它是15,前兩個特征值之和是95,占比達到了95%,如果我們認為足夠了,那么就可以只選前兩大特征值,將原始數據的特征維數從10維降到2維。
所有這些描述可能有一些抽象,讓我們嘗試一個具體的案例。假設我們有一個樣本集合,包含了3個樣本,每個樣本有3維特征
?
、
?
和
?
,對應的矩陣如下:
?
在標準化的時候,需要注意的是,我們的分母都使用
?
而不是
?
,這是為了和之后Python中sklearn庫的默認實現保持一致。首先需要獲取標準化之后的數據。第一維特征的數據是
?
,均值是
?
,方差是
?
。所以,標準化之后第一維特征的數據是
?
,
?
,
?
。以此類推,我們可以獲得第二維和第三維特征標準化之后的數據。當然,全部手工計算的工作量不小,這時可以讓計算機做它擅長的事情:重復性計算。代碼清單14-1展示了如何對樣本矩陣的數據進行標準化。
代碼清單14-1 矩陣標準化
import numpy as np from numpy import linalg as LA from sklearn.preprocessing import scale# 原始數據,包含了3個樣本和3個特征,每一行表示一個樣本,每一列表示一維特征 x = np.mat([[1, 3, -7], [2, 5, -14], [-3, -7, 2]])# 矩陣按列進行標準化 x_std = scale(x, with_mean=True, with_std=True, axis=0) print('標準化后的矩陣:\n', x_std, '\n')其中,scale函數使用了
?
,表示對列進行標準化,因為目前的矩陣排列中,每一列代表一個特征維度,這一點需要注意。如果矩陣排列中每一行代表一個特征維度,那么可以使用
?
對行進行標準化。最終標準化之后的矩陣是這樣的:
?
接下來是協方差的計算。對于第一維向量的方差是
?
。第二維和第二維向量之間的協方差是
?
。以此類推,我們就可以獲得完整的協方差矩陣。同樣,為了減少推算的工作量,使用代碼清單14-2獲得協方差矩陣。
代碼清單14-2 獲取協方差矩陣
# 計算協方差矩陣,注意這里需要先進行轉置,因為這里的函數是看行與行之間的協方差 x_cov = np.cov(x_std.transpose()) # 輸出協方差矩陣 print('協方差矩陣:\n', x_cov, '\n')和sklearn中的標準化函數scale有所不同,numpy中的協方差函數cov除以的是
?
,而不是
?
。最終完整的協方差矩陣如下:
?
然后,我們要求解協方差矩陣的特征值和特征向量:
?
通過對行列式的求解,我們可以得到:
?
最后化簡為:
?
?
所以
?
有3個近似解,分別是0、0.0777和4.4223。對于特征向量的求解,如果手工推算比較煩瑣,我們還是利用Python語言直接求出特征值和對應的特征向量,如代碼清單14-3所示。
代碼清單14-3 獲取協方差矩陣
# 求協方差矩陣的特征值和特征向量 eigVals, eigVects = LA.eig(x_cov) print('協方差矩陣的特征值:', eigVals) print('協方差矩陣的特征向量(主成分):\n', eigVects, '\n')我們可以得到3個特征值及它們對應的特征向量,如表14-2所示。
表14-2 特征值和特征向量
| 特征值 | 特征向量(主成分) |
| 4.42231151e+00 | ? |
| ?3.76638147e?16 | ? |
| 7.76884923e?02 | ? |
注意,Python代碼輸出的特征向量是列向量,而表14-2中列出的是行向量。我們繼續使用下面的這段代碼,找出特征值最大的特征向量,也就是最重要的主成分,然后利用這個主成分,對原始的樣本矩陣進行轉換,如代碼清單14-4所示。
代碼清單14-4 找出主成分并轉換原有矩陣
# 找到最大的特征值,及其對應的特征向量 max_eigVal = -1 max_eigVal_index = -1for i in range(0, eigVals.size):if eigVals[i] > max_eigVal:max_eigVal = eigVals[i]max_eigVal_index = ieigVect_with_max_eigVal = eigVects[:, max_eigVal_index]# 輸出最大的特征值及其對應的特征向量,也就是第一個主成分 print('最大的特征值:', max_eigVal) print('最大特征值所對應的特征向量:', eigVect_with_max_eigVal)# 輸出轉換后的數據矩陣。注意,這里的3個值表示3個樣本,而特征從3維變為1維了 print('轉換后的數據矩陣:', x_std.dot(eigVect_with_max_eigVal), '\n')很明顯,最大的特征值是4.422311507725755,對應的特征向量是是[?0.58077228 ?0.57896098 0.57228292],轉換后的樣本矩陣是:
?
該矩陣從原來的3個特征維度降維成1個特征維度了。Python的sklearn庫也實現了PCA,我們可以通過代碼清單14-5來嘗試一下。
代碼清單14-5 找出主成分并轉換原有矩陣
import numpy as np from sklearn.preprocessing import scale from sklearn.decomposition import PCA# 原始數據,包含了3個樣本和3個特征,每一行表示一個樣本,每一列表示一維特征 x = np.mat([[1, 3, -7], [2, 5, -14], [-3, -7, 2]])# 矩陣按列進行標準化 x_std = scale(x, with_mean=True, with_std=True, axis=0) print('標準化后的矩陣:\n', x_std, '\n')# 挑選前2個主成分 pca = PCA(n_components=2)# 進行PCA分析 pca.fit(x_std)# 輸出轉換后的數據矩陣。注意,這里的3個值表示3個樣本,而特征從3維變為1維了 print('方差(特征值): ', pca.explained_variance_) print('主成分(特征向量)\n', pca.components_) print('轉換后的樣本矩陣:\n', pca.transform(x_std)) print('信息量: ', pca.explained_variance_ratio_)這段代碼中,我們將輸出的主成分設置為2,也就是說挑出前2個最重要的主成分。相應地,轉換后的樣本矩陣有2個特征維度:
?
除了輸出主成分和轉換后的矩陣,sklearn的PCA還提供了信息量的數據,輸出如下:
信息量: [0.98273589 0.01726411]它是各個主成分的方差所占的比例,表示第一個主成分包含原始樣本矩陣中的98.27%的信息,而第二個主成分包含原始樣本矩陣中的1.73%的信息,可想而知,最后一個主成分提供的信息量很少,我們可以忽略不計了。如果我們覺得95%以上的信息量足夠了,就可以只保留第一個主成分,將原始的樣本矩陣的特征維數降到1維。
14.1.2 PCA背后的核心思想
當然,學習的更高境界,不僅要“知其然”,還要做到“知其所以然”。即使現在你對PCA的操作步驟了如指掌,可能也還是有不少疑惑,例如,為什么我們要使用協方差矩陣?這個矩陣的特征值和特征向量又表示什么?為什么選擇特征值最大的主成分,就能涵蓋最多的信息量呢?不用著急,接下來會對此做出更透徹的解釋,讓你不僅明白如何進行PCA,同時還明白為什么要這么做。
1.為什么要使用協方差矩陣
首先要回答的第一個問題是,為什么我們要使用樣本數據中各個維度之間的協方差來構建一個新的協方差矩陣?要弄清楚這一點,首先要回到PCA最終的目標:降維。降維就是要去除那些表達信息量少,或者冗余的維度。我們首先來看如何定義維度的信息量大小。這里我們認為樣本在某個特征維度上的差異越大,那么這個特征包含的信息量就越大,就越重要。反之,信息量就越小,需要被過濾掉。很自然,我們就能想到使用某維特征的方差來定義樣本在這個特征維度上的差異。另外,我們要看如何發現冗余的信息。如果兩種特征有很高的相關性,那么我們可以從一個維度的值推算出另一個維度的值,這兩種特征所表達的信息就是重復的。第二篇“概率統計”介紹過多個變量間的相關性,而在實際應用中,我們可以使用皮爾森(Pearson)相關系數來描述兩個變量之間的線性相關程度。這個系數的取值范圍是[?1.0, 1.0],絕對值越大,說明相關性越強,正數表示正相關,負數表示負相關。圖14-1展示了正相關和負相關的含義。左側的
?
曲線和
?
曲線有非常近似的變化趨勢,當
?
上升的時候,
?
往往也是上升的,
?
下降的時候,
?
往往也下降,這表示兩者有較強的正相關性。右側的
?
和
?
兩者相反,當
?
上升的時候,
?
往往是下降的,
?
下降的時候,
?
往往是上升的,這表示兩者有較強的負相關性。
?
圖14-1 兩個變量的正負相關性
使用同樣的矩陣標記,皮爾森系數的計算公式如下:
?
其中,
?
表示向量維度,
?
和
?
分別為兩個特征維度
?
和
?
在第
?
個采樣上的數值。
?
和
?
分別表示兩個特征維度上所有樣本的均值,
?
和
?
分別表示兩個特征維度上所有樣本的標準差。我們將皮爾森系數的公式稍加變化,來觀察一下皮爾森系數和協方差之間的關系:
?
從上式可以看出,變化后的分子就是協方差。而分母類似于標準化數據中的分母。所以在本質上,皮爾森相關系數和數據標準化后的協方差是一致的。考慮到協方差既可以衡量信息量的大小,又可以衡量不同維度之間的相關性,因此我們就使用各個維度之間的協方差所構成的矩陣,作為PCA的對象。就如前面說講述的,這個協方差矩陣主對角線上的元素是各維度上的方差,也就體現了信息量,而其他元素是兩兩維度間的協方差,也就體現了相關性。既然協方差矩陣提供了我們所需要的方差和相關性,那么下一步,我們就要考慮對這個矩陣進行怎樣的操作了。
2.為什么要計算協方差矩陣的特征值和特征向量
關于這一點,我們可以從兩個角度來理解。
第一個角度是對角矩陣。所謂對角矩陣,就是只有矩陣主對角線之上的元素有非零值,而其他元素的值都為0。我們剛剛解釋了協方差矩陣的主對角線上的元素,都是表示信息量的方差,而其他元素都是表示相關性的協方差。既然我們希望盡可能保留大信息量的維度,而去除相關的維度,那么就意味著我們希望對協方差進行對角化,盡可能地使得矩陣只有主對角線上有非零元素。假如我們確實可以將矩陣盡可能地對角化,那么對于對角化之后的矩陣,它的主對角線上的元素就是或者接近矩陣的特征值,而特征值本身又表示轉換后的方差,也就是信息量。此時,對應的各個特征向量之間基本是正交的,也就是相關性極弱甚至沒有相關性。
第二個角度是特征值和特征向量的幾何意義。之前我們介紹過,在向量空間中,對某個向量左乘一個矩陣,實際上是對這個向量進行了一次變換。在這個變換的過程中,被左乘的向量主要發生旋轉和伸縮這兩種變換。如果左乘矩陣對某一個向量或某些向量只產生伸縮變換,而不對這些向量產生旋轉的效果,那么這些向量就稱為這個矩陣的特征向量,而伸縮的比例就是特征值。換句話說,某個矩陣的特征向量表示這個矩陣在空間中的變換方向,這些方向都是趨于正交的,而特征值表示每個方向上伸縮的比例。如果一個特征值很大,那么說明在對應的特征向量所表示的方向上,伸縮幅度很大。這也是我們需要使用原始數據去左乘這個特征向量來獲取降維后的新數據的原因。因為這樣做可以幫助我們找到一個方向,讓它最大限度地包含原始的信息。需要注意的是,這個新的方向往往不代表原始的特征,而是多個原始特征的組合和縮放。
以來內容摘自《程序員的數學基礎課:從理論到Python實踐》
?
本書緊貼計算機領域,從程序員的需求出發,精心挑選了程序員真正用得上的數學知識,通過生動的案例來解讀知識中的難點,使程序員更容易對實際問題進行數學建模,進而構建出更優化的算法和代碼。
本書共分為三大模塊:“基礎思想”篇梳理編程中常用的數學概念和思想,既由淺入深地精講數據結構與數學中基礎、核心的數學知識,又闡明數學對編程和算法的真正意義;“概率統計”篇以概率統計中核心的貝葉斯公式為基點,向上講解隨機變量、概率分布等基礎概念,向下講解樸素貝葉斯,并分析其在生活和編程中的實際應用,使讀者真正理解概率統計的本質,跨越概念和應用之間的鴻溝;“線性代數”篇從線性代數中的核心概念向量、矩陣、線性方程入手,逐步深入分析這些概念是如何與計算機融會貫通以解決實際問題的。除了理論知識的闡述,本書還通過Python語言,分享了通過大量實踐積累下來的寶貴經驗和編碼,使讀者學有所用。
本書的內容從概念到應用,再到本質,層層深入,不但注重培養讀者養成良好的數學思維,而且努力使讀者的編程技術實現進階,非常適合希望從本質上提升編程質量的中級程序員閱讀和學習。
總結
以上是生活随笔為你收集整理的矩阵的特征:主成分分析(PCA)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++String fing函数
- 下一篇: 手游开发分辨率