sklearn:四、降維算法——8.28~9.8


四、降維算法

  • 特征矩陣/DataFrame結(jié)構(gòu)永遠(yuǎn)只是一張表(就有行和列),其中行是樣本,列是特征。針對(duì)每一張表,維度指的是樣本的數(shù)量或特征的數(shù)量*,一般無(wú)特別說(shuō)明,指的都是特征的數(shù)量;
  • 對(duì)于圖像而言,維度就是圖像中特征向量的數(shù)量(也就是坐標(biāo)軸的數(shù)量);
  • 降維算法中的”降維“,指的是降低特征矩陣中特征的數(shù)量——>目的:讓算法運(yùn)算更快,效果更好;
  • 數(shù)據(jù)可視化:三維以上的看不懂,所以得降維之后才有助于理解;
  • sklearn中的降維算法

主成分分析中PCA和TruncatedSVD是混合在一起的;現(xiàn)在比較受歡迎的是高級(jí)矩陣算法

SVD和PCA都是通過(guò)分解特征矩陣來(lái)進(jìn)行降維

4.1 PCA與SVD

  • 在降維過(guò)程中,我們會(huì)減少特征的數(shù)量,這意味著刪除數(shù)據(jù),數(shù)據(jù)量變少——>模型可以獲取的信息會(huì)變少,模型的表現(xiàn)可能會(huì)因此受影響;
  • 目標(biāo):找到一個(gè)能夠即減少特征的數(shù)量,又保留大部分有效信息的方法——>創(chuàng)造出能夠代表原特征矩陣大部分信息的,特征更少的,新特征矩陣(將那些帶有重復(fù)信息的特征合并,并刪除那些帶無(wú)效信息的特征等等);
  • PCA使用的信息量衡量指標(biāo)樣本方差,又稱為可解釋性方差,方差越大,特征所帶的信息量越多:

Var代表一個(gè)特征的方差,n代表樣本量,xi代表一個(gè)特征中的每個(gè)樣本取值,xhat代表這一列樣本的均值。
n-1是因?yàn)榈昧说玫?strong>無(wú)偏估計(jì)


4.1.1 降維究竟是怎樣實(shí)現(xiàn)?

class sklearn.decomposition.PCA (n_components=None, copy=True, whiten=False, svd_solver=’auto’, tol=0.0,iterated_power=’auto’, random_state=None)

  • 降維例子

我們現(xiàn)在有一組簡(jiǎn)單的數(shù)據(jù),有特征x1和x2,三個(gè)樣本數(shù)據(jù)的坐標(biāo)點(diǎn)分別為(1,1),(2,2),(3,3)。那么其對(duì)應(yīng)方差就是:

每個(gè)特征的數(shù)據(jù)一模一樣,因此方差也都為1,數(shù)據(jù)的方差總和是2

  • 目標(biāo):只用一個(gè)特征向量來(lái)描述這組數(shù)據(jù),即將二維數(shù)據(jù)降為一維數(shù)據(jù),并且盡可能地保留信息量,即讓數(shù)據(jù)的總方差盡量靠近2;
  • 做法:把坐標(biāo)軸轉(zhuǎn)一下,然后得到了各個(gè)點(diǎn)對(duì)應(yīng)的新坐標(biāo),此時(shí)的x1均值為2√2,而方差為:

應(yīng)該是x1*這里打錯(cuò)了

x2*上的數(shù)值此時(shí)都變成了0,因此x2*明顯不帶有任何有效信息了(此時(shí)x2*的方差也為0了)那么他就可以刪掉了,這樣就使得表只剩下一列/一個(gè)特征,這樣一來(lái)就成功的降維了;

  • 步驟

