主成分分析PCA(Principal Component Analysis)簡明教程

簡介

本文的目的是為了能夠讓讀者對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ù)集:
X = [1\ 2\ 4\ 6\ 12\ 15\ 25\ 45\ 68\ 67\ 65\ 98]
我們使用X代表整個數(shù)據(jù)集,使用戶X_i代表數(shù)據(jù)集中的第i個元素啤覆,我相信大家都知道這個樣本數(shù)據(jù)集的平均值如何計算苍日,計算公式如下:
\overline X = \frac {\sum_{i=1}^n X_i}{ n }
平均值\overline X就是把所有的數(shù)字加起來再除以數(shù)字的總數(shù)。但是它除了告訴我們數(shù)據(jù)集的中間值以外窗声,并沒有提供更多的信息相恃,比如下面兩個集合:
[0\ 8\ 12\ 20] \ and \ [8 \ 9\ 11\ 12]
簡單計算可以知道這兩個集合的平均值都是10,但是顯然我們可以看出來它們不太一樣笨觅,比如左邊的集合中的數(shù)字明顯分的比較開拦耐,而右邊集合中的數(shù)字則相對緊湊,即兩個數(shù)據(jù)集合的離散程度不太一樣见剩。
下面引入標(biāo)準差的定義:

標(biāo)準差(Standard Deviation) 杀糯,是離均差平方的算術(shù)平均數(shù)(即:方差)的算術(shù)平方根,用σ表示苍苞。標(biāo)準差也被稱為標(biāo)準偏差固翰,或者實驗標(biāo)準差,在概率統(tǒng)計中最常使用作為統(tǒng)計分布程度上的測量依據(jù)。

由此可知倦挂,標(biāo)準差主要反映一個數(shù)據(jù)集的離散程度。平均數(shù)相同的兩組數(shù)據(jù)担巩,標(biāo)準差未必相同方援。它的計算公式如下:

至于上式的分母為什么是n-1而不是n,這個有點點復(fù)雜涛癌,感興趣的同學(xué)可以參考鏈接犯戏。
總的來說,如果是估算總體方差拳话,根號內(nèi)除以n先匪,如果是估算樣本方差,根號內(nèi)除以n-1弃衍。因為我們計算的是樣本方差呀非,所以除以n-1
接著針對上面提供的兩個樣本集合镜盯,我們可以使用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ù)離集合的平均值距離較遠降允,即離散程度較高。
而對于下面的集合:
[10 \ 10\ 10\ 10]
我們甚至都不用計算就知道它的標(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ù)集(x,y,z),那你可以計算xy疏唾,yz页衙,xz之間的協(xié)方差摊滔。協(xié)方差的計算公式其實與方差的計算公式非常類似,為了對比它們之間的差異店乐,我們換一種形式來描述方差計算公式惭载,如下:

接下來是協(xié)方差公式:

你看出來差別了嗎?它僅僅是把其中一個(X_i - \overline X)換成了(Y_i - \overline Y)响巢,它的含義是描滔,對每一個數(shù)據(jù)項,將X\overline X的差值乘以Y\overline Y的差值踪古,然后全部累加之后除以n-1含长。
但是它是如何工作的呢?假如我們有以下數(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é)果枕扫,最后計算出協(xié)方差值:

你可能會疑惑最后這個計算結(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)然你也許會問cov(X,Y)cov(Y,X)是相等的么弹沽?回頭看一下協(xié)方差的計算公式,你會很快得到答案甚亭,它們是相等的贷币。因為它們之間的唯一區(qū)別在于(X_i - \overline X) (Y_i - \overline Y)(Y_i - \overline Y) (X_i - \overline X)代替了而已击胜,而順序并不重要亏狰。

協(xié)方差矩陣

