一、算法簡(jiǎn)介
主成分分析(Principal Component Analysis,簡(jiǎn)稱(chēng)PCA)算法是降維中最常用的一種手段,降維的算法還有很多,比如奇異值分解(SVD)、因子分析(FA)、獨(dú)立成分分析(ICA)。這里我們主要講解PCA的降維,它的目標(biāo)是通過(guò)某種線性投影,將高維的數(shù)據(jù)映射到低維的空間中,并期望在所投影的維度上數(shù)據(jù)的信息量最大(方差最大),以此使用較少的數(shù)據(jù)維度,同時(shí)保留住較多的原數(shù)據(jù)點(diǎn)的特性。
PCA降維的目的,就是為了盡量保證"信息量不丟失"的情況下,對(duì)原始特征進(jìn)行降維,也就是盡可能將原始特征往具有最大投影信息量的維度上進(jìn)行投影。將原特征投影到這些維度上,使降維后信息量損失最小。
二、原理詳解
1、相關(guān)概念
-
方差:
-
兩個(gè)特征之間的協(xié)方差
-
協(xié)方差(假設(shè)均值為0時(shí)):
-
協(xié)方差矩陣:
-
協(xié)方差對(duì)角化:
補(bǔ)充一下:
(1)方差的計(jì)算公式是針對(duì)一維特征,即針對(duì)同一特征不同樣本的取值來(lái)進(jìn)行計(jì)算得到;而協(xié)方差則必須要求至少滿(mǎn)足二維特征
(2)協(xié)方差為正,說(shuō)明兩個(gè)特征值呈正相關(guān)關(guān)系;協(xié)方差為負(fù),說(shuō)明兩個(gè)特征值呈負(fù)相關(guān)關(guān)系;協(xié)方差為0,說(shuō)明兩個(gè)特征值不相關(guān)。
2、最大方差理論

上圖中,u1就是主成分方向,然后在二維空間中取和u1方向正交的方向,就是u2的方向。則n個(gè)數(shù)據(jù)在u1軸的離散程度最大(方差最大),數(shù)據(jù)在u1上的投影代表了原始數(shù)據(jù)的絕大部分信息,即使不考慮u2,信息損失也不多。而且,u1、u2不相關(guān)。只考慮u1時(shí),二維降為一維。橢圓的長(zhǎng)短軸相差得越大,降維也越有道理。
最大方差理論:在信號(hào)處理中認(rèn)為信號(hào)具有較大的方差,噪聲有較小的方差,信噪比就是信號(hào)與噪聲的方差比,越大越好。如前面的圖,樣本在u1上的投影方差較大,在u2上的投影方差較小,那么可認(rèn)為u2上的投影是由噪聲引起的。
因此我們認(rèn)為,最好的k維特征是將n維樣本點(diǎn)轉(zhuǎn)換為k維后,每一維上的樣本方差都很大。
3、原理分析
PCA的主要思想是將n維特征映射到k維上,這k維是全新的正交特征也被稱(chēng)為主成分,是在原有n維特征的基礎(chǔ)上重新構(gòu)造出來(lái)的k維特征。PCA的工作就是從原始的空間中順序地找一組相互正交的坐標(biāo)軸,新的坐標(biāo)軸的選擇與數(shù)據(jù)本身是密切相關(guān)的。其中,第一個(gè)新坐標(biāo)軸選擇是原始數(shù)據(jù)中方差最大的方向,第二個(gè)新坐標(biāo)軸選取是與第一個(gè)坐標(biāo)軸正交的平面中使得方差最大的,第三個(gè)軸是與第1,2個(gè)軸正交的平面中方差最大的。依次類(lèi)推,可以得到n個(gè)這樣的坐標(biāo)軸。通過(guò)這種方式獲得的新的坐標(biāo)軸,我們發(fā)現(xiàn),大部分方差都包含在前面k個(gè)坐標(biāo)軸中,后面的坐標(biāo)軸所含的方差幾乎為0。于是,我們可以忽略余下的坐標(biāo)軸,只保留前面k個(gè)含有絕大部分方差的坐標(biāo)軸。事實(shí)上,這相當(dāng)于只保留包含絕大部分方差的維度特征,而忽略包含方差幾乎為0的特征維度,實(shí)現(xiàn)對(duì)數(shù)據(jù)特征的降維處理。
4、求解步驟
- 求平均值
- 計(jì)算協(xié)防差矩陣
- 計(jì)算協(xié)方差矩陣的特征值和特征向量
- 將特征值排序
- 保留前K個(gè)最大的特征值對(duì)應(yīng)的特征向量
-
將原始特征轉(zhuǎn)換到上面得到的K個(gè)特征向量構(gòu)建的新空間中(最后兩步,實(shí)現(xiàn)了特征壓縮)
我們通過(guò)一組數(shù)據(jù)的實(shí)例進(jìn)行講解:
1、原始數(shù)據(jù):
2、計(jì)算協(xié)方差矩陣
3、獲取特征值:
4、獲取特征向量:
5、特征向量一定能使協(xié)防差矩陣對(duì)角化:
6、將特征向量進(jìn)行標(biāo)準(zhǔn)化,然后降維
這就得到了我們想要的降維之后的數(shù)據(jù)。
三、案例分析
這里我們使用的數(shù)據(jù)是鳶尾花的數(shù)據(jù)集,網(wǎng)上相關(guān)信息也比較多,有需要的同學(xué)可以私信我。這里我們講兩個(gè)方法,一種是原始求解,一種是使用sklearn包中封裝好的API
1、導(dǎo)入我們需要的包
from sklearn.preprocessing import StandardScaler
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
2、讀取數(shù)據(jù),劃分特征值與目標(biāo)值
def pca():
"""
主成分分析進(jìn)行特征降維
:return:
"""
#讀取數(shù)據(jù)集
data = pd.read_csv('../../數(shù)據(jù)集/機(jī)器學(xué)習(xí)/分類(lèi)算法/鳶尾花數(shù)據(jù)集/iris.csv')
#劃分特征值與目標(biāo)值
x = data.iloc[:,0:4].values
y = data.iloc[:,4].values
print(x,y)
return None
if __name__=="__main__":
pca()