在步驟3當(dāng)中,我們用來(lái)找出n個(gè)新特征向量,讓數(shù)據(jù)能夠被壓縮到少數(shù)特征上并且總信息量不損失太多的技術(shù)就是矩陣分解

  • PCA和SVD是兩種不同的降維算法,但他們都遵從上面的過(guò)程來(lái)實(shí)現(xiàn)降維,只是兩種算法中矩陣分解的方法不同信息量的衡量指標(biāo)不同罷了(PCA能干的事,SVD也能干,反之亦然)
    (1)PCA使用方差作為信息量的衡量指標(biāo),并且特征值分解來(lái)找出空間V。降維時(shí),它會(huì)通過(guò)一系列數(shù)學(xué)的神秘操作(比如說(shuō),產(chǎn)生協(xié)方差矩陣1/nXXT)將特征矩陣X分解為以下三個(gè)矩陣:

Q和Q-1是兩個(gè)輔助矩陣,而∑則是個(gè)對(duì)角矩陣,其中對(duì)角線上的元素就是方差

降維完成之后,PCA找到的每個(gè)新特征向量就叫做“主成分”,而被丟棄的特征向量被認(rèn)為信息量很少,這些信息很可能就是噪音;
(2)而SVD使用奇異值分解來(lái)找出空間V:

其中Σ也是一個(gè)對(duì)角矩陣,不過(guò)它對(duì)角線上的元素是奇異值,這也是SVD中用來(lái)衡量特征上的信息量的指標(biāo)。U和VT分別是左奇異矩陣和右奇異矩陣,也都是輔助矩陣


4.1.2 重要參數(shù)n_components

  • 含義:是我們降維后需要的維度,即降維后需要保留的特征數(shù)量,降維流程中第二步里需要確認(rèn)的k值,一般輸入[0, min(X.shape)]范圍中的整數(shù);
  • 確定方法:可以先從我們的降維目標(biāo)說(shuō)起:如果我們希望可視化一組數(shù)據(jù)來(lái)觀察數(shù)據(jù)分布,我們往往將數(shù)據(jù)降到三維以下,很多時(shí)候是二維,即n_components的取值為2;
  • 案例:高維數(shù)據(jù)可視化:
  1. 調(diào)用庫(kù)和模塊
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA

2.提取數(shù)據(jù)集

iris = load_iris()
y = iris.target
X = iris.data
#作為數(shù)組,X是幾維?
X.shape
#(150, 4) 
#作為數(shù)據(jù)表或特征矩陣,X是幾維?
import pandas as pd
pd.DataFrame(X)

說(shuō)明X是四維的

  1. 建模
#調(diào)用PCA
#實(shí)例化
pca = PCA(n_components=2) 
#擬合模型
pca = pca.fit(X) 
#獲取新矩陣
X_dr = pca.transform(X) 
X_dr
X_dr.shape
#(150, 2)
#也可以fit_transform一步到位
#X_dr = PCA(2).fit_transform(X)
  1. 可視化
#要將三種鳶尾花的數(shù)據(jù)分布顯示在二維平面坐標(biāo)系中,對(duì)應(yīng)的兩個(gè)坐標(biāo)(兩個(gè)特征向量)應(yīng)該是三種鳶尾花降維后的x1和x2,怎樣才能取出三種鳶尾花下不同的x1和x2呢?

#可以直接拿X_dr畫點(diǎn)圖,但是這樣不知道哪個(gè)點(diǎn)對(duì)應(yīng)哪種花
#所以要根據(jù)花的類別來(lái)把三種不同的花標(biāo)記出來(lái)

#這里是布爾索引,看出來(lái)了么?這里就是取出標(biāo)簽為0的花的第一個(gè)特征
X_dr[y == 0, 0] 

#要展示三中分類的分布,需要對(duì)三種鳶尾花分別繪圖
#可以寫成三行代碼,也可以寫成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 #設(shè)置點(diǎn)的透明度
                   ,c=colors[i]
                   ,label=iris.target_names[i]
                   )
plt.legend()
plt.title('PCA of IRIS dataset')
plt.show()

