文章目錄
降維算法 PCA
一、數據維度概念
二、skLearn中的降維算法
三、PCA與SVD
① 降維的實現步驟解析
② 重要參數n_components
• 累積可解釋方差貢獻率曲線
• 最大似然估計自選超參數
• 按信息量占比選超參數
③ 重要參數 svd_solver
④ 重要屬性 components_
• 迷你案例:人臉識別應用
可視化faces.images數據集
PCA降維處理faces.data數據集
⑤ 重要接口inverse_transform
• 迷你案例:用人臉識別看PCA降維后的信息保存量
• 迷你案例:PCA 手寫數字數據集噪音過濾
⑥ 重要接口、參數、屬性總結
降維算法 PCA
一、數據維度概念
對於數組和Series來說,維度就是功能shape返回的結果,shape中返回了幾個數字,就是幾維。索引以外的數據,不分行列的叫一維(此時shape返回唯一的維度上的數據個數),有行列之分叫二維(shape返回行x列),也稱為表。一張表最多二維,復數的表構成了更高的維度。當一個數組中存在2張3行4列的表時,shape返回的是(更高維,行,列)。當數組中存在2組2張3行4列的表時,數據就是4維,shape返回(2,2,3,4)。
數組中的每一張表,都可以是一個特征矩陣或一個DataFrame,這些結構永遠只有一張表,所以一定有行列,其中行是樣本,列是特征。針對每一張表,維度指的是樣本的數量或特征的數量,一般無特別說明,指的都是特征的數量。除了索引之外,一個特征是一維,兩個特征是二維,n個特征是n維。
對圖像來說,維度就是圖像中特征向量的數量。特征向量可以理解為是坐標軸,一個特征向量定義一條直線,是一維,兩個相互垂直的特征向量定義一個平面,即一個直角坐標系,就是二維,三個相互垂直的特征向量定義一個空間,即一個立體直角坐標系,就是三維。三個以上的特征向量相互垂直,定義人眼無法看見,也無法想象的高維空間。
降維算法中的”降維“,指的是降低特征矩陣中特征的數量。降維的目的是為了讓算法運算更快,效果更好,但其實還有另一種需求:數據可視化。從上面的圖我們其實可以看得出,圖像和特征矩陣的維度是可以相互對應的,即一個特征對應一個特征向量,對應一條坐標軸。所以,三維及以下的特征矩陣,是可以被可視化的,這可以幫助我們很快地理解數據的分布,而三維以上特征矩陣的則不能被可視化,數據的性質也就比較難理解。
返回頂部
二、skLearn中的降維算法
sklearn中降維算法都被包括在模塊decomposition中,這個模塊本質是一個矩陣分解模塊。
返回頂部
三、PCA與SVD
在降維過程中,我們會減少特征的數量,這意味着刪除數據,數據量變少則表示模型可以獲取的信息會變少,模型的表現可能會因此受影響。同時,在高維數據中,必然有一些特征是不帶有有效的信息的(比如噪音),或者有一些特征帶有的信息和其他一些特征是重復的(比如一些特征可能會線性相關)。我們希望能夠找出一種辦法來幫助我們衡量特征上所帶的信息量,讓我們在降維的過程中,能夠即減少特征的數量,又保留大部分有效信息——將那些帶有重復信息的特征合並,並刪除那些帶無效信息的特征等等——逐漸創造出能夠代表原特征矩陣大部分信息的,特征更少的,新特征矩陣。
之前學習過一種重要的特征選擇方法:方差過濾。如果一個特征的方差很小,則意味着這個特征上很可能有大量取值都相同(比如90%都是1,只有10%是0,甚至100%是1),那這一個特征的取值對樣本而言就沒有區分度,這種特征就不帶有有效信息。從方差的這種應用就可以推斷出,如果一個特征的方差很大,則說明這個特征上帶有大量的信息。因此,在降維中,PCA使用的信息量衡量指標,就是樣本方差,又稱可解釋性方差,方差越大,特征所帶的信息量越多。
Var代表一個特征的方差,n代表樣本量,xi代表一個特征中的每個樣本取值,xhat代表這一列樣本的均值。
計算中,為什么樣本方差里面要除以(n-1)而不是n?
① 降維的實現步驟解析
class sklearn.decomposition.PCA (n_components=None, copy=True, whiten=False,
svd_solver=’auto’, tol=0.0,
iterated_power=’auto’, random_state=None)
PCA作為矩陣分解算法的核心算法,其實沒有太多參數,但是每個參數的意義和運用都很難,因為幾乎每個參數都涉及到高深的數學原理。為了參數的運用和意義變得明朗,我們來看一組簡單的二維數據的降維:
我們現在有一組簡單的數據,有特征x1和x2,三個樣本數據的坐標點分別為(1,1),(2,2),(3,3)。我們可以讓x1和x2分別作為兩個特征向量,很輕松地用一個二維平面來描述這組數據。這組數據現在每個特征的均值都為2,方差則等於:
每個特征的數據一模一樣,因此方差也都為1,數據的方差總和是2。
現在我們的目標是:只用一個特征向量來描述這組數據,即將二維數據降為一維數據,並且盡可能地保留信息量,即讓數據的總方差盡量靠近2。於是,我們將原本的直角坐標系逆時針旋轉45°,形成了新的特征向量x1'和 x2'組成的新平面,在這個新平面中,三個樣本數據的坐標點可以表示為 可以注意到,x2'上的數值此時都變成了0,因此x2'明顯不帶有任何有效信息了(此時x2'的方差也為0了)。此時,x2'特征上的數據均值是
,而方差則可表示成:
此時,我們根據信息含量的排序,取信息含量最大的一個特征,因為我們想要的是一維數據。所以我們可以將x2'刪除,同時也刪除圖中的x2'特征向量,剩下的x1'就代表了曾經需要兩個特征來代表的三個樣本點。通過旋轉原有特征向量組成的坐標軸來找到新特征向量和新坐標平面,我們將三個樣本點的信息壓縮到了一條直線上,實現了二維變一維,並且盡量保留原始數據的信息。一個成功的降維,就實現了。
在步驟3當中,我們用來找出n個新特征向量,讓數據能夠被壓縮到少數特征上並且總信息量不損失太多的技術就是矩陣分解。PCA和SVD是兩種不同的降維算法,但他們都遵從上面的過程來實現降維,只是兩種算法中矩陣分解的方法不同,信息量的衡量指標不同罷了。
在數學原理中,無論是PCA和SVD都需要遍歷所有的特征和樣本來計算信息量指標。並且在矩陣分解的過程之中,會產生比原來的特征矩陣更大的矩陣,比如原數據的結構是(m,n),在矩陣分解中為了找出最佳新特征空間V,可能需要產生(n,n),(m,m)大小的矩陣,還需要產生協方差矩陣去計算更多的信息,所以降維算法過程計算量大,有時會很緩慢。
返回頂部
② 重要參數n_components
n_components是我們降維后需要的維度,即降維后需要保留的特征數量,降維流程中第二步里需要確認的k值,一般輸入[0, min(X.shape)]范圍中的整數。一說到K,大家可能都會想到,類似於KNN中的K和隨機森林中的n_estimators,這是一個需要我們人為去確認的超參數,並且我們設定的數字會影響到模型的表現。如果留下的特征太多,就達不到降維的效果,如果留下的特征太少,那新特征向量可能無法容納原始數據集中的大部分信息,因此,n_components既不能太大也不能太小。
可以先從我們的降維目標說起:如果我們希望可視化一組數據來觀察數據分布,我們往往將數據降到三維以下,很多時候是二維,即n_components的取值為2。
# 導庫
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
# 提取數據集
iris = load_iris()
x = pd.DataFrame(iris.data) # 二維數組 --- 四維特征矩陣
y = iris.target
# 訓練模型獲取降維結果
result = PCA(n_components=2).fit_transform(x)
# 可視化
plt.figure(figsize=(10,6))
plt.scatter(result[y==0,0],result[y==0,1],color='red',label=iris.target_names[0])
plt.scatter(result[y==1,0],result[y==1,1],color='yellow',label=iris.target_names[1])
plt.scatter(result[y==2,0],result[y==2,1],color='blue',label=iris.target_names[2])
plt.legend()
plt.title("PCA of IRIS Dataset",color="white")
plt.tick_params(axis="x",colors="white")
plt.tick_params(axis="y",colors="white")
plt.show(
鳶尾花的分布被展現在我們眼前了,明顯這是一個分簇的分布,並且每個簇之間的分布相對比較明顯,也許versicolor和virginia這兩種花之間會有一些分類錯誤,但setosa肯定不會被分錯。這樣的數據很容易分類,可以遇見,KNN,隨機森林,神經網絡,朴素貝葉斯,Adaboost這些分類器在鳶尾花數據集上,未調整的時候都可以有
95%上下的准確率。
探索降維后的數據:
# 探索降維后的數據
pca = PCA(n_components=2).fit(x)
#屬性explained_variance,查看降維后每個新特征向量上所帶的信息量大小(可解釋性方差的大小)
explained = pca.explained_variance_
print("降維后每個新特征向量上所帶的信息量大小:\n",explained)
#屬性explained_variance_ratio,查看降維后每個新特征向量所占的信息量占原始數據總信息量的百分比
#又叫做可解釋方差貢獻率
explained_ratio = pca.explained_variance_ratio_
print("降維后每個新特征向量所占的信息量占原始數據總信息量的百分比:\n",explained_ratio)
降維后每個新特征向量上所帶的信息量大小:
[4.22824171 0.24267075]
降維后每個新特征向量所占的信息量占原始數據總信息量的百分比:
[0.92461872 0.05306648]
返回頂部
• 累積可解釋方差貢獻率曲線
當參數n_components中不填寫任何值,則默認返回min(X.shape)個特征,一般來說,樣本量都會大於特征數目,所以什么都不填就相當於轉換了新特征空間,但沒有減少特征的個數。一般來說,不會使用這種輸入方式。但我們卻可以使用這種輸入方式來畫出累計可解釋方差貢獻率曲線,以此選擇最好的n_components的整數取值。
# n_components采用默認值,選取min(x.shape)
pca = PCA().fit(x)
explained_ratio = pca.explained_variance_ratio_
print("降維后每個新特征向量所占的信息量占原始數據總信息量的百分比:\n",explained_ratio)
降維后每個新特征向量所占的信息量占原始數據總信息量的百分比:
[0.92461872 0.05306648 0.01710261 0.00521218]
累積可解釋方差貢獻率曲線是一條以降維后保留的特征個數為橫坐標,降維后新特征矩陣捕捉到的可解釋方差貢獻率為縱坐標的曲線,能夠幫助我們決定n_components最好的取值。
# 使用np.cumsum()對可解釋方差貢獻率進行累加
np.cumsum(explained_ratio)
array([0.92461872, 0.97768521, 0.99478782, 1. ])
可視化:
# 可視化累計可解釋方差貢獻率曲線
pca_line = PCA().fit(x)
plt.plot([1,2,3,4],np.cumsum(pca_line.explained_variance_ratio_))
plt.xticks([1,2,3,4])
plt.xlabel("number of components after dimension reduction",color="white")
plt.ylabel("cumulative explained variance",color="white")
plt.tick_params(axis="x",colors="white")
plt.tick_params(axis="y",colors="white")
plt.show()
回頂部
• 最大似然估計自選超參數
除了輸入整數,n_components還有哪些選擇呢?之前我們提到過,矩陣分解的理論發展在業界獨樹一幟,勤奮智慧的數學大神Minka, T.P.在麻省理工學院媒體實驗室做研究時找出了讓PCA用最大似然估計(maximum likelihood estimation)自選超參數的方法,輸入“mle”作為n_components的參數輸入,就可以調用這種方法 。
pca_mle = PCA(n_components="mle").fit(x)
result = pca_mle.transform(x)
print("降維后的數據形狀是:\n",result.shape)
print("累計可解釋方差貢獻率為:\n",pca_mle.explained_variance_ratio_.sum())
降維后的數據形狀是:
(150, 3)
累計可解釋方差貢獻率為:
0.9947878161267246
通過結果可以發現,利用最大似然估計自選的超參數值為3,再結合累計可解釋方差貢獻率曲線來看,在n_components=3的時候,三個特征所包含的整體信息量較為可觀。
返回頂部
• 按信息量占比選超參數
輸入[0,1]之間的浮點數,並且讓參數svd_solver = "full',表示希望降維后的總解釋性方差占比大於n_components指定的百分比,即是說,希望保留百分之多少的信息量。比如說,如果我們希望保留97%的信息量,就可以輸入n_components = 0.97,PCA會自動選出能夠讓保留的信息量超過97%的特征數量。
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_
array([0.92461872, 0.05306648])
返回頂部
③ 重要參數 svd_solver
細心的小伙伴可能注意到了,svd_solver是奇異值分解器的意思,為什么PCA算法下面會有有關奇異值分解的參數?不是兩種算法么?
我們之前曾經提到過,PCA和SVD涉及了大量的矩陣計算,兩者都是運算量很大的模型,但其實,SVD有一種驚人的數學性質,即是它可以跳過數學神秘的宇宙,不計算協方差矩陣,直接找出一個新特征向量組成的n維空間,而這個n維空間就是奇異值分解后的右矩陣 (所以一開始在講解降維過程時,我們說”生成新特征向量組成的空間V",並非巧合,而是特指奇異值分解中的矩陣
)。
右奇異矩陣 有着如下性質:
k就是n_components,是我們降維后希望得到的維度。若X為(m,n)的特征矩陣, (k,n)就是結構為(n,n)的矩陣,取這個矩陣的前k行(進行切片),即將V轉換為結構為(k,n)的矩陣。而
與原特征矩陣X相乘,即可得到降維后的特征矩陣X_dr。這是說,奇異值分解可以不計算協方差矩陣等等結構復雜計算冗長的矩陣,就直接求出新特征空間和降維后的特征矩陣。
簡而言之,SVD在矩陣分解中的過程比PCA簡單快速,雖然兩個算法都走一樣的分解流程,但SVD可以作弊耍賴。但是遺憾的是,SVD的信息量衡量指標比較復雜,要理解”奇異值“遠不如理解”方差“來得容易,因此,sklearn將降維流程拆成了兩部分:一部分是計算特征空間V,由奇異值分解完成,另一部分是映射數據和求解新特征矩陣,由主成分分析完成,實現了用SVD的性質減少計算量,卻讓信息量的評估指標是方差,具體流程如下圖:
但在 sklearn中,矩陣U和Σ雖然會被計算出來(同樣也是一種比起PCA來說簡化非常多的數學過程,不產生協方差矩陣),但完全不會被用到,也無法調取查看或者使用,因此我們可以認為,u和在fit過后就被遺棄了。奇異值分解追求的僅僅是V,只要有了V,就可以計算出降維后的特征矩陣。在 transform過程之后,fit中奇異值分解的結果除了V(kn)以外,就會被舍棄,而v(n)會被保存在屬性components_當中,可以調用查看。
重要參數 svd_solver 的取值:
參數svd_solver是在降維過程中,用來控制矩陣分解的一些細節的參數。有四種模式可選:"auto","ful","arpack","randomized",默認"auto"。
auto:基於x.shape和n_components的默認策略來選擇分解器:如果輸入數據的尺寸大於500×500且要提取的特征數小於數據最小維度min( shape)的80%,就啟用效率更高的randomized方法。否則,精確完整的SVD將被計算,截斷將會在矩陣被分解完成后有選擇地發生.
full:從 scipy. linalg.svd中調用 LAPACK標准的分解器來生成精確完整的SVD,適合數據量比較適中,計算時間充足的情況,生成的精確完整的SVD的結構為:
arpack:從 scipy. sparse. linalg.svds調 ARPACK用分解器來運行截斷奇異值分解(SVD truncated),分解時就將特征數量降到n_components中輸入的數值k,可以加快運算速度,適合特征矩陣很大的時候,但一般用於特征矩陣為稀疏矩陣的情況,此過程包含一定的隨機性。截斷后的SVD分解出的結構為:
randomized,通過 Halko等人的隨機方法進行隨機SVD。在"full"方法中,分解器會根據原始數據和輸入的n_components值去計算和尋找符合需求的新特征向量,但是在"randomized"方法中,分解器會先生成多個隨機向量,然后——去檢測這些隨機向量中是否有任何一個符合我們的分解需求,如果符合,就保留這個隨機向量,並基於這個隨機向量來構建后續的向量空間。這個方法已經被 Halko等人證明,比"full"模式下計算快很多,並且還能夠保證模型運行效果。適合特征矩陣巨大,計算量龐大的情況。
而參數 random_state在參數svd_solver的值為"arpack“or”randomized"的時候生效可以控制這兩種SVD模式中的隨機模式。通常我們就選用auto。
返回頂部
④ 重要屬性 components_
現在我們了解了,V(k,n)是新特征空間,是我們要將原始數據進行映射的那些新特征向量組成的矩陣。我們用它來計算新的特征矩陣,但我們希望獲取的畢竟是X_dr,為什么我們要把V(k,n)這個矩陣保存在n_components這個屬性當中來讓大家調取查看呢?
我們之前談到過PCA與特征選擇的區別,即特征選擇后的特征矩陣是可解讀的,而PCA降維后的特征矩陣式不可解讀的:PCA是將已存在的特征進行壓縮,降維完畢后的特征不是原本的特征矩陣中的任何一個特征,而是通過某些方式組合起來的新特征。通常來說,在新的特征矩陣生成之前,我們無法知曉PCA都建立了怎樣的新特征向量,特征矩陣生成之后也不具有可讀性,我們無法判斷新特征矩陣的特征是從原數據中的什么特征組合而來,新特征然帶有原始數據的信息,卻已經不是原數據上代表着的含義了。
但是其實,在矩陣分解時,PCA是有目標的:在原有特征的基礎上,找出能夠讓信息盡量聚集的新特征向量。在sklearn使用的PCA和SVD聯合的降維方法中,這些新特征向量組成的新特征空間其實就是V(k,n)。當V(k,n)是數字時,我們無法判斷V(k,n)和原有的特征究竟有着怎樣千絲萬縷的數學聯系。但是,如果原特征矩陣是圖像,V(k,n)這個空間矩陣也可以被可視化的話,我們就可以通過兩張圖來比較,就可以看出新特征空間究竟從原始數據里提取了什么重要的信息。
• 迷你案例:人臉識別應用
# 導庫
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
from matplotlib import pyplot as plt
import numpy as np
# 加載數據集
# 在數據集中每個人取出60張面部照片
faces = fetch_lfw_people(min_faces_per_person=60)
{'data': array([[138. , 135.66667 , 127.666664 , ..., 1.6666666 ,
1.6666666 , 0.33333334],
[ 71.333336 , 56. , 67.666664 , ..., 247.66667 ,
243. , 238.33333 ],
[ 84.333336 , 97.333336 , 72.333336 , ..., 114. ,
194.33333 , 241. ],
...,
[ 29.333334 , 29. , 29.333334 , ..., 145. ,
147. , 141.66667 ],
[ 49.333332 , 55.666668 , 76.666664 , ..., 186.33333 ,
176.33333 , 161. ],
[ 31. , 26.333334 , 28. , ..., 34. ,
42. , 69.666664 ]], dtype=float32),
'images': array([[[138. , 135.66667 , 127.666664 , ..., 69. ,
68.333336 , 67.333336 ],
[146. , 139.33333 , 125. , ..., 68.333336 ,
67.666664 , 67.333336 ],
[150. , 138.33333 , 124.333336 , ..., 68.333336 ,
67.666664 , 66.666664 ],
...,
............................
...,
[ 44.666668 , 42.666668 , 44.666668 , ..., 22.333334 ,
25.333334 , 46.333332 ],
[ 42.333332 , 42.333332 , 45. , ..., 25.333334 ,
32.666668 , 49.666668 ],
[ 46. , 49.333332 , 51.666668 , ..., 34. ,
42. , 69.666664 ]]], dtype=float32),
'target': array([1, 3, 3, ..., 7, 3, 5], dtype=int64),
'target_names': array(['Ariel Sharon', 'Colin Powell', 'Donald Rumsfeld', 'George W Bush',
'Gerhard Schroeder', 'Hugo Chavez', 'Junichiro Koizumi',
'Tony Blair'], dtype='<U17'),
.........................
從數據集中可以看出,包含了七個人的面部圖像信息data以及images。
faces.images.shape
(1348, 62, 47)
# 1348 是矩陣中圖像的個數
# 62 是每個圖像的特征矩陣的行數
# 47 是每個圖像的特征矩陣的列數
返回頂部
可視化faces.images數據集
我們通過繪制子圖的形式先展示出數據的基本樣式,繪制一幅包含有20個子圖的圖片,展示出每張圖片的信息。
fig,axes = plt.subplots(4,5 # 總共的子圖數:行、列
,figsize=(20,10) # 總圖的大小
,subplot_kw = {"xticks":[],"yticks":[]} # 不顯示每張子圖的坐標
)
axes[0][0].imshow(faces.images[0,:,:])
通過遍歷展示前20條人臉數據:
通過imshow()中的cmap參數可以控制生成圖片的顏色。Matplotlib顏色選取網站:https://matplotlib.org/stable/tutorials/colors/colormaps.html
返回頂部
PCA降維處理faces.data數據集
x = faces.data # 提取二維數據
pca = PCA(150).fit(x) # 實例化PCA降維
v = pca.components_
print("PCA降維后的新特征矩陣維度為:\n",v.shape)
PCA降維后的新特征矩陣維度為:
(150, 2914)
可視化降維后的數據:
由於降維只改變了數據的特征維度,基本的結構沒有改變,所以每張圖片的信息依然可以拆解為62x47的特征矩陣進行可視化。
fig,axes = plt.subplots(3,8 # 總共的子圖數:行、列
,figsize=(20,10) # 總圖的大小
,subplot_kw = {"xticks":[],"yticks":[]} # 不顯示每張子圖的坐標
)
k = 0
for i in range(3):
for j in range(8):
axes[i][j].imshow(v[k,:].reshape(62,47),cmap="gray")
k=k+1
這張圖稍稍有一些恐怖,但可以看出,比起降維前的數據,新特征空間可視化后的人臉非常模糊,這是因為原始數據還沒有被映射到特征空間中。但是可以看出整體比較亮的圖片,獲取的信息較多,整體比較暗的圖片,卻只能看見黑漆漆的一塊。在比較亮的圖片中,眼睛,鼻子,嘴巴,都相對清晰,臉的輪廓,頭發之類的比較模糊。
這說明,新特征空間里的特征向量們,大部分是"五官"和"亮度"相關的向量,所以新特征向量上的信息肯定大部分是由原數據中和"五官"和"亮度"相關的特征中提取出來的。到這里,我們通過可視化新特征空間V,解釋了一部分降維后的特征:雖然顯示出來的數字看着不知所雲,但畫出來的圖表示,這些特征是和"五官"以及"亮度"有關的。這也再次證明了,PCA能夠將原始數據集中重要的數據進行聚集。
返回頂部
⑤ 重要接口inverse_transform
在之前的特征工程中,我們學到了神奇的接口 inverse_transform,可以將我們歸一化,標准化,啞變量的特征矩陣還原回原始數據中的特征矩陣。這幾乎在向我們暗示,任何有 inverse_transform接口的過程都是可逆的。PCA應該也是如此。在 sklearn中,我們通過讓原特征矩陣右乘新特征空間矩陣X_dr,那理論上來說,讓新特征矩陣X_dr右乘V(k,n)的逆矩陣 V ( k , n ) − 1 V_{(k,n)}^{-1} V
(k,n)
−1
就可以將新特征X_dr還原為原本的特征矩陣X。
• 迷你案例:用人臉識別看PCA降維后的信息保存量
人臉識別是最容易的,用來探索 inverse_ transform功能的數據。我們先調用一組人臉數據X(m,n),對人臉圖像進行繪制,然后我們對人臉數據進行降維得到x_dr,之后再使用inverse_transform(x_dr)返回一個inverse(m,n)並對這個新矩陣中的人臉圖像也進行繪制。如果PCA的降維過程是可逆的,我們應當期待X(m,n)和inverse(m,n)返回一模一樣的圖像,即攜帶一模一樣的信息。
fig,axes = plt.subplots(2,10
,figsize=(20,5)
,subplot_kw={"xticks":[],"yticks":[]}
)
for j in range(10):
axes[0,j].imshow(faces.images[j,:,:],cmap="binary_r") # 原始數據
axes[1,j].imshow(x_inverse[j].reshape(62,47),cmap="binary_r") # 降維逆轉數據
可以明顯看出,這兩組數據可視化后,由降維后再通過 inverse_transform轉換回原維度的數據畫出的圖像和原數據畫的圖像大致相似,但原數據的圖像明顯更加清晰。這說明:inverse_transform並沒有實現數據的完全逆轉。
這是因為,在降維的時候,部分信息已經被舍棄了,x_dr中往往不會包含原數據100%的信息,所以在逆轉的時候,即便維度升高,原數據中已經被舍棄的信息也不可能再回來了。所以,降維不是完全可逆的。Inverse_transform的功能,是基於x_dr中的數據進行升維,將數據重新映射到原數據所在的特征空間中,而並非恢復所有原有的數據。但同時,我們也可以看出,降維到150以后的數據,的確保留了原數據的大部分信息,所以圖像看起來,才會和原數據高度相似,只是稍稍模糊罷了。
返回頂部
• 迷你案例:PCA 手寫數字數據集噪音過濾
降維的目的之一就是希望希望拋棄掉對模型帶來負面影響的特征,而我們相信,帶有效信息的特征方差應該是遠遠大於噪音的,所以相比噪音,有效的特征所帶的信息不會應該不會在PCA過程中被大量拋棄。inverse_transform能夠在不恢復原始數據的情況下,將降維后的數據返回到原本的高維空間,即是說能夠實現"保證維度但去掉方差很小特征所帶的信息"。利用 inverse_transform的這個性質,我們能夠實現噪音過濾。
# 導庫
from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from matplotlib import pyplot as plt
import numpy as np
# 加載數據集
digits = load_digits()
x = digits.data
print("手寫數字數據集的data的形狀:\n",digits.data.shape)
print("手寫數字數據集的images的形狀:\n",digits.images.shape)
手寫數字數據集的data的形狀:
(1797, 64)
手寫數字數據集的images的形狀:
(1797, 8, 8)
# 數據集可視化
fig, axes = plt.subplots(4,
10,
figsize=(20, 8),
subplot_kw={
"xticks": [],
"yticks": []
})
k = 0 # 控制從原始數據中提取的數據索引
for i in range(4):
for j in range(10):
axes[i][j].imshow(x[k].reshape(8, 8), cmap="binary")
k = k+1
進行人為添加噪音,再次繪制:
# 人為添加噪音
rng = np.random.RandomState(42)
# 在指定的數據集中,隨機抽取服從正態分布的數據
# 兩個參數:指定的數據集、抽取出來的正態分布的方差
noisy = rng.normal(digits.data,2)
# 數據集可視化
fig, axes = plt.subplots(4,
10,
figsize=(20, 8),
subplot_kw={
"xticks": [],
"yticks": []
})
k = 0 # 控制從原始數據中提取的數據索引
for i in range(4):
for j in range(10):
axes[i][j].imshow(noisy[k].reshape(8, 8), cmap="binary")
k = k+1
進行降維逆轉(降噪)處理后,可視化:
# 降維處理
pca = PCA(0.5,svd_solver="full").fit(noisy)
x_dr = pca.transform(noisy)
print("保留50%數據信息量降維后的數據形狀為:\n",x_dr.shape)
保留50%數據信息量降維后的數據形狀為:
(1797, 6)
# 逆轉降處理
without_noisy = pca.inverse_transform(x_dr)
# 可視化
# 數據集可視化
fig, axes = plt.subplots(4,
10,
figsize=(20, 8),
subplot_kw={
"xticks": [],
"yticks": []
})
k = 0 # 控制從原始數據中提取的數據索引
for i in range(4):
for j in range(10):
axes[i][j].imshow(without_noisy[k].reshape(8, 8), cmap="binary")
k = k+1
返回頂部
⑥ 重要接口、參數、屬性總結
到這里,我們已經完成了對PCA的學習。我們學習了重要參數參數n_components,svd_solver, random_state;學習了三個重要屬性: components_, explained_variance以及explained_variance_ratio,無數次用到了接口fit,transform, fit_transform,還講解了與眾不同的重要接口 inverse_transform所有的這些內容都可以被總結在這張圖中:
返回頂部
————————————————
版權聲明:本文為CSDN博主「騎着蝸牛ひ追導彈'」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_45797116/article/details/113888336