簡介
本文的目的是為了能夠讓讀者對PCA有一個清晰的理解栅盲,并且能夠用代碼自己實現(xiàn)其算法汪诉。
PCA是一種較常用的統(tǒng)計分析、簡化數(shù)據(jù)集的方法,在人臉識別和圖像壓縮等領(lǐng)域都有應(yīng)用扒寄,同時也是在高維數(shù)據(jù)中尋找模式的常用技術(shù)鱼鼓。它利用正交變換來對一系列可能相關(guān)的變量的觀測值進行線性變換,從而投影為一系列線性不相關(guān)變量的值该编,這些不相關(guān)變量稱為主成分(Principal Components)迄本。具體地,主成分可以看做一個線性方程课竣,其包含一系列線性系數(shù)來指示投影方向嘉赎。
基本數(shù)學(xué)概念
在介紹PCA之前,我首先會引入在PCA中會用到的一些基礎(chǔ)數(shù)學(xué)概念于樟,方便那些沒有對應(yīng)基礎(chǔ)知識的初學(xué)者學(xué)習(xí)曹阔,包括:
- 標(biāo)準差
- 方差
- 協(xié)方差
- 特征值和特征向量
這些背景知識對PCA的理解很重要,如果你對這些知識已經(jīng)比較熟悉了隔披,可以選擇直接跳過本節(jié)赃份。
標(biāo)準差
要理解標(biāo)準差,我們首先需要一個數(shù)據(jù)集奢米。以美國大選民意調(diào)查為例抓韩,人口是指全美所有的人,而樣本則是全美所有人口的一個子集鬓长。統(tǒng)計學(xué)的精妙之處在于谒拴,通過只抽樣測量(通過電話調(diào)查或問卷等方式)樣本數(shù)據(jù),而不需要對全體人口都做調(diào)查涉波,就可以計算出比較精確的結(jié)果英上。
下面是一個假設(shè)的樣本數(shù)據(jù)集:
我們使用代表整個數(shù)據(jù)集,使用戶
代表數(shù)據(jù)集中的第
個元素啤覆,我相信大家都知道這個樣本數(shù)據(jù)集的平均值如何計算苍日,計算公式如下:
平均值就是把所有的數(shù)字加起來再除以數(shù)字的總數(shù)。但是它除了告訴我們數(shù)據(jù)集的中間值以外窗声,并沒有提供更多的信息相恃,比如下面兩個集合:
簡單計算可以知道這兩個集合的平均值都是10,但是顯然我們可以看出來它們不太一樣笨觅,比如左邊的集合中的數(shù)字明顯分的比較開拦耐,而右邊集合中的數(shù)字則相對緊湊,即兩個數(shù)據(jù)集合的離散程度不太一樣见剩。
下面引入標(biāo)準差的定義:
由此可知倦挂,標(biāo)準差主要反映一個數(shù)據(jù)集的離散程度。平均數(shù)相同的兩組數(shù)據(jù)担巩,標(biāo)準差未必相同方援。它的計算公式如下:標(biāo)準差(Standard Deviation) 杀糯,是離均差平方的算術(shù)平均數(shù)(即:方差)的算術(shù)平方根,用σ表示苍苞。標(biāo)準差也被稱為標(biāo)準偏差固翰,或者實驗標(biāo)準差,在概率統(tǒng)計中最常使用作為統(tǒng)計分布程度上的測量依據(jù)。
至于上式的分母為什么是而不是
,這個有點點復(fù)雜涛癌,感興趣的同學(xué)可以參考鏈接犯戏。
總的來說,如果是估算總體方差拳话,根號內(nèi)除以先匪,如果是估算樣本方差,根號內(nèi)除以
弃衍。因為我們計算的是樣本方差呀非,所以除以
。
接著針對上面提供的兩個樣本集合镜盯,我們可以使用python里面的numpy庫快速計算岸裙,代碼如下:
import numpy as np
X = [0,8,12,20]
Y = [8,9,11,12]
print("集合X的標(biāo)準差: ", np.std(X, ddof=1))
print("集合Y的標(biāo)磚茶: ", np.std(Y, ddof=1))
結(jié)果如下:
正如意料的那樣,第一個集合的標(biāo)準差會比第二個集合的標(biāo)準差大很多速缆,原因就是因為它的數(shù)據(jù)離集合的平均值距離較遠降允,即離散程度較高。
而對于下面的集合:
我們甚至都不用計算就知道它的標(biāo)準差為0艺糜,因為它的全部數(shù)據(jù)和平均值都是一樣的剧董,即數(shù)據(jù)離散程度為0。
方差
方差是另外一種測量數(shù)據(jù)離散程度的方式破停。實際上翅楼,它就是標(biāo)準差的平方,其公式如下:也許你產(chǎn)生一個疑問真慢,既然有了標(biāo)準差犁嗅,又來個方差干嘛呢?我以前也有這樣的疑問晤碘,但是這不是本文的重點褂微,有興趣的同學(xué)可以參考這里。
協(xié)方差
上面所講的兩種測量公式都是針對一維數(shù)據(jù)的园爷,比如全班同學(xué)的身高宠蚂,每個人的數(shù)學(xué)考試成績等。但是現(xiàn)實中很多數(shù)據(jù)集往往不止一維童社,對于這些高維數(shù)據(jù)的統(tǒng)計分析的目的是希望發(fā)現(xiàn)這些維度之間的關(guān)系求厕。
比如,我們有這樣一個樣本數(shù)據(jù),里面包含了班上每一位同學(xué)的身高呀癣,以及他們的數(shù)學(xué)成績美浦。我們可以通過統(tǒng)計分析來發(fā)現(xiàn)是否一個學(xué)生的身高與它的數(shù)學(xué)成績是否包含某種關(guān)系。
上述只是個示例项栏,實際上這兩者之間可能壓根沒任何關(guān)系浦辨。??
協(xié)方差(Covariance)總是用于衡量兩個隨機變量的聯(lián)合變化程度。而方差是協(xié)方差的一種特殊情況沼沈,即變量與自身的協(xié)方差流酬。即如果你衡量一個變量與其自身的聯(lián)合變化程度峰尝,你得到的結(jié)果就是方差峡眶。
如果你有一個三維數(shù)據(jù)集,那你可以計算
和
疏唾,
和
页衙,
和
之間的協(xié)方差摊滔。協(xié)方差的計算公式其實與方差的計算公式非常類似,為了對比它們之間的差異店乐,我們換一種形式來描述方差計算公式惭载,如下:
你看出來差別了嗎?它僅僅是把其中一個換成了
响巢,它的含義是描滔,對每一個數(shù)據(jù)項,將
與
的差值乘以
與
的差值踪古,然后全部累加之后除以
含长。
但是它是如何工作的呢?假如我們有以下數(shù)據(jù)集伏穆,它記錄了班上每一個同學(xué)在數(shù)學(xué)上花費的時間拘泞,以及他們最終的數(shù)學(xué)成績,如下圖所示:
No. | Hours(H) | Mark(M) |
---|---|---|
0 | 9 | 39 |
1 | 15 | 56 |
2 | 25 | 93 |
3 | 14 | 61 |
4 | 10 | 50 |
5 | 18 | 75 |
6 | 0 | 32 |
7 | 16 | 85 |
8 | 5 | 42 |
9 | 19 | 70 |
10 | 16 | 66 |
11 | 20 | 80 |
你可能會疑惑最后這個計算結(jié)果的含義是什么陪腌?其實最終的具體值并不重要,重要的是它的符號烟瞧。
如果這個值是正的诗鸭,這表明隨著其中一維數(shù)據(jù)的增大,另外一維數(shù)據(jù)也會相應(yīng)增大参滴。
如果這個數(shù)字是負的强岸,表明隨著其中一維數(shù)據(jù)的增加,另外一維數(shù)據(jù)會減少砾赔。
如果這個數(shù)字是0蝌箍,則表明這兩維數(shù)據(jù)之間是相互獨立的青灼,即其中一維數(shù)據(jù)的變化并不會影響另外一維。
觀察我們的計算結(jié)果妓盲,它是正的杂拨,這表明隨著學(xué)習(xí)時間的增加,對應(yīng)的成績也會相應(yīng)提高悯衬。
當(dāng)然你也許會問和
是相等的么弹沽?回頭看一下協(xié)方差的計算公式,你會很快得到答案甚亭,它們是相等的贷币。因為它們之間的唯一區(qū)別在于
被
代替了而已击胜,而順序并不重要亏狰。
協(xié)方差矩陣
協(xié)方差總是計算衡量兩個隨機變量之間的聯(lián)合變化程度,那如果我們的數(shù)據(jù)集超過2維了怎么辦偶摔?比如外面有一個3維數(shù)據(jù)集暇唾,那么我們得對兩兩維度之間進行協(xié)方差計算,即要計算
和
和
辰斋。實際上策州,對于一個n維的數(shù)據(jù)集,我們需要計算
個不同的協(xié)方差值宫仗。
為了表述方便够挂,比較好的方式是利用一個矩陣來保存每兩個隨機變量之間的協(xié)方差,定義如下:
其中是一個
行
列的矩陣藕夫,
代表的是第
維孽糖。矩陣中的每一個元素代表了兩個不同維度之間的協(xié)方差值。舉個例子毅贮,對于第2行办悟,第3列來說,其中保存了第二維和第三維之間的協(xié)方差值滩褥。
對于上面距離的3維數(shù)據(jù)集來說病蛉,它對應(yīng)的協(xié)方差矩陣大小為3x3,具體定義如下:
觀察上述矩陣的主對角線瑰煎,它計算的某一維與它自身的協(xié)方差铺然,故其實就是那一維度的方差,再由于與
相等酒甸,故上述矩陣是一個對稱矩陣探熔。
看起來很復(fù)雜對吧,但是實際使用中我們不需要自己計算烘挫,使用numpy庫可以幫我們快速搞定诀艰。下面是針對上文提及的全班學(xué)生數(shù)學(xué)學(xué)習(xí)時長和成績的數(shù)據(jù)計算得到的協(xié)方差矩陣柬甥,因為數(shù)據(jù)是2維的,即{Hours, Mark}其垄,故最后的協(xié)方差矩陣是2x2的苛蒲。具體代碼和結(jié)果如下:
import numpy as np
x = np.array([9,15,25,14,10,18,0,16,5,19,16,20])
y = np.array([39,56,93,61,50,75,32,85,42,70,66,80])
# 計算協(xié)方差矩陣
covxy = np.cov(x, y)
print(covxy)
結(jié)果:呼~ 人生苦短,我用python绿满。??
線性代數(shù)
這一節(jié)會介紹一些關(guān)于PCA使用到的線性代數(shù)相關(guān)的基礎(chǔ)知識臂外。我會尤其介紹對于一個給定矩陣,如何去找到它的特征值和特征向量喇颁。當(dāng)然這個前提是我假設(shè)你對矩陣已經(jīng)有了基本的認識漏健,尤其是矩陣乘法。
先給一下維基百科上對于特征值和特征向量的定義:
對于一個給定矩陣
橘霎,它的特征向量
經(jīng)過一個線性變化之后蔫浆,得到的新向量與原來的
保持在同一條直線上,但是其長度或者方向也許會改變姐叁,即:
其中為標(biāo)量瓦盛,即特征向量的長度在該線性變化下縮放的比例,稱
為其特征值外潜。
概念貌似有點枯澀原环,我們用一個例子來演示一下,假設(shè)我們定義一個矩陣如下:
還有一個向量(先別問我這個向量哪里來的)处窥,那么
的計算過程如下:
此時我們可以認為就是
的特征向量嘱吗,
是特征向量對應(yīng)的特征值。
這里要注意特征值和特征向量是成對出現(xiàn)的滔驾。
這里的矩陣其實可以看做是一種線性變換谒麦,它對向量
進行了一種變化,而這種變換作用到
上的結(jié)果相當(dāng)于將
進行了一定比例的伸縮而保持方向不變嵌灰。
特征值和特征向量有什么性質(zhì)呢弄匕?主要包含以下幾個方面:
- 只有方陣才有特征向量
- 不同特征值對應(yīng)的特征向量是線性無關(guān)的
- 同一個特征值可以有多個特征向量,而一個特征向量不能屬于不同的特征值
上述第二條性質(zhì)對后續(xù)的PCA是十分有用的沽瞭,即一個矩陣的特征向量是兩兩正交的迁匠,這一點很重要的原因是它意味著我們可以根據(jù)這些正交特征向量來重新表達數(shù)據(jù),而不是原始的向量空間驹溃,比如
軸和
軸城丧。
當(dāng)我們找到特征向量之后,通常會對其單位化豌鹤。因為我們知道亡哄,向量是有方向和大小的量,而我們一般更關(guān)注其方向而不是其大小布疙。因此為了標(biāo)準特征向量蚊惯,我們通常對其單位化愿卸,這樣所有的特征向量都有同樣的大小1。下面以特征向量來演示下如何單位化:
首先計算出向量的長度截型,如下:
其次趴荸,我們讓原向量除以這個長度,得到:
但是對于一個方陣宦焦,我們?nèi)绾握业綄?yīng)的特征值和特征向量呢发钝?如果是比較小的矩陣,比如3x3大小的波闹,我們可以通過一定的方法將其手算出來酝豪。但是對于比較大的矩陣,一般采用復(fù)雜的迭代方法來計算精堕,但是這不在本文的范圍之內(nèi)孵淘,如果你想了解更多關(guān)于特征值和特征向量的內(nèi)容,可以參考B站的線性代數(shù)視頻锄码,非常生動形象夺英,強烈推薦晌涕。
同樣滋捶,我們依舊使用numpy來演示如何計算上述矩陣的特征值和特征向量:
import numpy as np
A = np.matrix([[2,3],
[2,1]])
eigvalue, eigvector = np.linalg.eig(A)
print("特征值: ", eigvalue)
print("特征向量: ", eigvector)
結(jié)果如下:PCA
呼~終于來到正題了。
PCA思路
PCA顧名思義余黎,就是要找出數(shù)據(jù)的主成分重窟,用數(shù)據(jù)的最主要的方面來代替原始數(shù)據(jù)。具體的惧财,假如我們的數(shù)據(jù)集是n維的巡扇,共有m個數(shù)據(jù),故我們可以用一個
的矩陣來表達這個原始數(shù)據(jù)集垮衷。如果我們希望將其降低到
維厅翔,希望這個
個
維的數(shù)據(jù)能夠盡可能的代表原始數(shù)據(jù)集。我們知道從
維降低到
維肯定是會有損失的搀突,那如何讓損失盡可能的小呢刀闷?
先看下最簡單的情況仰迁,當(dāng)時甸昏,也就是我們希望將數(shù)據(jù)從2維降低到1維翻默。如下圖县恕,我們希望找到一個維度方向美尸,它可以代表這兩個方向,圖中列了兩個向量方向
和
,那么哪一個更優(yōu)呢韭赘?
直觀上來看坦仍,會比較好,為什么呢糊闽?有兩種解釋:
- 樣本點到
方向的直線的距離足夠近
- 樣本點在
方向的直線上的投影分的足夠開
因此我們可以得到降維的兩個標(biāo)準為:樣本點到這個超平面的距離足夠近,或者說樣本點在這個超平面上的投影能盡可能的分開梳玫。
基于最大投影方差的PCA推導(dǎo)
下面基于最大投影方差來推導(dǎo)一下PCA,如果覺得有困難右犹,也可以直接跳過提澎,直接看下一節(jié)的PCA算法流程。
假如有個
維數(shù)據(jù)
已經(jīng)進行了中心化傀履,即
虱朵。
中心化是為了消除不同評價指標(biāo)之間的量綱影響莉炉,處理方法就是用變量減去它的平均值钓账,具體可參考這里。
經(jīng)過投影變換之后得到的新坐標(biāo)系為絮宁,其中
是標(biāo)準正交基梆暮,即
。
如果我們把數(shù)據(jù)從維降到
維绍昂,即丟棄新數(shù)據(jù)集中的部分坐標(biāo)啦粹,新的坐標(biāo)系為
,樣本點
在
維坐標(biāo)系中的投影為
窘游。其中
是
在低維坐標(biāo)系里第
維的坐標(biāo)唠椭。
對于任意的一個樣本,在新的坐標(biāo)系中的投影為
忍饰,在新的坐標(biāo)系中的投影方差為
贪嫂,要使得所有樣本的投影方差最大,也就是需要最大化
的跡艾蓝,即:
利用拉格朗日函數(shù)可以得到:
對求導(dǎo)得
力崇,整理下得:
仔細觀察上式你發(fā)現(xiàn)了什么斗塘?也許你啥都沒發(fā)現(xiàn),沒關(guān)系亮靴,我們換一個形式馍盟,約定,那么上式可以寫成:
這不就是特征值和特征向量的定義么茧吊?其中為矩陣
的
個特征向量組成的矩陣贞岭,
為
的若干特征值組成的矩陣,特征值在主對角線上搓侄,其余位置為0曹步。
當(dāng)需要將數(shù)據(jù)集從維降低到
維時,我們只需要計算特征值矩陣休讳,并且找到最大的前
個特征值對應(yīng)的特征向量讲婚。這
個特征向量組成的矩陣
即為我們需要的矩陣。
對于原始數(shù)據(jù)集俊柔,我們只需要用筹麸,就可以把原始數(shù)據(jù)集從
維降到
維。
PCA算法流程
根據(jù)上述內(nèi)容可以看出雏婶,求樣本的
維的主成分其實就是求協(xié)方差矩陣
的前
個特征值對應(yīng)的特征向量
物赶,然后對于每個樣本
,做以下變換
留晚,即達到降維的目的酵紫。
下面是具體的算法流程:
- 對所有的樣本進行中心化操作
- 計算樣本的協(xié)方差矩陣
- 求出矩陣
的特征值和特征向量
- 取出最大的
個特征值對應(yīng)的特征向量
然后分別對其單位化,然后組成特征向量矩陣
- 對樣本集中的每一個樣本
错维,通過變換
轉(zhuǎn)換到新的向量空間中奖地。
- 得到新的樣本集
PCA實戰(zhàn)
老規(guī)矩,舉一個例子來說明PCA的過程赋焕,為了方便可視化参歹,我們選擇2維的數(shù)據(jù)來演示。
1.樣本中心化
假如我們有這樣一個數(shù)據(jù)集隆判,它包含了10個數(shù)據(jù)犬庇,每個數(shù)據(jù)有2個特征,數(shù)據(jù)如下:
x | y |
---|---|
2.5 | 2.4 |
0.5 | 0.7 |
2.2 | 2.9 |
1.9 | 2.2 |
3.1 | 3.0 |
2.3 | 2.7 |
2 | 1.6 |
1 | 1.1 |
1.5 | 1.6 |
1.1 | 0.9 |
這么看不太明顯侨嘀,我們借助python的matplotlib將其繪制出來如下臭挽,代碼如下:
import matplotlib.pyplot as plt
x = [2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2.0, 1.0, 1.5, 1.1]
y = [2.4, 0.7, 2.9, 2.2, 3.0, 2.7, 1.6, 1.1, 1.6, 0.9]
plt.figure('Draw')
plt.scatter(x,y)#繪制散點圖
plt.xlabel('x')
plt.ylabel('y')
plt.xlim(-3,3)
plt.ylim(-3,3)
plt.grid(True, linestyle='-.')
plt.plot(x, y, 'ro')
plt.show()
結(jié)果:接下來我們進行樣本中心化:
import numpy as np
x = [2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2.0, 1.0, 1.5, 1.1]
y = [2.4, 0.7, 2.9, 2.2, 3.0, 2.7, 1.6, 1.1, 1.6, 0.9]
XXT = np.zeros([10,2]) #創(chuàng)建一個10x2的零矩陣
XXT[:,0] = x
XXT[:,1] = y
#計算每一列的均值
meanVals = np.mean(XXT, axis=0)
#中心化
XXT = XXT - meanVals
print(XXT)
結(jié)果如下:
x | y |
---|---|
0.69 | 0.49 |
-1.31 | -1.21 |
0.39 | 0.99 |
0.09 | 0.29 |
1.29 | 1.09 |
0.49 | 0.79 |
0.19 | -0.31 |
-0.81 | -0.81 |
-0.31 | -0.31 |
-0.71 | -1.01 |
同樣,我們將其繪制出來:
plt.figure('Draw')
plt.scatter(XXT[:,0],XXT[:,1])#繪制散點圖
plt.xlim(-3,3)
plt.ylim(-3,3)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True, linestyle='-.')
plt.plot(XXT[:,0],XXT[:,1], 'ro', color='red')
結(jié)果如下:可以看到分子部分包含,在我們進行中心化操作之后吹截,
瘦陈,分子不就變成了
,這明顯使得計算變簡單了波俄。
另外我不知道你有沒有注意到晨逝,上一節(jié)PCA算法流程的第二步:
計算樣本的協(xié)方差矩陣
,
為什么就可以計算出協(xié)方差矩陣了懦铺?看上面公式不是很復(fù)雜么捉貌?其實正是因為我們對數(shù)據(jù)做了中心化之后才可以這么計算的。還記得上面列舉的學(xué)生在數(shù)學(xué)上花的時間與最終考試成績的數(shù)據(jù)集么冬念,我們當(dāng)時使用了numpy去計算協(xié)方差矩陣趁窃,一行代碼就搞定了。現(xiàn)在我先對其去中心化急前,再使用
來計算它的協(xié)方差矩陣醒陆,你看看兩種方式的計算結(jié)果一不一樣,代碼如下:
import numpy as np
x = np.array([9,15,25,14,10,18,0,16,5,19,16,20])
y = np.array([39,56,93,61,50,75,32,85,42,70,66,80])
# 計算協(xié)方差矩陣
covxy = np.cov(x, y)
print(covxy)
X = np.zeros([12,2]) #創(chuàng)建一個12x2的零矩陣
X[:,0] = x
X[:,1] = y
meanVals = np.mean(X, axis=0)
X = X - meanVals #中心化
XT = X.T #得到矩陣的轉(zhuǎn)置
# 計算協(xié)方差矩陣
XTX = np.matrix(XT)*np.matrix(X)/(len(x)-1)
print(XTX)
結(jié)果: 很明顯裆针,結(jié)果是一樣的刨摩,那么說明中心化確實可以給計算帶來很大的方便。
那肯定一樣啊世吨,結(jié)果不一樣澡刹,我也不敢放上來呀。??
2.計算協(xié)方差矩陣的特征值和特征向量
直接在原始矩陣XXT上計算協(xié)方差計算另假,使用以下代碼:
covMat = np.cov(XXT, rowvar=0)
eigVals, eigVects = np.linalg.eig(np.mat(covMat))
print("特征值: ", eigVals)
print("特征向量: ", eigVects)
結(jié)果如下:
可以看到我們得到了兩個特征值和對應(yīng)的特征向量像屋,注意這里得到的特征向量已經(jīng)是單位化之后的特征向量。
也許你會問這代表著什么呢边篮?那我畫出來給你看看好了,?? 看圖:
我畫了兩條直線奏甫,
戈轿,分別用綠色和黑色表示,這兩條直線的方程如下:
細心的你估計發(fā)現(xiàn)了阵子,這兩條直線的斜率不就是分別根據(jù)上面兩個特征向量計算得到的么思杯?
注意黑色的直線,你可以看到它直接從數(shù)據(jù)點中間穿了過去,怎么感覺有點線性回歸擬合直線那味兒呢色乾?
總之誊册,從上圖我們可以看出這個特征向量向我們展示了數(shù)據(jù)點與黑色直線的關(guān)系,直覺告訴我們暖璧,如果我們把數(shù)據(jù)點映射到黑色直線指向的方向案怯,那么效果會是比較好的。
對應(yīng)的特征值和特征向量分別是
和
澎办,可以看到代表這條直線方向的特征向量對應(yīng)的特征值是比較大的那一個嘲碱。
實際上,具有最大特征值的特征向量代表了數(shù)據(jù)集中的主要部分(principal component)局蚀,這也是PCA的來源麦锯,即只選擇最主要的部分。因此我們需要對特征值進行一個排序琅绅,然后忽略掉不怎么重要的成分扶欣,這當(dāng)然會造成信息損失,但是如果被丟棄的特征值比較小千扶,那其實也沒有丟掉太多宵蛀,因為它們表示的也不是最重要的部分。確切地說县貌,如果你的數(shù)據(jù)集有維术陶,那么你可以計算出
個特征值和特征向量,我們可以選擇最大的前
個作為主要部分煤痕,而丟棄掉剩余的部分,那么最后的數(shù)據(jù)就是
維的梧宫。
3.得到輸出集
因為我們的數(shù)據(jù)集是2維的,我們要降低到1維摆碉,故我們選擇特征值較大的特征向量來進行投影塘匣。
這里給大家梳理一下轉(zhuǎn)換流程,令代表中心化后的樣本數(shù)據(jù)巷帝,它是
的大小忌卤,在上面的例子中,
楞泼。我們的特征向量矩陣
原本是
的大小驰徊,我們只選取了其中具有最大特征值的1個特征向量構(gòu)成投影矩陣
,即大小為
堕阔,那么最終降維后的數(shù)據(jù)大小為:
即降維之后的樣本數(shù)據(jù)大小為10x1棍厂。
代碼如下:
covMat = np.cov(XXT, rowvar=0)
eigVals, eigVects = np.linalg.eig(np.mat(covMat))
print("特征值: ", eigVals)
print("特征向量: ", eigVects)
print(eigVects[:,1]) # 這是具有最大特征值的特征向量
print(XXT.shape)
print(eigVects[:,1].shape)
print(XXT * eigVects[:,1])
結(jié)果如下:故我們成功地實現(xiàn)了PCA降維。??????
4. 利用Sklean實現(xiàn)PCA降維
肯定有人會說這個過程太麻煩了超陆,我還是喜歡調(diào)包牺弹,這不,包來了。我們可以用python的機器學(xué)習(xí)庫Sklearn來處理PCA张漂,僅需短短幾行代碼晶默,我把上面的例子也基于Sklearn實現(xiàn)了一下,代碼如下:
from sklearn.decomposition import PCA
x = [2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2.0, 1.0, 1.5, 1.1]
y = [2.4, 0.7, 2.9, 2.2, 3.0, 2.7, 1.6, 1.1, 1.6, 0.9]
X = np.zeros([10,2]) #創(chuàng)建一個10x2的零矩陣
X[:,0] = x
X[:,1] = y
pca = PCA(n_components=1)
pca.fit(X)
X_new = pca.transform(X)
print(X_new)
結(jié)果:可以看到Sklean輸出的結(jié)果跟我們上面自己寫的是一模一樣的哦航攒,相信你看了上面的教程也知道如何自己實現(xiàn)一個PCA算法了磺陡,我就不在這里貼出完整代碼了,感興趣的同學(xué)可以按照我上面的代碼自己試試屎债。
總結(jié)
PCA作為一個非監(jiān)督學(xué)習(xí)的降維方法仅政,它只需要特征值分解,就可以對數(shù)據(jù)進行壓縮盆驹,去噪圆丹。因此在實際場景應(yīng)用很廣泛。
PCA算法優(yōu)點:
- 僅僅需要以方差衡量信息量躯喇,不受數(shù)據(jù)集以外的因素影響辫封。
- 各主成分之間正交,可消除原始數(shù)據(jù)成分間的相互影響的因素
- 計算方法簡單廉丽,主要運算是特征值分解倦微,易于實現(xiàn)。
PCA算法缺點:
- 主成分各個特征維度的含義具有一定的模糊性正压,不如原始樣本特征的解釋性強
- 方差小的非主成分也可能含有對樣本差異的重要信息欣福,因降維丟棄可能對后續(xù)數(shù)據(jù)處理有影響。
參考
- https://baike.baidu.com/item/%E6%A0%87%E5%87%86%E5%B7%AE
- https://www.zhihu.com/question/20099757
- https://zh.wikipedia.org/wiki/%E5%8D%8F%E6%96%B9%E5%B7%AE
- https://zh.wikipedia.org/wiki/%E7%89%B9%E5%BE%81%E5%80%BC%E5%92%8C%E7%89%B9%E5%BE%81%E5%90%91%E9%87%8F
- https://zh.wikipedia.org/wiki/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90
- http://www.cs.otago.ac.nz/cosc453/student_tutorials/principal_components.pdf
- https://www.cnblogs.com/pinard/p/6239403.html
- 《機器學(xué)習(xí)實戰(zhàn)》-- Peter Harrington