可以看出每種花都是挨在一起的(分簇的分布)并且每個(gè)簇之間的分布相對(duì)比較明顯,這種分布正式聚類模型擅長(zhǎng)的。也許versicolor和virginia這兩種花之間會(huì)有一些分類錯(cuò)誤,但setosa肯定不會(huì)被分錯(cuò)。KNN,隨機(jī)森林,神經(jīng)網(wǎng)絡(luò),樸素貝葉斯,Adaboost這些分類器在鳶尾花數(shù)據(jù)集上,未調(diào)整的時(shí)候都可以有95%上下的準(zhǔn)確率

  1. 探索降維后的數(shù)據(jù)
#屬性explained_variance_,查看降維后每個(gè)新特征向量上所帶的信息量大小(可解釋性方差的大?。?pca.explained_variance_
#array([4.22824171, 0.24267075])  說(shuō)明大多數(shù)信息都在第一個(gè)軸上

#屬性explained_variance_ratio,查看降維后每個(gè)新特征向量所占的信息量占原始數(shù)據(jù)總信息量的百分比
#又叫做可解釋方差貢獻(xiàn)率
pca.explained_variance_ratio_
#array([0.92461872, 0.05306648])
#大部分信息都被有效地集中在了第一個(gè)特征上

pca.explained_variance_ratio_.sum()
#0.977685206318795  因?yàn)榻稻S后的信息量一定有損失
  1. 選擇最好的n_components:累積可解釋方差貢獻(xiàn)率曲線
    當(dāng)參數(shù)n_components中不填寫任何值,則默認(rèn)返回min(X.shape)個(gè)特征,一般來(lái)說(shuō),樣本量都會(huì)大于特征數(shù)目——>什么都不填就相當(dāng)于轉(zhuǎn)換了新特征空間,但沒(méi)有減少特征的個(gè)數(shù)

可以使用這種輸入方式來(lái)畫出累計(jì)可解釋方差貢獻(xiàn)率曲線,以此選擇最好的n_components的整數(shù)取值;

  • 累積可解釋方差貢獻(xiàn)率曲線是一條以降維后保留的特征個(gè)數(shù)為橫坐標(biāo),降維后新特征矩陣捕捉到的可解釋方差貢獻(xiàn)率為縱坐標(biāo)的曲線——>能夠幫助我們決定n_components最好的取值:
import numpy as np
pca_line = PCA().fit(X)
pca_line.explained_variance_ratio_
#array([0.92461872, 0.05306648, 0.01710261, 0.00521218])
np.cumsum(pca_line.explained_variance_ratio_)
#array([0.92461872, 0.97768521, 0.99478782, 1.        ])  分別是前2/3/4個(gè)數(shù)值相加的結(jié)果

#畫圖
plt.plot([1,2,3,4],np.cumsum(pca_line.explained_variance_ratio_))
#這是為了限制坐標(biāo)軸顯示為整數(shù)
plt.xticks([1,2,3,4]) 
plt.xlabel("number of components after dimension reduction")
plt.ylabel("cumulative explained variance ratio")
plt.show()

在這里,2/3都是可以考慮的選擇。當(dāng)特征數(shù)很大時(shí),這個(gè)曲線就會(huì)比較平滑:我們就找在曲率變小之前的那一段來(lái)判斷特征個(gè)數(shù)

  • 最大似然估計(jì)自選超參數(shù):讓PCA用最大似然估計(jì)(maximum likelihoodestimation)自選超參數(shù)的方法,輸入“mle”作為n_components的參數(shù)輸入,就可以調(diào)用這種方法,但是計(jì)算量會(huì)很大:
pca_mle = PCA(n_components="mle")
pca_mle = pca_mle.fit(X)
X_mle = pca_mle.transform(X)

X_mle
#可以發(fā)現(xiàn),mle為我們自動(dòng)選擇了3個(gè)特征

pca_mle.explained_variance_ratio_.sum()
#得到了比設(shè)定2個(gè)特征時(shí)更高的信息含量,對(duì)于鳶尾花這個(gè)很小的數(shù)據(jù)集來(lái)說(shuō),3個(gè)特征對(duì)應(yīng)這么高的信息含量,并不需要去糾結(jié)于只保留2個(gè)特征,畢竟三個(gè)特征也可以可視化
#0.9947878161267247 (牛蛙牛蛙)
  • 按信息量占比選超參數(shù):輸入[0,1]之間的浮點(diǎn)數(shù),并且讓參數(shù)svd_solver =='full',表示希望降維后的總解釋性方差占比大于n_components指定的百分比,即是說(shuō),希望保留百分之多少的信息量:
pca_f = PCA(n_components=0.97,svd_solver="full")
pca_f = pca_f.fit(X)
X_f = pca_f.transform(X)
#自動(dòng)返回了一個(gè)二維的

pca_f.explained_variance_ratio_
#array([0.92461872, 0.05306648])

這種方法能夠讓我們知道:需要多少的信息量才能讓模型保持準(zhǔn)確度,可以在一開(kāi)始的時(shí)候拿來(lái)用,一般都是80~90%;


4.1.3 PCA中的SVD

(1) PCA中的SVD哪里來(lái)

SVD可以不計(jì)算協(xié)方差矩陣,直接找出一個(gè)新特征向量組成的n維空間,而這個(gè)n維空間就是奇異值分解后的右矩陣VT,它有著如下的性質(zhì):

k就是n_components,是我們降維后希望得到的維度。若X為(m,n)的特征矩陣,VT就是結(jié)構(gòu)為(n,n)的矩陣,取這個(gè)矩陣的前k行(進(jìn)行切片),即將V轉(zhuǎn)換為結(jié)構(gòu)為(k,n)的矩陣。而V(k,n)T與原特征矩陣X相乘,即可得到降維后的特征矩陣Xdr

這是說(shuō),奇異值分解可以不計(jì)算協(xié)方差矩陣等等結(jié)構(gòu)復(fù)雜計(jì)算冗長(zhǎng)的矩陣,就直接求出新特征空間和降維后的特征矩陣;
但是奇異值也挺難理解的,sklearn將降維流程拆成了兩部分:一部分計(jì)算特征空間V,由奇異值分解完成,另一部分映射數(shù)據(jù)和求解新特征矩陣,由主成分分析完成,實(shí)現(xiàn)了用SVD的性質(zhì)減少計(jì)算量,卻讓信息量的評(píng)估指標(biāo)是方差。具體流程如下:

在transform過(guò)程之后,fit中奇異值分解的結(jié)果除了V(k,n)以外,就會(huì)被舍棄,V(k,n)會(huì)被保存在屬性components_ 當(dāng)中,可以調(diào)用查看:

PCA(2).fit(X).components_
#array([[ 0.36138659, -0.08452251,  0.85667061,  0.3582892 ],
#       [ 0.65658877,  0.73016143, -0.17337266, -0.07548102]])
#返回新特征空間V(k,n)
PCA(2).fit(X).components_.shape
#(2, 4)

(2)重要參數(shù)svd_solver 與 random_state

參數(shù)svd_solver是在降維過(guò)程中,用來(lái)控制矩陣分解的一些細(xì)節(jié)的參數(shù)。有四種模式可選:"auto", "full", "arpack","randomized",默認(rèn)”auto":

  • auto::如果輸入數(shù)據(jù)的尺寸大于500x500且要提取的特征數(shù)小于數(shù)據(jù)最小維度min(X.shape)的80%,就啟用效率更高的”randomized“方法。否則,精確完整的SVD(完成分解后的U,Σ,V都會(huì)被完整轉(zhuǎn)置)將被計(jì)算,截?cái)鄬?huì)在矩陣被分解完成后有選擇地發(fā)生;
  • full:從scipy.linalg.svd中調(diào)用標(biāo)準(zhǔn)的LAPACK分解器來(lái)生成精確完整的SVD,適合數(shù)據(jù)量比較適中,計(jì)算時(shí)間充足的情況(因?yàn)橐傻木仃嚭艽螅傻木_完整的SVD的結(jié)構(gòu)為:
  • arpack:從scipy.sparse.linalg.svds調(diào)用ARPACK分解器來(lái)運(yùn)行截?cái)嗥娈愔捣纸?SVD truncated),分解時(shí)就將特征數(shù)量降到n_components中輸入的數(shù)值k,可以加快運(yùn)算速度,適合特征矩陣很大的時(shí)候,但一般用于特征矩陣為稀疏矩陣的情況,此過(guò)程包含一定的隨機(jī)性。截?cái)嗪蟮腟VD分解出的結(jié)構(gòu)為:
  • randomized:分解器會(huì)先生成多個(gè)隨機(jī)向量,然后一一去檢測(cè)這些隨機(jī)向量中是否有任何一個(gè)符合我們的分解需求,如果符合,就保留這個(gè)隨機(jī)向量,并基于這個(gè)隨機(jī)向量來(lái)構(gòu)建后續(xù)的向量空間。已經(jīng)被證實(shí)比f(wàn)ull好使,適合特征矩陣巨大,計(jì)算量龐大的情況;

