機(jī)器學(xué)習(xí)(七):PCA主成分分析和案例實(shí)現(xiàn)

一、算法簡(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)概念

  • 方差:
    Var(a)=\frac{1}{m}\sum_{i=1}^{m}(a_{i}-\mu)^2
  • 兩個(gè)特征之間的協(xié)方差
    \sigma_{jk}=\frac{1}{n-1}\sum_{i=1}^n(x_{ij}-\vec x_{j})(x_{ik}-\vec x_{k})
  • 協(xié)方差(假設(shè)均值為0時(shí)):
    Cov(a,b)=\frac{1}{m}\sum_{i=1}^{m}a_{i}b_{i}
  • 協(xié)方差矩陣:
    X=\begin{pmatrix} a_{1}&a_{2}&...&a_{m}\\ b_{1}&b_{2}&...&b_{m} \end{pmatrix}
    Cov = \frac{1}{m}XX^T=\begin{pmatrix} \frac{1}{m}\sum_{i=1}^{m}a_{i}^2&\frac{1}{m}\sum_{i=1}^{m}a_{i}b_{i}\\ \frac{1}{m}\sum_{i=1}^{m}a_{i}b_{i}&\frac{1}{m}\sum_{i=1}^{m}b_{i}^2 \end{pmatrix}
  • 協(xié)方差對(duì)角化:
    PCP^T=\begin{bmatrix} \lambda_{1}&&\\ &\lambda_{12}&\\ &&.\\ &&&.\\ &&&&.\\ &&&&&\lambda_{n}\\ \end{bmatrix}
    補(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ù):
    \begin{pmatrix} -1&-1&0&2&0\\ -2&0&0&1&1 \end{pmatrix}
    2、計(jì)算協(xié)方差矩陣
    C=\frac{1}{5}\begin{pmatrix} -1&-1&0&2&0\\ -2&0&0&1&1 \end{pmatrix}\begin{pmatrix} -1&-2\\ -1&0\\ 0&0\\ 2&1\\ 0&1 \end{pmatrix}=\begin{pmatrix} \frac{6}{5}&\frac{4}{5}\\ \frac{4}{5}&\frac{6}{5} \end{pmatrix}
    3、獲取特征值:\lambda_{1}=2,\lambda_{2}=2/5
    4、獲取特征向量:C_{1}\begin{pmatrix}1\\1\end{pmatrix},C_{2}\begin{pmatrix}-1\\1\end{pmatrix}
    5、特征向量一定能使協(xié)防差矩陣對(duì)角化:
    PCP^T=\begin{pmatrix}1/\sqrt{2}&1/\sqrt{2}\\-1/\sqrt{2}&1/\sqrt{2}\end{pmatrix}\begin{pmatrix}6/5&4/5\\4/5&6/5\end{pmatrix}\begin{pmatrix}1/\sqrt{2}&-1/\sqrt{2}\\1/\sqrt{2}&1/\sqrt{2}\end{pmatrix}=\begin{pmatrix}2&0\\0&2/5\end{pmatrix}
    6、將特征向量進(jìn)行標(biāo)準(zhǔn)化,然后降維
    Y=\begin{pmatrix}1/\sqrt{2}&1/\sqrt{2}\end{pmatrix}\begin{pmatrix} -1&-1&0&2&0\\-2&0&0&1&1\end{pmatrix}=\begin{pmatrix}-3/\sqrt{2}&-1/\sqrt{2}&0&3/\sqrt{2}&-1/\sqrt{2}\end{pmatrix}
    這就得到了我們想要的降維之后的數(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()
特征值
目標(biāo)值

截圖不完整,一共有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ō)明比重不大,所以我們決定將四維變成兩維。
  • 四維變成兩維(150 \times 4 \to 150 \times 2),我們需要一個(gè)4 \times 2的矩陣,我們選擇前兩維的特征向量作為我們需要數(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)題的小伙伴可以在下方留言或者私信,歡迎討論!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容