協(xié)方差總是計算衡量兩個隨機變量之間的聯(lián)合變化程度,那如果我們的數(shù)據(jù)集超過2維了怎么辦偶摔?比如外面有一個3維數(shù)據(jù)集(x,y,z)暇唾,那么我們得對兩兩維度之間進行協(xié)方差計算,即要計算cov(x,y)cov(y,z)cov(x,z)辰斋。實際上策州,對于一個n維的數(shù)據(jù)集,我們需要計算C_n^2 = \frac {n!}{(n-1)!*2}個不同的協(xié)方差值宫仗。
為了表述方便够挂,比較好的方式是利用一個矩陣來保存每兩個隨機變量之間的協(xié)方差,定義如下:
C^{n \times n} = (c_{i,j} , c_{i,j} = cov(Dim_i, Dim_j))
其中C^{n \times n}是一個nn列的矩陣藕夫,Dim_x代表的是第x維孽糖。矩陣中的每一個元素代表了兩個不同維度之間的協(xié)方差值。舉個例子毅贮,對于第2行办悟,第3列來說,其中保存了第二維和第三維之間的協(xié)方差值滩褥。
對于上面距離的3維數(shù)據(jù)集(x,y,z)來說病蛉,它對應(yīng)的協(xié)方差矩陣大小為3x3,具體定義如下:
C = \begin{pmatrix}cov(x,x) & cov(x,y) & cov(x,z) \\cov(y,x) & cov(y,y) & cov(y,z) \\ cov(z,x) & cov(z,y) & cov(z,z) \end{pmatrix}
觀察上述矩陣的主對角線瑰煎,它計算的某一維與它自身的協(xié)方差铺然,故其實就是那一維度的方差,再由于cov(x,y)cov(y,x)相等酒甸,故上述矩陣是一個對稱矩陣探熔。
看起來很復(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)有了基本的認識漏健,尤其是矩陣乘法。
先給一下維基百科上對于特征值和特征向量的定義:

對于一個給定矩陣A橘霎,它的特征向量v經(jīng)過一個線性變化之后蔫浆,得到的新向量與原來的v保持在同一條直線上,但是其長度或者方向也許會改變姐叁,即:
Av = \lambda v
其中\lambda為標(biāo)量瓦盛,即特征向量的長度在該線性變化下縮放的比例,稱\lambda為其特征值外潜。

概念貌似有點枯澀原环,我們用一個例子來演示一下,假設(shè)我們定義一個矩陣A如下:

還有一個向量v = (3, 2)^T(先別問我這個向量哪里來的)处窥,那么A \times v的計算過程如下:

此時我們可以認為v就是A的特征向量嘱吗,\lambda =4是特征向量對應(yīng)的特征值。

這里要注意特征值和特征向量是成對出現(xiàn)的滔驾。

這里的矩陣A其實可以看做是一種線性變換谒麦,它對向量v進行了一種變化,而這種變換作用到v上的結(jié)果相當(dāng)于將v進行了一定比例的伸縮而保持方向不變嵌灰。
特征值和特征向量有什么性質(zhì)呢弄匕?主要包含以下幾個方面:

  • 只有方陣才有特征向量
  • 不同特征值對應(yīng)的特征向量是線性無關(guān)的
  • 同一個特征值可以有多個特征向量,而一個特征向量不能屬于不同的特征值

上述第二條性質(zhì)對后續(xù)的PCA是十分有用的沽瞭,即一個矩陣A的特征向量是兩兩正交的迁匠,這一點很重要的原因是它意味著我們可以根據(jù)這些正交特征向量來重新表達數(shù)據(jù),而不是原始的向量空間驹溃,比如x軸和y軸城丧。
當(dāng)我們找到特征向量之后,通常會對其單位化豌鹤。因為我們知道亡哄,向量是有方向和大小的量,而我們一般更關(guān)注其方向而不是其大小布疙。因此為了標(biāo)準特征向量蚊惯,我們通常對其單位化愿卸,這樣所有的特征向量都有同樣的大小1。下面以特征向量v=[3,2]^T來演示下如何單位化:
首先計算出向量的長度截型,如下:
\sqrt{3^2+2^2} = \sqrt{13}
其次趴荸,我們讓原向量除以這個長度,得到:

但是對于一個方陣A宦焦,我們?nèi)绾握业綄?yīng)的特征值和特征向量呢发钝?如果是比較小的矩陣,比如3x3大小的波闹,我們可以通過一定的方法將其手算出來酝豪。但是對于比較大的矩陣,一般采用復(fù)雜的迭代方法來計算精堕,但是這不在本文的范圍之內(nèi)孵淘,如果你想了解更多關(guān)于特征值和特征向量的內(nèi)容,可以參考B站的線性代數(shù)視頻锄码,非常生動形象夺英,強烈推薦晌涕。
同樣滋捶,我們依舊使用numpy來演示如何計算上述矩陣A的特征值和特征向量:

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ù)(x^{(1)}, x^{(2)},...,x^{(m)}),故我們可以用一個m \times n的矩陣來表達這個原始數(shù)據(jù)集垮衷。如果我們希望將其降低到m \times n'維厅翔,希望這個mn'維的數(shù)據(jù)能夠盡可能的代表原始數(shù)據(jù)集。我們知道從n維降低到n'維肯定是會有損失的搀突,那如何讓損失盡可能的小呢刀闷?
先看下最簡單的情況仰迁,當(dāng)n=2, n' = 1時甸昏,也就是我們希望將數(shù)據(jù)從2維降低到1維翻默。如下圖县恕,我們希望找到一個維度方向美尸,它可以代表這兩個方向,圖中列了兩個向量方向u_1u_2,那么哪一個更優(yōu)呢韭赘?

直觀上來看坦仍,u_1會比較好,為什么呢糊闽?有兩種解釋:

  1. 樣本點到u_1方向的直線的距離足夠近
  2. 樣本點在u_1方向的直線上的投影分的足夠開

因此我們可以得到降維的兩個標(biāo)準為:樣本點到這個超平面的距離足夠近,或者說樣本點在這個超平面上的投影能盡可能的分開梳玫。

基于最大投影方差的PCA推導(dǎo)

下面基于最大投影方差來推導(dǎo)一下PCA,如果覺得有困難右犹,也可以直接跳過提澎,直接看下一節(jié)的PCA算法流程。
假如有mn維數(shù)據(jù)(x^{(1)}, x^{(2)},...,x^{(m)})已經(jīng)進行了中心化傀履,即\sum_{i=1}^m x^{(i)} = 0虱朵。

中心化是為了消除不同評價指標(biāo)之間的量綱影響莉炉,處理方法就是用變量減去它的平均值钓账,具體可參考這里

經(jīng)過投影變換之后得到的新坐標(biāo)系為\{w_1, w_2,...,w_n\}絮宁,其中w是標(biāo)準正交基梆暮,即\| w\|_2 = 1, w_i^Tw_j=0
如果我們把數(shù)據(jù)從n維降到n'維绍昂,即丟棄新數(shù)據(jù)集中的部分坐標(biāo)啦粹,新的坐標(biāo)系為\{w_1, w_2,...,w_{n'}\},樣本點x^{(i)}n'維坐標(biāo)系中的投影為z^{(i)} = (z_1^{(i)} ,z_2^{(i)} ,...,z_{n'}^{(i)} )^T窘游。其中z_j^{(i)} = w_j^Tx^{(i)}x^{(i)}在低維坐標(biāo)系里第j維的坐標(biāo)唠椭。
對于任意的一個樣本x^{(i)},在新的坐標(biāo)系中的投影為w^Tx^{(i)}忍饰,在新的坐標(biāo)系中的投影方差為W^Tx^{(i)} (W^Tx^{(i)})^T = x^{(i)T}WW^Tx^{(i)}贪嫂,要使得所有樣本的投影方差最大,也就是需要最大化\sum_{i=1}^mW^Tx^{(i)} x^{(i)T}W的跡艾蓝,即:
argmax \ tr(W^TXX^TW), \ s.t. W^TW=I
利用拉格朗日函數(shù)可以得到:
J(W) = tr(W^TXX^TW + \lambda (W^TW-I))
W求導(dǎo)得XX^TW + \lambda W = 0力崇,整理下得:
XX^TW = (-\lambda)W
仔細觀察上式你發(fā)現(xiàn)了什么斗塘?也許你啥都沒發(fā)現(xiàn),沒關(guān)系亮靴,我們換一個形式馍盟,約定A = XX^T,那么上式可以寫成:
AW = (-\lambda)W
這不就是特征值和特征向量的定義么茧吊?其中W為矩陣XX^Tn'個特征向量組成的矩陣贞岭,-\lambdaXX^T的若干特征值組成的矩陣,特征值在主對角線上搓侄,其余位置為0曹步。
當(dāng)需要將數(shù)據(jù)集從n維降低到n'維時,我們只需要計算特征值矩陣休讳,并且找到最大的前n'個特征值對應(yīng)的特征向量讲婚。這n'個特征向量組成的矩陣W^{n \times n'}即為我們需要的矩陣。
對于原始數(shù)據(jù)集俊柔,我們只需要用z^{(i)} = W^Tx^{(i)}筹麸,就可以把原始數(shù)據(jù)集從n維降到n'維。