參數(shù)random_state在參數(shù)svd_solver的值為"arpack" or "randomized"的時(shí)候生效,可以控制這兩種SVD模式中的隨機(jī)模式。通常我們就選用”auto“,不必對(duì)這個(gè)參數(shù)糾結(jié)太多。


(3) 重要屬性components

雖然要的是Xdr但是保存V(k,n)是為了后面把它可視化然后找出所提取的重要的信息;

PCA與特征選擇的區(qū)別:即特征選擇后的特征矩陣是可解讀的,而PCA降維后的特征矩陣式不可解讀的:PCA是將已存在的特征進(jìn)行壓縮,降維完畢后的特征不是原本的特征矩陣中的任何一個(gè)特征,而是通過(guò)某些方式組合起來(lái)的新特征;

  • 人臉識(shí)別中屬性components_的運(yùn)用[]
  1. 導(dǎo)入需要的庫(kù)和模塊
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
  1. 實(shí)例化數(shù)據(jù)集,探索數(shù)據(jù)
#實(shí)例化,這一步下數(shù)據(jù)可能要一會(huì)
faces = fetch_lfw_people(min_faces_per_person=60)
faces.images.shape
#(1348, 62, 47)
#怎樣理解這個(gè)數(shù)據(jù)的維度?
#嚴(yán)格來(lái)說(shuō),這個(gè)才是特征矩陣,雖然是三維的
#1348是圖像個(gè)數(shù),62/47是每個(gè)圖像的特征矩陣的行/列

#行是樣本
#列是樣本相關(guān)的特征
faces.data.shape
#(1348, 2914)
#換成特征矩陣之后,這個(gè)矩陣是什么樣?
X = faces.data

6247=2914,說(shuō)明這里的特征是由兩個(gè)相互垂直的特征向量構(gòu)成的;
雖然2914不能圖像化,但是62
47是可以的,代表的是總像素的數(shù)字

  1. 看看圖像什么樣?將原特征
#數(shù)據(jù)本身是圖像,和數(shù)據(jù)本身只是數(shù)字,使用的可視化方法不同

#創(chuàng)建畫布和子圖對(duì)象
#4,5代表畫4行,每行有5張圖;figsize代表畫布大小;subplot_kw代表
fig, axes = plt.subplots(4,5
                           ,figsize=(8,4)
                           ,subplot_kw = {"xticks":[],"yticks":[]} #不要顯示坐標(biāo)軸
                           )
#fig就是上面的畫布
fig

#每個(gè)畫布的對(duì)象
axes
#不難發(fā)現(xiàn),axes中的一個(gè)對(duì)象對(duì)應(yīng)fig中的一個(gè)空格
#我們希望,在每一個(gè)子圖對(duì)象中填充圖像(共20張圖),因此我們需要寫一個(gè)在子圖對(duì)象中遍歷的循環(huán)

axes.shape
#(4, 5)