截圖不完整,一共有150行數(shù)據(jù)。
3、數(shù)據(jù)標(biāo)準(zhǔn)化
#數(shù)據(jù)標(biāo)準(zhǔn)化
std = StandardScaler()
x_std = std.fit_transform(x)
print(x_std)

4、主成分分析
- 求每列的平均值
#求每列的平均值
mean_vec = np.mean(x_std,axis=0)
- 求協(xié)方差矩陣(兩個(gè)方法)
# 求協(xié)方差矩陣(直接求)
cov_mat = (x_std-mean_vec).T.dot((x_std-mean_vec)) / (x_std.shape[0] -1)
#使用numpy中自帶的公式求協(xié)方差矩陣np.cov(x_std.T)
cov_mat = np.cov(x_std.T)
print('Covariance matrix \n%s' %cov_mat)

- 計(jì)算協(xié)方差的特征值和特征向量
eig_vals,eig_vecs = np.linalg.eig(cov_mat)
print('Eigenvectors \n%s' %eig_vecs)
print('\nEigenvalues \n%s' %eig_vals)

- 將特征值與特征向量對(duì)應(yīng)起來(lái)并按照特征值排序
eig_pairs = [(np.abs(eig_vals[i]),eig_vecs[:,i]) for i in range(len(eig_vals))]
# print(eig_pairs)
#從高到底按特征值對(duì)eig_pairs排序
eig_pairs.sort(key=lambda x:x[0],reverse=True)
print('Eigvalues in descending order:')
for i in eig_pairs:
print(i[0])

- 通過(guò)累加,確定將特征值降到幾維
#通過(guò)累加,確定將特征值降到幾維
tot = sum(eig_vals)
var_exp = [(i/tot)*100 for i in sorted(eig_vals,reverse=True)]
cum_var_exp = np.cumsum(var_exp)
print(cum_var_exp)
前兩列的變化比較大,從第三列開(kāi)始變化比較小,說(shuō)明比重不大,所以我們決定將四維變成兩維。
- 四維變成兩維(
),我們需要一個(gè)
的矩陣,我們選擇前兩維的特征向量作為我們需要數(shù)據(jù)。
#因?yàn)榍皟删S的數(shù)據(jù)變化比較大,所以我們決定降到2維數(shù)據(jù),150x4->150x2 需要一個(gè)4x2的矩陣,前兩維的特征向量是我們需要的2維數(shù)據(jù)
matrix_w = np.hstack((eig_pairs[0][1].reshape(4,1),eig_pairs[1][1].reshape(4,1)))#水平方向平鋪
print('Matrix W:\n',matrix_w)

- 最后,我們將標(biāo)準(zhǔn)化后的數(shù)據(jù)與Matrix W相乘,得到我們降維后的數(shù)據(jù)
Y = x_std.dot(matrix_w)
print(Y)

一共150行
- 我們來(lái)對(duì)比一下,降維前與降維后的數(shù)據(jù)對(duì)比,
#畫(huà)圖比較進(jìn)行PCA之前和之后的變化
#之前
plt.figure(figsize=(6,6))
for lab,col in zip(('setosa','versicolor','virginica'),('blue','red','green')):
plt.scatter(x[y == lab,0],
x[y == lab,1],
label=lab,
c = col)
plt.xlabel('Sepal.Length')
plt.ylabel('Sepal.Width')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
#之后
plt.figure(figsize=(6,6))
for lab,col in zip(('setosa','versicolor','virginica'),('blue','red','green')):
plt.scatter(Y[y == lab,0],
Y[y == lab,1],
label=lab,
c = col)
plt.xlabel('Sepal.Length')
plt.ylabel('Sepal.Width')
plt.legend(loc='best')
plt.tight_layout()
plt.show()


