(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )html
主成分分析(Principal Component Analysis, PCA)能夠說是數據降維的絕招,不只在人口統計學,數量地理學,分子動力學模擬,數學建模等領域有着重要的應用,並且在機器學習領域,PCA也是很是經常使用的一種數據降維方法。git
首先來理解什麼叫數據降維:假設有一個項目,要從外觀上來判斷某我的是男人仍是女人,咱們能夠提取各類各樣的特徵,好比身高,通常而言,男人的身高要比女人高,但也有特例,好比頭髮長度,有無鬍鬚,臉型,衣服顏色,身材,體重,膚色,BMI指標。。。。等等,若是有須要,你能夠爲這個項目提取幾百甚至幾千個特徵,假如你一口氣提取了200個特徵,每個特徵都反映了一我的的某一個方面的信息,那麼,用機器學習的方法對這200個特徵進行建模,並用訓練集來訓練,則會很是耗時,並且獲得的模型結構龐大,故而咱們須要減小特徵數量,可是咱們不但願減小特徵數量的同時把重要的信息給弄丟了。將特徵數量從幾百上千下降到幾十的過程就是數據降維。github
在上面這個項目中,有不少特徵之間是由關聯的,好比BMI指標就是身高/體重的平方,那麼很明顯,BMI指標一個特徵就包括了身高和體重兩個特徵,BMI和這兩個指標之間具備很是強的相關性。同理,200個特徵之間也可能有不少變量之間具備相關性,因此這些相關特徵之間所反映的信息是同樣的,PCA的做用就是對全部的這200個特徵,去除相關性很是強的特徵,創建儘量少的新特徵,使得這些新特徵之間是兩兩不相關,而且這些新特徵在反應項目的信息方面會盡量保持原有的信息。算法
關於PCA的理論推導和更深層次的數學邏輯,請參考博文PCA算法dom
爲了看到降維效果,此處咱們用隨機數自動生成一個數據集,前兩個特徵向量都是隨機數,後三個特徵向量是前兩個特徵計算組合而來。以下爲代碼機器學習
# 假如某個項目有5個特徵,這五個特徵分別爲:
f1=np.random.normal(size=250)
f2=np.random.normal(size=250)
# 後面的三個特徵是前面兩個特徵演變而來,即與前面兩特徵具備很強的相關性
f3=2*f1+3*f2
f4=4*f1-f2
f5=f3+2*f4
複製代碼
不少時候,咱們要查看數據集中各特徵向量之間的相關性,以下學習
# 將這些特徵組合成數據集
dataset_X=np.c_[f1,f2,f3,f4,f5]
# 計算各特徵列之間的相關係數
df=pd.DataFrame(dataset_X,columns=['f1','f2','f3','f4','f5'])
print(df.corr())
複製代碼
-------------------------------------輸---------出--------------------------------spa
f1 f2 f3 f4 f5
複製代碼
f1 1.000000 -0.002496 0.528931 0.966354 0.994370 f2 -0.002496 1.000000 0.847342 -0.259627 0.103485 f3 0.528931 0.847342 1.000000 0.292844 0.615884 f4 0.966354 -0.259627 0.292844 1.000000 0.933656 f5 0.994370 0.103485 0.615884 0.933656 1.0000003d
--------------------------------------------完-------------------------------------code
能夠明顯看出,數據集中有不少特徵之間具備比較強的相關性,好比f1-f5,f1-f4等。
因此咱們能夠用PCA來進行降維:
# 能夠看出f1-f5,f1-f4,f2-f3等之間具備強相關性,故而能夠用PCA降維
from sklearn import decomposition
pca=decomposition.PCA()
pca.fit(dataset_X) # 用PCA降維
# 打印降維後的新特徵
variances=pca.explained_variance_
print(variances) # 能夠理解成該特徵的重要性,後面三個數字很是小,即特徵不重要
複製代碼
-------------------------------------輸---------出--------------------------------
[1.15552796e+02 1.14453854e+01 3.08872295e-31 8.39043564e-32 1.18268234e-32]
--------------------------------------------完-------------------------------------
# 故而能夠爲重要性設置一個閾值,小於該閾值的認爲該特徵不重要,可刪除
thresh=0.8
useful_features=variances>thresh
print(useful_features) # 標記爲True的表示重要特徵,要保留,False則刪除
複製代碼
-------------------------------------輸---------出--------------------------------
[ True True False False False]
--------------------------------------------完-------------------------------------
一旦咱們經過PCA進行了降維,就須要將原來的高維數據集轉換爲低維數據集,而後用低維數據集來建模
useful_features_num=np.sum(useful_features) # 計算True的個數
# 進行PCA降維以後的新數據集爲:
pca.n_components=useful_features_num # 即設置PCA的新特徵數量爲n_components
new_dataset_X=pca.fit_transform(dataset_X)
print('before PCA, dataset shape: ', dataset_X.shape)
print('after PCA, dataset shape: ', new_dataset_X.shape)
複製代碼
-------------------------------------輸---------出--------------------------------
before PCA, dataset shape: (250, 5) after PCA, dataset shape: (250, 2)
--------------------------------------------完-------------------------------------
PCA的優勢和缺點:
優勢:1,對數據進行降維處理,咱們能夠對新求出的「主元」向量的重要性進行排序,根據須要取前面最重要的部分,將後面的維數省去,能夠達到降維從而簡化模型或是對數據進行壓縮的效果。同時最大程度的保持了原有數據的信息。
2,徹底無參數限制,處理結果只與數據相關,而與用戶無關:在PCA的計算過程當中徹底不須要人爲的設定參數或是根據任何經驗模型對計算進行干預,最後的結果只與數據相關,與用戶是獨立的。
缺點:1,PCA以線性方式工做,若是數據集不是以線性方式組織的,那麼PCA效果就不好,此時,咱們能夠根據先驗知識對數據預先進行非線性轉換,將非線性數據集轉換到相信空間中,這種分析方式叫作Kernel-PCA,也叫核PCA,它解決了PCA只能處理線性數據集的缺點,又結合一些先驗知識的約束,是目前比較流行的方法。
2,有的數據集的分佈並不知足高斯分佈,在非高斯分佈的狀況下,PCA獲得的主要特徵可能並非最優的,在尋找主要特徵時不能將方差做爲衡量重要性的標準,此時要根據數據的分佈狀況選擇合適的描述徹底分佈的變量,根據必定的機率分佈公式來計算兩個特徵數據分佈的相關性,這種分析方式叫獨立主元分解(ICA)。
能夠參考博文: 主成分分析(Principal components analysis)-最小平方偏差解釋
前面提到,PCA雖好,但也不是放之四海而皆準,對於非線性方式組織的數據集,PCA方法可能效果較差,此時須要用核PCA方法來解決。
咱們來看一個典型的非線性方式組織的數據集:
# 準備數據集
from sklearn.datasets import make_circles
dataset_X,dataset_y=make_circles(n_samples=500,factor=0.2,noise=0.04)
複製代碼
該數據集的二維分佈圖爲:
那麼若是咱們用普通PCA對這個數據集進行降維,會獲得什麼樣的結果了?
# 若是用普通的PCA來降維
from sklearn.decomposition import PCA
pca = PCA()
dataset_X_pca = pca.fit_transform(dataset_X)
print(dataset_X_pca.shape)
visual_2D_dataset(dataset_X_pca,dataset_y,'PCA transformed dataset')
# 從圖中幾乎看不出PCA降維先後有啥區別
複製代碼
若是用核PCA來降維,可以將數據集變成線性可分,以下:
# 用核PCA方法來降維
from sklearn.decomposition import KernelPCA
kernel_pca = KernelPCA(kernel="rbf", fit_inverse_transform=True, gamma=10)
X_kernel_pca = kernel_pca.fit_transform(dataset_X)
print(X_kernel_pca.shape) # 2維特徵變成了465維,降維?增維?
visual_2D_dataset(X_kernel_pca[:,:2],dataset_y,'Kernel PCA transformed dataset')
複製代碼
很明顯,獲得的新數據集即是線性可分。
話說,怎麼通過核PCA降維以後,原先的2個特徵怎麼增長到465個特徵?降維仍是增維?呵呵。
那麼從這個核PCA獲得的新數據集可以返回到原來的數據集了?
# 如何從Kernel PCA獲得的數據集反向計算出原始的數據集
dataset_X_inverse = kernel_pca.inverse_transform(X_kernel_pca)
print(dataset_X_inverse.shape)
visual_2D_dataset(dataset_X_inverse,dataset_y,'inversed dataset_X from KernelPCA')
複製代碼
能夠看出,恢復以後的數據集的分佈狀況和原始數據集的分佈狀況相同。
########################小**********結###############################
1,對數據集進行降維能夠很好地解決特徵數太多致使的訓練太耗時,模型結構臃腫的問題,降維方法有不少種,其中的PCA降維方式能夠解決具備線性方式的數據集,而核PCA方法能夠對具備非線性方式組織的數據集進行降維。
#################################################################
注:本部分代碼已經所有上傳到(個人github)上,歡迎下載。
參考資料:
1, Python機器學習經典實例,Prateek Joshi著,陶俊傑,陳小莉譯