#二維結(jié)構(gòu),可以有兩種循環(huán)方式,一種是使用索引,循環(huán)一次同時(shí)生成一列上的三個(gè)圖
#另一種是把數(shù)據(jù)拉成一維,循環(huán)一次只生成一個(gè)圖
#在這里,究竟使用哪一種循環(huán)方式,是要看我們要畫的圖的信息,儲(chǔ)存在一個(gè)怎樣的結(jié)構(gòu)里
#我們使用 子圖對(duì)象.imshow 來(lái)將圖像填充到空白畫布上
#而imshow要求的數(shù)據(jù)格式必須是一個(gè)(m,n)格式的矩陣,即每個(gè)數(shù)據(jù)都是一張單獨(dú)的圖
#因此我們需要遍歷的是faces.images,其結(jié)構(gòu)是(1277, 62, 47)
#要從一個(gè)數(shù)據(jù)集中取出24個(gè)圖,明顯是一次性的循環(huán)切片[i,:,:]來(lái)得便利
#因此我們要把a(bǔ)xes的結(jié)構(gòu)拉成一維來(lái)循環(huán)

axes[0][0].imshow(faces.images[0,:,:])
#<matplotlib.image.AxesImage at 0x25cea82f880>,實(shí)際上就已經(jīng)畫出一個(gè)人臉圖了

#降維成一維數(shù)組
axes.flat

#給每個(gè)對(duì)象加個(gè)索引
enumerate(axes.flat) 

#填充圖像,i就是0-19;ax就是每個(gè)畫圖對(duì)象
for i, ax in enumerate(axes.flat):
        ax.imshow(faces.images[i,:,:] 
                 ,cmap="gray" #選擇色彩的模式
                   )
#上面這個(gè)for要放到建畫布那里去
#https://matplotlib.org/tutorials/colors/colormaps.html
image.png
  1. 建模降維,提取新特征空間矩陣
#原本有2900維,我們現(xiàn)在來(lái)降到150維
pca = PCA(150).fit(X) 

V = pca.components_
V.shape
#(150, 2914)
  1. 將新特征空間矩陣可視化
fig, axes = plt.subplots(3,8,figsize=(8,4),subplot_kw = {"xticks":[],"yticks":[]})
#對(duì)V進(jìn)行循環(huán),把其中每個(gè)2914都變成62*47的結(jié)構(gòu),這樣就可以畫圖了
for i, ax in enumerate(axes.flat):
        ax.imshow(V[i,:].reshape(62,47),cmap="gray")

大抵還是能看出眼鼻嘴的,這說(shuō)明這仨是降維過(guò)程中所提取的主要特征信息


4.1.4 重要接口inverse_transform

  • 作用:可以將我們歸一化,標(biāo)準(zhǔn)化,甚至做過(guò)啞變量的特征矩陣還原回原始數(shù)據(jù)中的特征矩陣;

(1) 迷你案例:用人臉識(shí)別看PCA降維后的信息保存量

我們先調(diào)用一組人臉數(shù)據(jù)X(m,n),對(duì)人臉圖像進(jìn)行繪制,然后我們對(duì)人臉數(shù)據(jù)進(jìn)行降維得到X_dr,之后再使用inverse_transform(X_dr)返回一個(gè)X_inverse(m,n),并對(duì)這個(gè)新矩陣中的人臉圖像也進(jìn)行繪制。如果PCA的降維過(guò)程是可逆的,我們應(yīng)當(dāng)期待X(m,n)和X_inverse(m,n)返回一模一樣的圖像,即攜帶一模一樣的信息

  1. 導(dǎo)入需要的庫(kù)和模塊(與2.3.3節(jié)中步驟一致)
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np
  1. 導(dǎo)入數(shù)據(jù),探索數(shù)據(jù)(與2.3.3節(jié)中步驟一致)
faces = fetch_lfw_people(min_faces_per_person=60)
faces.images.shape
#怎樣理解這個(gè)數(shù)據(jù)的維度?
faces.data.shape
#換成特征矩陣之后,這個(gè)矩陣是什么樣?
X = faces.dat
  1. 建模降維,獲取降維后的特征矩陣X_dr
#實(shí)例化
pca = PCA(150)
#擬合+提取結(jié)果
X_dr = pca.fit_transform(X)
X_dr.shape
#(1348, 150)
  1. 將降維后矩陣用inverse_transform返回原空間
