sklearn实战之降维算法PCA与SVD
sklearn實戰(zhàn)系列:
(1) sklearn實戰(zhàn)之決策樹
(2) sklearn實戰(zhàn)之隨機森林
(3) sklearn實戰(zhàn)之?dāng)?shù)據(jù)預(yù)處理與特征工程
(4) sklearn實戰(zhàn)之降維算法PCA與SVD
(5) sklearn實戰(zhàn)之邏輯回歸與制作評分卡
(6) sklearn實戰(zhàn)之聚類算法
四、sklearn中的降維算法PCA和SVD
1、sklearn中的降維算法
sklearn中降維算法都被包括在模塊decomposition中,這個模塊本質(zhì)是一個矩陣分解模塊。在過去的十年中,如果要討論算法進(jìn)步的先鋒,矩陣分解可以說是獨樹一幟。矩陣分解可以用在降維,深度學(xué)習(xí),聚類分析,數(shù)據(jù)預(yù)處理,低緯度特征學(xué)習(xí),推薦系統(tǒng),大數(shù)據(jù)分析風(fēng)領(lǐng)域中。在2006年,Netflix舉辦了一個獎金為100萬美元的推薦系統(tǒng)算法的比賽,最后的獲獎?wù)呔褪褂昧司仃嚪纸庵械拿餍?#xff1a;SVD分解(奇異值分解)。
| 主成分分析 | |
| decomposition.PCA | 主成分分析(PCA) |
| decomposition.IncrementalPCA | 增量主成分分析(IPCA) |
| decomposition.KernelPCA | 核主成分分析(KPCA) |
| decomposition.MiniBatchSparserPCA | 小批量系數(shù)主成分分析 |
| decomposition.SparserPCA | 系數(shù)主成分分析(SparserPCA) |
| decomposition.TruncatedSVD | 截斷的SVD(aka LSA) |
| 因子分析 | |
| decomposition.FactorAnalysis | 因子分析(FA) |
| 獨立成分分析 | |
| decomposition.FastICA | 獨立成分分析的快速算法 |
| 字典學(xué)習(xí) | |
| decomposition.DictionaryLearning | 字典學(xué)習(xí) |
| decomposition.MiniBatchDictionaryLearning | 小批量字典學(xué)習(xí) |
| decomposition.dict_learning | 字典學(xué)習(xí)用于矩陣分解 |
| decomposition.dict_learning_online | 在線字典學(xué)習(xí)用于矩陣分解 |
| 高級矩陣分解 | |
| decomposition.LatentDirichletAllocation | 具有在線變貝葉斯算法的隱含迪利克雷分布 |
| decomposition.NMF | 非負(fù)矩陣分解(NMF) |
| 其他矩陣分解 | |
| decomposition.SparerCoder | 稀疏編碼 |
SVD和主成分分析PAce都屬于矩陣分解算法中斷的入門算法,都是通過分解特征矩陣來進(jìn)行降維,他們也是我們要學(xué)習(xí)的重點!
2、PCA與SVD
在降維過程中,我們會減少特征的數(shù)量,這意味著刪除數(shù)據(jù),數(shù)據(jù)亮變少則表示模型可以獲取的信息就會變少,模型的表現(xiàn)可能因此受影響。同時,在高維數(shù)據(jù)中,必然有一些特征是不帶有效信息的(比如噪聲),或者,有些特征帶有的信息和其他一些特征是重讀的(比如一些特征可能會線性相關(guān))。我們希望能夠找出一種辦法來幫助我們衡量特特征上所帶的信息量,讓我們在降維的過程中,能夠既減少特征的數(shù)量,又保留大部分有效信息——將那些帶有重復(fù)信息的特征合并,并刪除那些無效信息的特征等等——組件創(chuàng)造出能夠代表原特征矩陣大部分信息的,特征更少的,新特征矩陣。
上周的特征工程課中,我們提到過一種重要的特征選擇方法:方差過濾。如果一個特征的方差很小,則意味這這個特征可能很大程度上有大量取值都相同(比如90%是1,甚至100%是1),那這個特征的取值對樣本而言就沒有區(qū)分度,這種特征就不帶有有效信息。從方差的這種應(yīng)用就可以推斷出,如果一個特征的方差很大,則說明這個特征上帶大量的信息。因此,在降維中,PCA使用的信息量衡量指標(biāo)就是樣本方差,又可稱為可解釋性方差,方差越大,特征所帶的信息也就越多。
Var=1n?1∑i=1n(xi?xhat)2Var=\frac{1}{n-1}\sum_{i=1}^n(x_i-x^{hat})^2 Var=n?11?i=1∑n?(xi??xhat)2
Var代表一個特征大方差,n代表樣本量,xi代表一個特征中的每一個樣本取值,xhatx^{hat}xhat代表這一列樣本的均值。
面試高危問題
方差計算公式中為什么除數(shù)是n-1?
這是為了得到樣本的無偏估計,更多的大家自己去探索吧~
2.1 降維究竟是怎樣實現(xiàn)?
2.2 重要參數(shù)n_components
n_components是我們降維后需要的維度,即降維后需要保留的特征數(shù)量,降維流程中第二步里需要確認(rèn)的K值,一般輸入[0,min(X.shape)]范圍中的證書。一說到K,大家可能都會想到,類似于KNN中的K和隨機森林中的n_estimators。這是一個需要我們認(rèn)為去確定的超參數(shù),并且我們設(shè)定的數(shù)字會影響到模型的表現(xiàn)。如果留下的特征太多,就達(dá)不到降維的效果,如果留下的特征太小,那新特征可能無法容納原始數(shù)據(jù)集中的大部分信息,因此,n_components既不能太大也不能太小。那應(yīng)該怎么選擇呢?
可以先從我們的降維目標(biāo)開始說起:如果我們希望可視化一組數(shù)據(jù)來觀察數(shù)據(jù)分布,我們往往將數(shù)據(jù)降到三維以下,很多時候是二維,即n_components的取值是2。
2.2.1 迷你案例:高維數(shù)據(jù)的可視化
1、調(diào)用庫和模塊
import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.decomposition import PCA2、提取數(shù)據(jù)集
iris = load_iris() y = iris.target X = iris.data #作為數(shù)組,X是幾維? X.shape #作為數(shù)據(jù)表或特征矩陣,X是幾維? import pandas as pd pd.DataFrame(X)3、建模
#調(diào)用PCA pca = PCA(n_components=2) #實例化 pca = pca.fit(X) #擬合模型 X_dr = pca.transform(X) #獲取新矩陣 X_dr #也可以fit_transform一步到位 #X_dr = PCA(2).fit_transform(X)4、可視化
#要將三種鳶尾花的數(shù)據(jù)分布顯示在二維平面坐標(biāo)系中,對應(yīng)的兩個坐標(biāo)(兩個特征向量)應(yīng)該是三種鳶尾花降維后的 x1和x2,怎樣才能取出三種鳶尾花下不同的x1和x2呢? X_dr[y == 0, 0] #這里是布爾索引,看出來了么? #要展示三中分類的分布,需要對三種鳶尾花分別繪圖 #可以寫成三行代碼,也可以寫成for循環(huán) """ plt.figure() plt.scatter(X_dr[y==0, 0], X_dr[y==0, 1], c="red", label=iris.target_names[0]) plt.scatter(X_dr[y==1, 0], X_dr[y==1, 1], c="black", label=iris.target_names[1]) plt.scatter(X_dr[y==2, 0], X_dr[y==2, 1], c="orange", label=iris.target_names[2]) plt.legend() plt.title('PCA of IRIS dataset') plt.show() """ colors = ['red', 'black', 'orange'] iris.target_names plt.figure() for i in [0, 1, 2]:plt.scatter(X_dr[y == i, 0],X_dr[y == i, 1],alpha=.7,c=colors[i],label=iris.target_names[i]) plt.legend() plt.title('PCA of IRIS dataset') plt.show()鳶尾花的分布被展現(xiàn)在我們眼前了,明顯這是一個分簇的分布,并且每個簇之間的分布相對比較明顯,也許 versicolor和virginia這兩種花之間會有一些分類錯誤,但setosa肯定不會被分錯。這樣的數(shù)據(jù)很容易分類,可以遇 見,KNN,隨機森林,神經(jīng)網(wǎng)絡(luò),樸素貝葉斯,Adaboost這些分類器在鳶尾花數(shù)據(jù)集上,未調(diào)整的時候都可以有 95%上下的準(zhǔn)確率。
6、探索降維后的數(shù)據(jù)
#屬性explained_variance_,查看降維后每個新特征向量上所帶的信息量大小(可解釋性方差的大小) pca.explained_variance_ #屬性explained_variance_ratio,查看降維后每個新特征向量所占的信息量占原始數(shù)據(jù)總信息量的百分比 #又叫做可解釋方差貢獻(xiàn)率 pca.explained_variance_ratio_ #大部分信息都被有效地集中在了第一個特征上 pca.explained_variance_ratio_.sum()7、選擇最好的n_components:積累可解釋方差貢獻(xiàn)率曲線
當(dāng)參數(shù)n_components中不填寫任何值,則默認(rèn)返回min(X.shape)個特征,一般來說,樣本量都會大于特征數(shù)目,所以什么都不填就相當(dāng)于轉(zhuǎn)換了新特征孔家,但沒有減少特征的個數(shù)。一般來說,不會使用這種輸入方式。但我們卻可以使用這種輸入方式畫出累計可解釋方差貢獻(xiàn)率曲線,以此選擇最好的n_components的整數(shù)取值。
累計可解釋方差貢獻(xiàn)曲線是一條以降維后新特征矩陣捕捉到的可解釋方差貢獻(xiàn)率為縱坐標(biāo),能夠幫助我們解決n_components最好的取值。
import numpy as np pca_line = PCA().fit(X) plt.plot([1,2,3,4],np.cumsum(pca_line.explained_variance_ratio_)) plt.xticks([1,2,3,4]) #這是為了限制坐標(biāo)軸顯示為整數(shù) plt.xlabel("number of components after dimension reduction") plt.ylabel("cumulative explained variance ratio") plt.show()2.2.2 最大似然估計自選超參數(shù)
除了輸入證書,n_components還有哪些選擇呢?矩陣分解的理論發(fā)展在業(yè)界獨樹一幟,勤奮智 慧的數(shù)學(xué)大神Minka, T.P.在麻省理工學(xué)院媒體實驗室做研究時找出了讓PCA用最大似然估計(maximum likelihood estimation)自選超參數(shù)的方法,輸入“mle”作為n_components的參數(shù)輸入,就可以調(diào)用這種方法。
pca_mle = PCA(n_components="mle") pca_mle = pca_mle.fit(X) X_mle = pca_mle.transform(X) X_mle #可以發(fā)現(xiàn),mle為我們自動選擇了3個特征 pca_mle.explained_variance_ratio_.sum() #得到了比設(shè)定2個特征時更高的信息含量,對于鳶尾花這個很小的數(shù)據(jù)集來說,3個特征對應(yīng)這么高的信息含量,并不 需要去糾結(jié)于只保留2個特征,畢竟三個特征也可以可視化2.2.3 按信息量占比選超參數(shù)
輸入[0,1]之間的浮點數(shù),并且讓參數(shù)svd_slover==“full”,表示希望降維后的總解釋性方差占比大于n_components指定的百分比,即是說,希望保留百分之多少的信息量。比如說,如果我們希望暴力流97%的信息量,就可以輸入n_components=0.97,PCA就會自動選出能夠讓保留的信息量超過97%的特征數(shù)量。
pca_f = PCA(n_components=0.97,svd_solver="full") pca_f = pca_f.fit(X) X_f = pca_f.transform(X) pca_f.explained_variance_ratio_2.3 PCA中的SVD
2.3.1 PCA中的SCD哪里來的?
細(xì)心的同學(xué)可能注意到了,svd_solver是奇異值分解器的意思,為什么PCA算法下面會有關(guān)奇異值分解的參數(shù)?不是兩種算法嗎?我們之前曾經(jīng)提及過,PCA和SVD設(shè)計了大量的矩陣計算,兩者都是計算量很大的模型,但是其實,SVD有一種驚人的數(shù)學(xué)性質(zhì),即是它可以跳過數(shù)學(xué)神秘的宇宙,不計算協(xié)方差矩陣,直接找出一個新特征向量組成的n維空間,而這個n維空間就是奇異值分解后的右矩陣VTV^TVT(所以一開始講解降維過程中,我們說到的“生成新特征向量組成的空間V“,并非巧合,而是指奇異值分解后的矩陣VTV^TVT)。
右奇異值矩陣VTV^TVT有著如下性質(zhì):
Xdr=X?V[:k]TX^{dr}=X*V[:k]^T Xdr=X?V[:k]T
k就是n_components,是我們降維后希望得到的維度,弱X是(m,n)的特征矩陣,VTV^TVT就是結(jié)構(gòu)為(n,n)的矩陣,取這個矩陣的前k行(進(jìn)行切片),即將V轉(zhuǎn)換為結(jié)構(gòu)為(k,n)的矩陣。而V(k,n)TV_{(k,n)}^TV(k,n)T?與原特征矩陣X相乘,即可得到降維后的特征矩陣X_dr。這就是說,奇異值分解可以不計算協(xié)方差矩陣等等結(jié)構(gòu)復(fù)雜計算冗長的矩陣,就直接求出新特征空間和降維后的特征矩陣。
簡而言之,SVD在矩陣分解中的過程比PCA簡單快速,雖然兩個算法都走一樣的分解流程,但SVD可以作弊耍賴直接算出V。但遺憾的是,SVD的信息量衡量指標(biāo)比較復(fù)雜,要理解”奇異值”比理解方差來的容易,因此sklearn將降維流程拆成了兩部分:一部分似乎計算特征空間V,由于奇異值分解完成,另一部分是映射數(shù)據(jù)和求解新特征矩陣,有主成分分析完成,實現(xiàn)了有用SVD的性質(zhì)減少計算量,卻讓信息量的評估指標(biāo)是方差,具體流程如下圖:
講到這里,相信大家就能理解,為什么PCA的類里會包含控制SVD分解器的參數(shù)了。通過SVD和PCA的合作,sklearn實現(xiàn)了一種計算更快更簡單,但效果卻很好的“合作降維”。很多人理解SVD,是把SVD當(dāng)作是PCA的一種求解方法,但在sklearn中,矩陣U和Σ雖然會被計算出來(童顏也是一種比起PCA來說簡化非常多的數(shù)學(xué)過程,不產(chǎn)生協(xié)方差矩陣),但完全不會被用到,也無法調(diào)取查看或者使用,因此我們可以認(rèn)為,U和Σ在fit過后就被遺棄了。奇異值分解追求的僅僅是V,只要有了V,就可以計算出降維后的特征矩陣。在transform過程之后,fit中奇異值分解的結(jié)果除了V(k,n)以外,都會被舍棄,而V(k,n)會被保留在屬性components_當(dāng)中,可以調(diào)用查看。
PCA(2).fit(X).components_ PCA(2).fit(X).components_.shape輸出:
(2, 4)2.3.2 重要參數(shù)svd_solver與random_state
參數(shù)svd_solver是在降維過程中,用來控制矩陣分解的一些細(xì)節(jié)的參數(shù)。有四種模式可以選:“auto”,“full”,“arapck”,“randomized”,默認(rèn)"auto"。
- ”auto“:基于X.shape和n_components的默認(rèn)策略來選擇分解器。如果輸入的數(shù)據(jù)的尺寸大于500×500且要提取的特征數(shù)小于數(shù)據(jù)最小維度min(X.shape)的80%,就啟用效率更的”randomized“方法。否則,精確完整 的SVD將被計算,截斷將會在矩陣被分解完成后有選擇地發(fā)生。
- ”full“:從scipy.linalg.svd中調(diào)用標(biāo)準(zhǔn)的LAPACK分解器來生成精確完整的SVD,適合數(shù)據(jù)量比較適中,計算時 間充足的情況,生成的精確完整的SVD的結(jié)構(gòu)為:
U(m,m),Σ(m,n),V(n,n)TU_{(m,m)},Σ_{(m,n)},V_{(n,n)}^T U(m,m)?,Σ(m,n)?,V(n,n)T?
- "arpack":從scipy.sparse.linalg.svds調(diào)用ARPACK分解器來運行截斷奇異值分解(SVD truncated),分解時就 將特征數(shù)量降到n_components中輸入的數(shù)值k,可以加快運算速度,適合特征矩陣很大的時候,但一般用于 特征矩陣為稀疏矩陣的情況,此過程包含一定的隨機性。截斷后的SVD分解出的結(jié)構(gòu)為:
U(m,k),Σ(k,k),V(n,n)TU_{(m,k)},Σ_{(k,k)},V_{(n,n)}^T U(m,k)?,Σ(k,k)?,V(n,n)T?
- "randomized":通過Halko等人的隨機方法進(jìn)行隨機SVD。在"full"方法中,分解器會根據(jù)原始數(shù)據(jù)和輸入的 n_components值去計算和尋找符合需求的新特征向量,但是在"randomized"方法中,分解器會先生成多個 隨機向量,然后一一去檢測這些隨機向量中是否有任何一個符合我們的分解需求,如果符合,就保留這個隨 機向量,并基于這個隨機向量來構(gòu)建后續(xù)的向量空間。這個方法已經(jīng)被Halko等人證明,比"full"模式下計算快很多,并且還能夠保證模型運行效果。適合特征矩陣巨大,計算量龐大的情況。
而參數(shù)random_state在參數(shù)svd_solver的值為"arpack" or "randomized"的時候生效,可以控制這兩種SVD模式中 的隨機模式。通常我們就選用”auto“,不必對這個參數(shù)糾結(jié)太多。
2.3.3 重要屬性components_
現(xiàn)在我們了解了,V(k,n)是新特征空間,是我們要將原始數(shù)據(jù)進(jìn)行映射的那些新特征向量組成的矩陣,我們用它來計算新的特征矩陣,但我們希望獲取的是X_dr,為什么我們要把V(k,n)這個矩陣保存在n_components這個屬性當(dāng)中來讓大家調(diào)取查看呢?
我們之前談過PCA和特征選擇的區(qū)別,即特征選擇后的特征矩陣是可解讀的,而PC啊降維后的特征矩陣是不可解讀的:PCA是將已經(jīng)存在的特征進(jìn)行壓縮,降維完畢后的特征已經(jīng)不是原本特征矩陣中的任何一個特征,而是通過某些方式組合起來的新特征,通常來說,在新的特征矩陣生成之前,我們都無法知曉PCA都建立了怎樣的新特征向量,新特征矩陣生成之后也不具有可讀性,我們就無法判斷新特征矩陣的特征是從原數(shù)據(jù)中的什么特征組合而來的,新特征雖然帶有原始數(shù)據(jù)的信息,卻已經(jīng)不是原數(shù)據(jù)上代表的含義了。
但是其實,在矩陣分解時,PCA時有目標(biāo)的:在原特征的基礎(chǔ)上,找出能夠讓信息盡量聚集的新特征向量。在 sklearn使用的PCA和SVD聯(lián)合的降維方法中,這些新特征向量組成的新特征空間其實就是V(k,n)。當(dāng)V(k,n)是數(shù)字 時,我們無法判斷V(k,n)和原有的特征究竟有著怎樣千絲萬縷的數(shù)學(xué)聯(lián)系。但是,如果原特征矩陣是圖像,V(k,n)這 個空間矩陣也可以被可視化的話,我們就可以通過兩張圖來比較,就可以看出新特征空間究竟從原始數(shù)據(jù)里提取了 什么重要的信息。
讓我們來看一個,人臉識別中屬性components_的運用。
1、導(dǎo)入需要的庫和模塊
from sklearn.datasets import fetch_lfw_people from sklearn.decomposition import PCA import matplotlib.pyplot as plt import numpy as np2、實例化數(shù)據(jù)集,探索數(shù)據(jù)
faces = fetch_lfw_people(min_faces_per_person=60) faces.images.shape #怎樣理解這個數(shù)據(jù)的維度? faces.data.shape #換成特征矩陣之后,這個矩陣是什么樣? X = faces.data3、看看圖像什么樣?將原特征矩陣進(jìn)行可視化
#數(shù)據(jù)本身是圖像,和數(shù)據(jù)本身只是數(shù)字,使用的可視化方法不同 #創(chuàng)建畫布和子圖對象 fig, axes = plt.subplots(4,5,figsize=(8,4),subplot_kw = {"xticks":[],"yticks":[]} #不要顯示坐標(biāo)軸) fig axes #不難發(fā)現(xiàn),axes中的一個對象對應(yīng)fig中的一個空格 #我們希望,在每一個子圖對象中填充圖像(共24張圖),因此我們需要寫一個在子圖對象中遍歷的循環(huán) axes.shape #二維結(jié)構(gòu),可以有兩種循環(huán)方式,一種是使用索引,循環(huán)一次同時生成一列上的三個圖 #另一種是把數(shù)據(jù)拉成一維,循環(huán)一次只生成一個圖 #在這里,究竟使用哪一種循環(huán)方式,是要看我們要畫的圖的信息,儲存在一個怎樣的結(jié)構(gòu)里 #我們使用 子圖對象.imshow 來將圖像填充到空白畫布上 #而imshow要求的數(shù)據(jù)格式必須是一個(m,n)格式的矩陣,即每個數(shù)據(jù)都是一張單獨的圖 #因此我們需要遍歷的是faces.images,其結(jié)構(gòu)是(1277, 62, 47) #要從一個數(shù)據(jù)集中取出24個圖,明顯是一次性的循環(huán)切片[i,:,:]來得便利 #因此我們要把axes的結(jié)構(gòu)拉成一維來循環(huán) axes.flat enumerate(axes.flat) #填充圖像 for i, ax in enumerate(axes.flat):ax.imshow(faces.images[i,:,:] ,cmap="gray") #選擇色彩的模式#https://matplotlib.org/tutorials/colors/colormaps.html輸出:
4、建模降維,提取新特征空間矩陣
#原本有2900維,我們現(xiàn)在來降到150維 pca = PCA(150).fit(X) V = pca.components_ V.shape輸出(150,2914)
5、將新特征空間矩陣可視化
fig, axes = plt.subplots(3,8,figsize=(8,4),subplot_kw = {"xticks":[],"yticks":[]}) for i, ax in enumerate(axes.flat):ax.imshow(V[i,:].reshape(62,47),cmap="gray")輸出:
這張圖稍稍有一些恐怖,但可以看出,比起降維前的數(shù)據(jù),新特征空間可視化后的人臉非常模糊,這是因為原始數(shù)據(jù)還沒有被映射到特征空間中。但可以看出,整體比較亮的圖片,獲取的信息較多,整體較暗的圖片,卻智能看到漆黑的一片。在比較亮的圖片中,眼睛,鼻子,嘴巴等五官都相對清晰,臉的輪廓,頭發(fā)之類的比較模糊。
這說明,新特征空間里的特征向量們,大部分是”五官“和”亮度“相關(guān)的向量,所以新特征向量上的信息肯定大部分是由原數(shù)據(jù)中的”五官“和”亮度“相關(guān)的特征中提取出來的。到這里,我們通過可視化新特征空間X,解釋了一部分降維后的特征:雖然顯示出來的數(shù)字看著不知所云,但畫出來的圖表示,這些特征是和”無關(guān)“以及”亮度“相關(guān)的。這也再次證明了,PCA能夠啊將原始數(shù)據(jù)集中重要的數(shù)據(jù)進(jìn)行聚集。
2.4 重要接口inverse_transform
在上篇的特征工程中,我們學(xué)到了神奇的接口inverse_transform,可以將我們歸一化,標(biāo)準(zhǔn)化,甚至做過啞變量的特征矩陣還原回原始數(shù)據(jù)中的特征矩陣,這幾乎向我們暗示,任何有inverse_transform這個接口的過儲層都是可逆的。PCA應(yīng)該也是如此。在sklearn中,我們通過讓原特征矩陣X右乘新特征空間矩陣V(k,n)來生成新特征矩陣X_dr,那理論上來說,讓新特征矩陣X_dr右乘V(k,n)的逆矩陣V(k,n)?1V_{(k,n)}^{-1}V(k,n)?1?,就可以將新特征矩陣X_dr還原為X。那sklearn是否這樣做了呢?讓我們來看看下面的案例。
2.4.1 迷你案例:用人臉識別看PCA降維后的信息保存量
人臉識別是容易的,用來探索inverse_transform功能的數(shù)據(jù)。我們先調(diào)用一組人臉數(shù)據(jù)X(m,n),對人臉圖像進(jìn)行繪制,然后我們對人臉數(shù)據(jù)進(jìn)行降維得到X_dr,zhi后再使用inverse_transform(X_dr)返回一個X_transform(m,n),并對這個新矩陣中的人臉圖像也進(jìn)行繪制。如果PCA的降維過程是可逆的,我們應(yīng)當(dāng)期待X(m,n)和X_transform(m,n)返回一摸一樣的圖像,即攜帶一摸一樣的信息。
1、導(dǎo)入需要的模塊和庫
from sklearn.datasets import fetch_lfw_people from sklearn.decomposition import PCA import matplotlib.pyplot as plt import numpy as np2、導(dǎo)入數(shù)據(jù)并探索
faces = fetch_lfw_people(min_faces_per_person=60) faces.images.shape #怎樣理解這個數(shù)據(jù)的維度? faces.data.shape #換成特征矩陣之后,這個矩陣是什么樣? X = faces.data3、漸濃降維,獲取降維后的新特征矩陣X_dr
pca = PCA(150) X_dr = pca.fit_transform(X) X_dr.shape4、將降維后的矩陣用inverse_transform返回原空間
X_inverse = pca.inverse_transform(X_dr) X_inverse.shape5、將特征矩陣X和X_inverse可視化
fig, ax = plt.subplots(2,10,figsize=(10,2.5),subplot_kw={"xticks":[],"yticks":[]}) #和2.3.3節(jié)中的案例一樣,我們需要對子圖對象進(jìn)行遍歷的循環(huán),來將圖像填入子圖中 #那在這里,我們使用怎樣的循環(huán)? #現(xiàn)在我們的ax中是2行10列,第一行是原數(shù)據(jù),第二行是inverse_transform后返回的數(shù)據(jù) #所以我們需要同時循環(huán)兩份數(shù)據(jù),即一次循環(huán)畫一列上的兩張圖,而不是把ax拉平 for i in range(10):ax[0,i].imshow(face.image[i,:,:],cmap="binary_r")ax[1,i].imshow(X_inverse[i].reshape(62,47),cmap="binary_r")可以明顯看出,這兩組數(shù)據(jù)可視化后,由降維后再通過inverse_transform轉(zhuǎn)換回原維度的數(shù)據(jù)畫出的圖像和原數(shù) 據(jù)畫的圖像大致相似,但原數(shù)據(jù)的圖像明顯更加清晰。這說明,inverse_transform并沒有實現(xiàn)數(shù)據(jù)的完全逆轉(zhuǎn)。 這是因為,在降維的時候,部分信息已經(jīng)被舍棄了,X_dr中往往不會包含原數(shù)據(jù)100%的信息,所以在逆轉(zhuǎn)的時 候,即便維度升高,原數(shù)據(jù)中已經(jīng)被舍棄的信息也不可能再回來了。所以,降維不是完全可逆的。 Inverse_transform的功能,是基于X_dr中的數(shù)據(jù)進(jìn)行升維,將數(shù)據(jù)重新映射到原數(shù)據(jù)所在的特征空間中,而并非 恢復(fù)所有原有的數(shù)據(jù)。但同時,我們也可以看出,降維到300以后的數(shù)據(jù),的確保留了原數(shù)據(jù)的大部分信息,所以 圖像看起來,才會和原數(shù)據(jù)高度相似,只是稍稍模糊罷了。
2.4.2 迷你案例:用PCA做噪音過濾
降維的目的之一就是希望拋棄掉對模型帶來負(fù)面影響的特征,而我們相信,帶有效信息的特征的方差應(yīng)該是遠(yuǎn)大于 噪音的,所以相比噪音,有效的特征所帶的信息應(yīng)該不會在PCA過程中被大量拋棄。inverse_transform能夠在不 恢復(fù)原始數(shù)據(jù)的情況下,將降維后的數(shù)據(jù)返回到原本的高維空間,即是說能夠?qū)崿F(xiàn)”保證維度,但去掉方差很小特 征所帶的信息“。利用inverse_transform的這個性質(zhì),我們能夠?qū)崿F(xiàn)噪音過濾。
1、導(dǎo)入所需要的庫和模塊
from sklearn.datasets import load_digits from sklearn.decomposition import PCA import matplotlib.pyplot as plt import numpy as np2、導(dǎo)入數(shù)據(jù),探索數(shù)據(jù)
digits = load_digits() digits.data.shape3、自定義畫圖函數(shù)
def plot_digits(data):fig, axes = plt.subplots(4,10,figsize=(10,4),subplot_kw = {"xticks":[],"yticks":[]})for i, ax in enumerate(axes.flat):ax.imshow(data[i].reshape(8,8),cmap="binary")plot_digits(digits.data)[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fys0hIpY-1629554113021)(D:typora/picture/噪聲前.jpg)]
4、為數(shù)據(jù)加上噪音
np.random.RandomState(42) #在指定的數(shù)據(jù)集中,隨機抽取服從正態(tài)分布的數(shù)據(jù) #兩個參數(shù),分別是指定的數(shù)據(jù)集,和抽取出來的正太分布的方差 noisy = np.random.normal(digits.data,2) plot_digits(noisy)5、降維
pca = PCA(0.5).fit(noisy) X_dr = pca.transform(noisy) X_dr.shape6、逆轉(zhuǎn)降維結(jié)果,實現(xiàn)降噪
without_noise = pca.inverse_transform(X_dr) plot_digits(without_noise)2.5 重要接口,參數(shù)和屬性總結(jié)
到現(xiàn)在,我們已經(jīng)完成了對PCA的講解。我們講解了重要參數(shù)參數(shù)n_components,svd_solver,random_state, 講解了三個重要屬性:components_, explained_variance_以及explained_variance_ratio_,無數(shù)次用到了接口 fit,transform,fit_transform,還講解了與眾不同的重要接口inverse_transform。所有的這些內(nèi)容都可以被總結(jié) 在這張圖中:
3、案例:PCA對手寫數(shù)字?jǐn)?shù)據(jù)集的降維
還記得我們上次在介紹特征工程時,使用的手寫數(shù)字的數(shù)據(jù)集嗎?數(shù)據(jù)集結(jié)構(gòu)為(42000, 784),用KNN跑一次半小 時,得到準(zhǔn)確率在96.6%上下,用隨機森林跑一次12秒,準(zhǔn)確率在93.8%,雖然KNN效果好,但由于數(shù)據(jù)量太大, KNN計算太緩慢,所以我們不得不選用隨機森林。我們使用了各種技術(shù)對手寫數(shù)據(jù)集進(jìn)行特征選擇,最后使用嵌入 法SelectFromModel選出了324個特征,將隨機森林的效果也調(diào)到了96%以上。但是,因為數(shù)據(jù)量依然巨大,還是 有300多個特征。今天,我們就來試著用PCA處理一下這個數(shù)據(jù),看看效果如何。
1、導(dǎo)模塊和庫
from sklearn.decomposition import PCA from sklearn.ensemble import RandomForestClassifier as RFC from sklearn.model_selection import cross_val_score import matplotlib.pyplot as plt import pandas as pd import numpy as np2、導(dǎo)入數(shù)據(jù)
data = pd.read_csv(r"C:\work\learnbetter\micro-class\week 3 Preprocessing\digit recognizor.csv") X = data.iloc[:,1:] y = data.iloc[:,0]3、畫累計方差貢獻(xiàn)曲線,找最佳降維后維度的范圍
pca_line = PCA().fit(X) plt.figure(figsize=[20,5]) plt.plot(np.cumsum(pca_line.explained_variance_ratio_)) plt.xlabel("number of components after dimension reduction") plt.ylabel("cumulative explained variance ratio") plt.show()4、降維后的學(xué)習(xí)曲線,繼續(xù)縮小最佳的范圍
#======【TIME WARNING:2mins 30s】======# score = [] for i in range(1,101,10):X_dr = PCA(i).fit_transform(X)once = cross_val_score(RFC(n_estimators=10,random_state=0),X_dr,y,cv=5).mean()score.append(once) plt.figure(figsize=[20,5]) plt.plot(range(1,101,10),score) plt.show()5、細(xì)化學(xué)習(xí)曲線,找出降維后的最佳維度
#======【TIME WARNING:2mins 30s】======# score = [] for i in range(10,25):X_dr = PCA(i).fit_transform(X)once = cross_val_score(RFC(n_estimators=10,random_state=0),X_dr,y,cv=5).mean()score.append(once) plt.figure(figsize=[20,5]) plt.plot(range(10,25),score) plt.show()6、導(dǎo)入找出最佳的維度進(jìn)行降維,并查看模型效果
X_dr = PCA(23).fit_transform(X) #======【TIME WARNING:1mins 30s】======# cross_val_score(RFC(n_estimators=100,random_state=0),X_dr,y,cv=5).mean()模型效果還好,跑出了94.49%的水平,但還是沒有我們使用嵌入法特征選擇過后的96%高,有沒有什么辦法能夠 提高模型的表現(xiàn)呢?
7、 突發(fā)奇想,特征數(shù)量已經(jīng)不足原來的3%,換模型怎么樣?
在之前的建模過程中,因為計算量太大,所以我們一直使用隨機森林,但事實上,我們知道KNN的效果比隨機森林 更好,KNN在未調(diào)參的狀況下已經(jīng)達(dá)到96%的準(zhǔn)確率,而隨機森林在未調(diào)參前只能達(dá)到93%,這是模型本身的限制 帶來的,這個數(shù)據(jù)使用KNN效果就是會更好。現(xiàn)在我們的特征數(shù)量已經(jīng)降到不足原來的3%,可以使用KNN了嗎?
from sklearn.neighbors import KNeighborsClassifier as KNN cross_val_score(KNN(),X_dr,y,cv=5).mean()8、KNN的K值得學(xué)習(xí)曲線
#======【TIME WARNING: 】======# score = [] for i in range(10):X_dr = PCA(23).fit_transform(X)once = cross_val_score(KNN(i+1),X_dr,y,cv=5).mean()score.append(once) plt.figure(figsize=[20,5]) plt.plot(range(10),score) plt.show()9、定下超參數(shù)后,模型效果如何,模型運行時間如何?
cross_val_score(KNN(4),X_dr,y,cv=5).mean() #=======【TIME WARNING: 3mins】======# %%timeit cross_val_score(KNN(4),X_dr,y,cv=5).mean()可以發(fā)現(xiàn),原本785列的特征被我們縮減到23列之后,用KNN跑出了目前位置這個數(shù)據(jù)集上最好的結(jié)果。再進(jìn)行更 細(xì)致的調(diào)整,我們也許可以將KNN的效果調(diào)整到98%以上。PCA為我們提供了無限的可能,終于不用再因為數(shù)據(jù)量 太龐大而被迫選擇更加復(fù)雜的模型了!
總結(jié)
以上是生活随笔為你收集整理的sklearn实战之降维算法PCA与SVD的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue 前端代码风格指南、代码规范
- 下一篇: 使用SpringBoot编写电脑商城项目