通過(guò)比較發(fā)現(xiàn),經(jīng)過(guò)降維之后,數(shù)據(jù)更加分明,尤其是紅色與綠色部分,在降維前是比較難分離的,但是降維后我們會(huì)發(fā)現(xiàn),分離效果比較明顯。
補(bǔ)充:
sklearn中有封裝好的PCA,我們可以直接調(diào)用,非常方便。
sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False, svd_solver='auto', tol=0.0, iterated_power='auto',random_state=None)
- n_components:指定PCA降維后的特征維度數(shù)目
- copy表示是否在運(yùn)行算法時(shí),將原始數(shù)據(jù)復(fù)制一份。
默認(rèn)為T(mén)rue,則運(yùn)行PCA算法后,原始數(shù)據(jù)的值不會(huì)有任何改變。因?yàn)槭窃谠紨?shù)據(jù)的副本上進(jìn)行運(yùn)算的。 - whiten:白化。
所謂白化,就是對(duì)降維后的數(shù)據(jù)的每個(gè)特征進(jìn)行標(biāo)準(zhǔn)化,讓方差都為1。對(duì)于PCA降維本身來(lái)說(shuō),一般不需要白化。如果你PCA降維后有后續(xù)的數(shù)據(jù)處理動(dòng)作,可以考慮白化。默認(rèn)值是False,即不進(jìn)行白化。 - svd_solver:即指定奇異值分解SVD的方法
由于特征分解是奇異值分解SVD的一個(gè)特例,一般的PCA庫(kù)都是基于SVD實(shí)現(xiàn)的。有4個(gè)可以選擇的值:{‘a(chǎn)uto’, ‘full’, ‘a(chǎn)rpack’, ‘randomized’}。- 'randomized' 一般適用于數(shù)據(jù)量大,數(shù)據(jù)維度多同時(shí)主成分?jǐn)?shù)目比例又較低的PCA降維,它使用了一些加快SVD的隨機(jī)算法。
- 'full' 則是傳統(tǒng)意義上的SVD,使用了scipy庫(kù)對(duì)應(yīng)的實(shí)現(xiàn)。
- 'arpack' 和randomized的適用場(chǎng)景類(lèi)似,區(qū)別是randomized使用的是scikit-learn自己的SVD實(shí)現(xiàn),而arpack直接使用了scipy庫(kù)的sparse SVD實(shí)現(xiàn)。當(dāng)svd_solve設(shè)置為'arpack'時(shí),保留的成分必須少于特征數(shù),即不能保留所有成分。默認(rèn)是'auto',即PCA類(lèi)會(huì)自己去在前面講到的三種算法里面去權(quán)衡,選擇一個(gè)合適的SVD算法來(lái)降維。一般來(lái)說(shuō),使用默認(rèn)值就夠了|
from sklearn.decomposition import PCA
import pandas as pd
import numpy as np
def pca():
"""
主成分分析進(jìn)行特征降維
:return:
"""
#讀取數(shù)據(jù)集
data = pd.read_csv('../../數(shù)據(jù)集/機(jī)器學(xué)習(xí)/分類(lèi)算法/鳶尾花數(shù)據(jù)集/iris.csv')
#劃分特征值與目標(biāo)值
x = data.iloc[:,0:4].values
y = data.iloc[:,4].values
# print(x,y)
#數(shù)據(jù)標(biāo)準(zhǔn)化
std = StandardScaler()
x_std = std.fit_transform(x)
# 第二種方法:使用sklearn包
pca=PCA(n_components=2)#保留特證數(shù)目
Y=pca.fit_transform(x_std)
print(Y)
return None
if __name__=="__main__":
pca()

結(jié)果一樣,使用sklearn包我們只需要三行代碼就可以了,非常方便。
四、總結(jié)
1、優(yōu)點(diǎn)
- 不受樣本標(biāo)簽限制
- 計(jì)算方法簡(jiǎn)單,易于在計(jì)算機(jī)上實(shí)現(xiàn)
- 用少數(shù)指標(biāo)代替多數(shù)指標(biāo)
2、缺點(diǎn)
- 主成分解釋其含義往往具有一定的模糊性,不如原始樣本完整
- 貢獻(xiàn)率小的主成分往往可能含有對(duì)樣本差異的重要信息,也就是可能對(duì)于區(qū)分樣本的類(lèi)別(標(biāo)簽)更有用
- 特征值矩陣的正交向量空間是否唯一有待討論
好了,PCA主成分分析到這里就結(jié)束了,有問(wèn)題的小伙伴可以在下方留言或者私信,歡迎討論!