#希望降維后的X_inverse和原來(lái)的X是一樣的;如果相同就說(shuō)明inverse_transform完成了降維的逆轉(zhuǎn)
X_inverse = pca.inverse_transform(X_dr)
X_inverse.shape
(1348, 2914)
  1. 將特征矩陣X和X_inverse可視化
fig, ax = plt.subplots(2,10,figsize=(10,2.5)
                         ,subplot_kw={"xticks":[],"yticks":[]}
                         )
#和2.3.3節(jié)中的案例一樣,我們需要對(duì)子圖對(duì)象進(jìn)行遍歷的循環(huán),來(lái)將圖像填入子圖中
#那在這里,我們使用怎樣的循環(huán)?
#現(xiàn)在我們的ax中是2行10列,第一行是原數(shù)據(jù),第二行是inverse_transform后返回的數(shù)據(jù)
#所以我們需要同時(shí)循環(huán)兩份數(shù)據(jù),即一次循環(huán)畫一列上的兩張圖,而不是把a(bǔ)x拉平
for i in range(10):
        ax[0,i].imshow(faces.images[i,:,:],cmap="binary_r")
        ax[1,i].imshow(X_inverse[i].reshape(62,47),cmap="binary_r")

可以看出下面的圖比原數(shù)據(jù)要模糊,說(shuō)明降維刪除的信息無(wú)法復(fù)原
——>inverse_transform并沒(méi)有實(shí)現(xiàn)數(shù)據(jù)的完全逆轉(zhuǎn)
——>將為不可逆

Inverse_transform的功能是基于X_dr中的數(shù)據(jù)進(jìn)行升維,將數(shù)據(jù)重新映射到原數(shù)據(jù)所在的特征空間中,而并非恢復(fù)所有原有的數(shù)據(jù)。但是也說(shuō)明原有數(shù)據(jù)在經(jīng)過(guò)降維后仍然能夠保留大部分信息;


(2) 迷你案例:用PCA做噪音過(guò)濾

降維的目的之一就是希望拋棄掉對(duì)模型帶來(lái)負(fù)面影響的特征,所以相比噪音,有效的特征所帶的信息應(yīng)該不會(huì)在PCA過(guò)程中被大量拋棄,inverse_transform說(shuō)能夠?qū)崿F(xiàn)”保證維度,但去掉方差很小特征所帶的信息“——>噪音過(guò)濾

  1. 導(dǎo)入需要的庫(kù)和模塊
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import numpy as np

2.導(dǎo)入數(shù)據(jù),探索數(shù)據(jù)

digits = load_digits()
digits.data.shape
#(1797, 64)
#該數(shù)據(jù)集很干凈,沒(méi)有噪音

#set是個(gè)去重函數(shù)
set(digits.target)
#{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

3.定義畫圖函數(shù)

def plot_digits(data):
        #data的結(jié)構(gòu)必須是m*n,且n要能夠被分為(8,8)這樣的結(jié)構(gòu)
        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)
  1. 為數(shù)據(jù)加上噪音
import numpy as np
#對(duì)于圖像,使用正態(tài)分布的隨機(jī)抽取函數(shù)
rng = np.random.RandomState(42) 

#在指定的數(shù)據(jù)集中,隨機(jī)抽取服從正態(tài)分布的數(shù)據(jù)
#兩個(gè)參數(shù),分別是指定的數(shù)據(jù)集,和抽取出來(lái)的正太分布的方差
noisy = rng.normal(digits.data,2)

plot_digits(noisy)
  1. 降維
pca = PCA(0.5).fit(noisy)
X_dr = pca.transform(noisy)
X_dr.shape
#(1797, 6)
  1. 逆轉(zhuǎn)降維結(jié)果,實(shí)現(xiàn)降噪
without_noise = pca.inverse_transform(X_dr)
plot_digits(without_noise)

可以看到雖然還有一些噪音,但是比起之前的版本已經(jīng)好很多了;