PCA算法流程

根據(jù)上述內(nèi)容可以看出雏婶,求樣本x^{(i)}n'維的主成分其實就是求協(xié)方差矩陣XX^T的前n'個特征值對應(yīng)的特征向量W物赶,然后對于每個樣本x^{(i)},做以下變換z^{(i)} = W^Tx^{(i)}留晚,即達到降維的目的酵紫。
下面是具體的算法流程:

  1. 對所有的樣本進行中心化操作
  2. 計算樣本的協(xié)方差矩陣XX^T
  3. 求出矩陣XX^T的特征值和特征向量
  4. 取出最大的n'個特征值對應(yīng)的特征向量(w_1,w_2,...,w_{n'})然后分別對其單位化,然后組成特征向量矩陣W
  5. 對樣本集中的每一個樣本x^{(i)}错维,通過變換z^{(i)} = W^Tx^{(i)}轉(zhuǎn)換到新的向量空間中奖地。
  6. 得到新的樣本集D' = (z^{(1)}, z^{(2)},...,z^{(m)})

PCA實戰(zhàn)

老規(guī)矩,舉一個例子來說明PCA的過程赋焕,為了方便可視化参歹,我們選擇2維的數(shù)據(jù)來演示。

1.樣本中心化

假如我們有這樣一個數(shù)據(jù)集隆判,它包含了10個數(shù)據(jù)犬庇,每個數(shù)據(jù)有2個特征(x,y),數(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é)果如下:

可能看不太出來中心化到底有什么作用咬腕,現(xiàn)在我將原始數(shù)據(jù)和中心化后的數(shù)據(jù)同時顯示在一張圖上欢峰。用黑色代表原始數(shù)據(jù),紅色代表中心化后的數(shù)據(jù),結(jié)果如下:

可以看到中心化操作并沒有改變整體數(shù)據(jù)的形狀赤赊,而只是讓數(shù)據(jù)整體向坐標(biāo)系原點對齊了闯狱。當(dāng)然中心化還有很多好處,具體請參考我上面給的鏈接抛计。我這里提一點它給計算上帶來的便捷性哄孤。注意到上文提及的方差計算公式:

可以看到分子部分包含(X_i - \overline X) (X_i - \overline X),在我們進行中心化操作之后吹截,\overline X = 0瘦陈,分子不就變成了X_i^2,這明顯使得計算變簡單了波俄。
另外我不知道你有沒有注意到晨逝,上一節(jié)PCA算法流程的第二步:

計算樣本的協(xié)方差矩陣XX^T

為什么XX^T就可以計算出協(xié)方差矩陣了懦铺?看上面公式不是很復(fù)雜么捉貌?其實正是因為我們對數(shù)據(jù)做了中心化之后才可以這么計算的。還記得上面列舉的學(xué)生在數(shù)學(xué)上花的時間與最終考試成績的數(shù)據(jù)集么冬念,我們當(dāng)時使用了numpy去計算協(xié)方差矩陣趁窃,一行代碼就搞定了。現(xiàn)在我先對其去中心化急前,再使用XX^T來計算它的協(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)是單位化之后的特征向量。
eigenvalues = \begin{pmatrix}0.0490834 \\ 1.28402771 \end{pmatrix} \\ \\ eigenvectors = \begin{pmatrix} -0.73517866 & -0.6778734 \\ 0.6778734 & -0.73517866 \end{pmatrix}
也許你會問這代表著什么呢边篮?那我畫出來給你看看好了,?? 看圖:

我畫了兩條直線y_1奏甫,y_2戈轿,分別用綠色和黑色表示,這兩條直線的方程如下:

細心的你估計發(fā)現(xiàn)了阵子,這兩條直線的斜率不就是分別根據(jù)上面兩個特征向量計算得到的么思杯?
注意黑色的直線,你可以看到它直接從數(shù)據(jù)點中間穿了過去,怎么感覺有點線性回歸擬合直線那味兒呢色乾?
總之誊册,從上圖我們可以看出這個特征向量向我們展示了數(shù)據(jù)點與黑色直線的關(guān)系,直覺告訴我們暖璧,如果我們把數(shù)據(jù)點映射到黑色直線指向的方向案怯,那么效果會是比較好的。
y_2對應(yīng)的特征值和特征向量分別是1.28402771( -0.6778734,-0.73517866)^T澎办,可以看到代表這條直線方向的特征向量對應(yīng)的特征值是比較大的那一個嘲碱。
實際上,具有最大特征值的特征向量代表了數(shù)據(jù)集中的主要部分(principal component)局蚀,這也是PCA的來源麦锯,即只選擇最主要的部分。因此我們需要對特征值進行一個排序琅绅,然后忽略掉不怎么重要的成分扶欣,這當(dāng)然會造成信息損失,但是如果被丟棄的特征值比較小千扶,那其實也沒有丟掉太多宵蛀,因為它們表示的也不是最重要的部分。確切地說县貌,如果你的數(shù)據(jù)集有n維术陶,那么你可以計算出n個特征值和特征向量,我們可以選擇最大的前p個作為主要部分煤痕,而丟棄掉剩余的部分,那么最后的數(shù)據(jù)就是p維的梧宫。

3.得到輸出集

因為我們的數(shù)據(jù)集是2維的,我們要降低到1維摆碉,故我們選擇特征值較大的特征向量( -0.6778734,-0.73517866)^T來進行投影塘匣。
這里給大家梳理一下轉(zhuǎn)換流程,令X^{m \times n}代表中心化后的樣本數(shù)據(jù)巷帝,它是m \times n的大小忌卤,在上面的例子中,m=10,n=2楞泼。我們的特征向量矩陣v原本是2 \times 2的大小驰徊,我們只選取了其中具有最大特征值的1個特征向量構(gòu)成投影矩陣W^{2 \times 1},即大小為2 \times 1堕阔,那么最終降維后的數(shù)據(jù)大小為:
X^{10 \times 1} = X^{10 \times 2} W^{2 \times 1}
即降維之后的樣本數(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)點:

  1. 僅僅需要以方差衡量信息量躯喇,不受數(shù)據(jù)集以外的因素影響辫封。
  2. 各主成分之間正交,可消除原始數(shù)據(jù)成分間的相互影響的因素
  3. 計算方法簡單廉丽,主要運算是特征值分解倦微,易于實現(xiàn)。

PCA算法缺點:

  1. 主成分各個特征維度的含義具有一定的模糊性正压,不如原始樣本特征的解釋性強
  2. 方差小的非主成分也可能含有對樣本差異的重要信息欣福,因降維丟棄可能對后續(xù)數(shù)據(jù)處理有影響。

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焦履,一起剝皮案震驚了整個濱河市拓劝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘉裤,老刑警劉巖郑临,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屑宠,居然都是意外死亡厢洞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門典奉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躺翻,“玉大人,你說我怎么就攤上這事秋柄』裰Γ” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵骇笔,是天一觀的道長。 經(jīng)常有香客問我,道長笨触,這世上最難降的妖魔是什么懦傍? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮芦劣,結(jié)果婚禮上粗俱,老公的妹妹穿的比我還像新娘。我一直安慰自己虚吟,他們只是感情好寸认,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著串慰,像睡著了一般偏塞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邦鲫,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天灸叼,我揣著相機與錄音,去河邊找鬼庆捺。 笑死古今,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的滔以。 我是一名探鬼主播捉腥,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼你画!你這毒婦竟也來了抵碟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤撬即,失蹤者是張志新(化名)和其女友劉穎立磁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剥槐,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡唱歧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了粒竖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颅崩。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蕊苗,靈堂內(nèi)的尸體忽然破棺而出沿后,到底是詐尸還是另有隱情,我是刑警寧澤朽砰,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布尖滚,位于F島的核電站喉刘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏漆弄。R本人自食惡果不足惜睦裳,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撼唾。 院中可真熱鬧廉邑,春花似錦、人聲如沸倒谷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渤愁。三九已至牵祟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間猴伶,已是汗流浹背课舍。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留他挎,地道東北人筝尾。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像办桨,于是被迫代替她去往敵國和親筹淫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355