4.1.5 重要接口,參數(shù)和屬性總結(jié)

  • 重要參數(shù):n_components(高維數(shù)據(jù)可視化),svd_solver(解釋了SVD相關(guān)參數(shù)),random_state(隨機(jī)矩陣分解模式);
  • 重要屬性:components_(調(diào)用V(k,n), explained_variance_(衡量降維后每個(gè)特征的信息量)以及explained_variance_ratio_(幫助選擇最佳的n_components的取值);
  • 重要接口:fit,transform(調(diào)取結(jié)果),fit_transform(前兩個(gè)的結(jié)合),inverse_transform;

4.2 案例:PCA對(duì)手寫數(shù)字?jǐn)?shù)據(jù)集的降維

我們使用了各種技術(shù)對(duì)手寫數(shù)據(jù)集進(jìn)行特征選擇,最后使用嵌入法SelectFromModel選出了324個(gè)特征,將隨機(jī)森林的效果也調(diào)到了96%以上。但是,因?yàn)閿?shù)據(jù)量依然巨大,還是有300多個(gè)特征。今天,我們就來(lái)試著用PCA處理一下這個(gè)數(shù)據(jù),看看效果如何:

  1. 導(dǎo)入需要的模塊和庫(kù)
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 np
  1. 導(dǎo)入數(shù)據(jù),探索數(shù)據(jù)
data = pd.read_csv(r"E:\jupyter\sklearn\4 Decomposition\digit recognizor.csv")
  
#X是所有行數(shù)據(jù)第1列開(kāi)始取,直到最后
X = data.iloc[:,1:]
#y是所有行的第0列
y = data.iloc[:,0] 

X.shape
#(42000, 784)
  1. 畫累計(jì)方差貢獻(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()

0-200之間必然有個(gè)值是想要的

  1. 降維后維度的學(xué)習(xí)曲線,繼續(xù)縮小最佳維度的范圍
#======【TIME WARNING:2mins 30s】======#
score = []
#就是之前調(diào)參的原理
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()
  1. 細(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()
image.png

可得出:21是最好的數(shù)字,說(shuō)明此時(shí)在隨機(jī)森林中有著最好的取值

  1. 導(dǎo)入找出的最佳維度進(jìn)行降維,查看模型效果
X_dr = PCA(21).fit_transform(X)

cross_val_score(RFC(n_estimators=10,random_state=0),X_dr,y,cv=5).mean()
#0.9180952380952381

#======【TIME WARNING:1mins 30s】======#
cross_val_score(RFC(n_estimators=100,random_state=0),X_dr,y,cv=5).mean()
#0.9434047619047619
  1. 突發(fā)奇想,特征數(shù)量已經(jīng)不足原來(lái)的3%,換模型怎么樣?
from sklearn.neighbors import KNeighborsClassifier as KNN
cross_val_score(KNN(),X_dr,y,cv=5).mean()

之所以能用KNN,是因?yàn)槲覀円呀?jīng)通過(guò)降維來(lái)去掉了很多特征,從而加快了KNN的運(yùn)行速度

  1. 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()
  1. 定下超參數(shù)后,模型效果如何,模型運(yùn)行時(shí)間如何?
cross_val_score(KNN(3),X_dr,y,cv=5).mean()
#0.9680714285714286

#下面的代碼要另起一個(gè)格子
%%timeit
#表示對(duì)這個(gè)塊中的所有代碼都執(zhí)行一遍,求其運(yùn)行時(shí)間

#=======【TIME WARNING: 3mins】======#
cross_val_score(KNN(3),X_dr,y,cv=5).mean()
#1.5 s ± 47.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

可以發(fā)現(xiàn),原本785列的特征被我們縮減到21列之后,用KNN跑出了目前位置這個(gè)數(shù)據(jù)集上最好的結(jié)果。再進(jìn)行更細(xì)致的調(diào)整,我們也許可以將KNN的效果調(diào)整到96%以上。

PCA拿來(lái)減少特征數(shù),從而提高KNN的運(yùn)行速度

——>能用PCA一般就不用特征選擇了,不能用PCA才去選擇

拖更了,得虧還知道回來(lái)

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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