用 PCA 方法進行數(shù)據(jù)降維
在進行數(shù)據(jù)分析時,我們往往會遇到多維數(shù)據(jù),多維數(shù)據(jù)在處理時由于維度較大計算起來非常麻煩,這時我們需要對數(shù)據(jù)進行降維。而在所有降維方法中,PCA是我們最常用的方法之一,其在使用時可以消除指標間的相互影響,同時也不用考慮數(shù)據(jù)的分布,而且降維效果非常明顯,所以PCA可以在絕大多數(shù)情況下使用。而本文就是用python來解釋一下如何用PCA方法進行降維。
首先對PCA進行一下簡介。PCA全稱是principal components analysis,即主成分分析。假設對某一事物的研究設計p個指標,分別用X1、X2、......、Xp表示,這p個指標構成的p維隨機向量為X=(X1, X2, ..., Xp)’,設X的均值為μ,協(xié)方差矩陣為Σ。對X進行線性變換,可以形成新的綜合變量,用Y表示,也就是說新的變量可以由原來的變量線性表示,即滿足圖1中的關系。

圖1. PCA原理
Yi=(ui)’X的方差盡可能大且Yi之間相互獨立。所以我們將線性變換約束在下面的條件之內(nèi):import?numpy?as?np?
import?pandas?as?pd?
import?seaborn?as?sns
import?matplotlib.pyplot?as?plt
from?sklearn.decomposition?import?PCA
接下來讀取相關數(shù)據(jù)集,這個數(shù)據(jù)集位于seaborn庫當中。前8行數(shù)據(jù)如圖2所示。
data?=?sns.load_dataset('iris')
data.head(8)

圖2. 數(shù)據(jù)集樣例
然后對數(shù)據(jù)做一個簡單的處理,看一下各個維度之間的相關關系。所得結果如圖3和圖4所示。
values?=?data.iloc[:,?:4]?#讀取前4列數(shù)據(jù)
correlation?=?values.corr()?#列與列之間的相關系數(shù)
fig,?ax?=?plt.subplots(figsize=(12,?10))
sns.heatmap(correlation,?annot=True,?annot_kws={'size':16},?cmap='Reds',?square=True,?ax=ax)?#熱力圖
sns.pairplot(data,?hue='species')?#散點關系圖

圖3. 各維度之間的相關系數(shù)熱力圖

圖4. 各維度之間的散點關系圖
從圖中可以大致看出,sepal_length和petal_length與petal_width都有較強的相關性,而petal_length和petal_width的相關性最強,達到0.96。下面我們來用PCA具體來分析一下該數(shù)據(jù)集,首先先看看該數(shù)據(jù)在選取4個主成分下的情況,這時候其主成分的數(shù)量和原數(shù)據(jù)的維度數(shù)相等。其結果如圖5所示。
pca?=?PCA(n_components=4)?#選取4個主成分
pc?=?pca.fit_transform(values)?#對原數(shù)據(jù)進行pca處理
print("explained?variance?ratio:?%s"?%?pca.explained_variance_ratio_)?#輸出各個主成分所占的比例
plt.plot(range(1,?5),?np.cumsum(pca.explained_variance_ratio_))?#繪制主成分累積比例圖
plt.scatter(range(1,5),np.cumsum(pca.explained_variance_ratio_))
plt.xlim(0,?5)
plt.ylim(0.9,?1.02)
plt.xlabel("number?of?components")
plt.ylabel("cumulative?explained?variance");

圖5. 各主成分累加結果
我們可以看到pca.explained_variance_ratio_的結果是[0.92461872 0.05306648 0.01710261 0.00521218],而圖5中也顯示前兩個主成分之和就已經(jīng)接近所有主成分的98%,所以在只考慮前兩個主成分的情況下,我們就能夠?qū)?shù)據(jù)的損失控制在很小的范圍內(nèi)。這里我們就只用前兩個主成分來做分析。接下來我們就只用前兩個主成分來分析原數(shù)據(jù),將兩個主成分的數(shù)據(jù)轉(zhuǎn)換成dataframe格式,然后再加上一列原數(shù)據(jù)中species的數(shù)據(jù),代碼如下,結果如圖6所示。
pca1?=?PCA(n_components=2)?#選取2個主成分
pc1?=?pca1.fit_transform(values)?
pc1_df?=?pd.DataFrame(pc1,?columns=['pc_1',?'pc_2'])
pc1_df['species']?=?data['species']?#加上一列species
pc1_df.head(8)

圖6. 只有兩個主成分的數(shù)據(jù)樣例
接下來我們來看一下這兩個主成分的組成。
print(pca1.components_)
結果如下。
[[?0.36138659?-0.08452251??0.85667061??0.3582892?]
?[?0.65658877??0.73016143?-0.17337266?-0.07548102]]
用這個結果來驗證一下前面的數(shù)據(jù)。按照圖1中的原理來計算,pca1.components_第一行的數(shù)據(jù)和values第一行數(shù)據(jù)對應項相乘的和,應該等于pc1_df中pc_1列第一個數(shù)據(jù)-2.684126,即圖6中第一行第一列數(shù)據(jù)。即有下列代碼。
print(np.dot(pca1.components_[0],?values.iloc[0]))
按照上式計算,結果是2.8182395066394683。很多人看到這里,認為是不是算錯了,其實我們在計算方法上都沒有錯,只是在這里有一個隱含條件沒有滿足,就是sklearn在進行PCA計算時,數(shù)據(jù)要進行“中心化”,即每個數(shù)據(jù)減去這組數(shù)據(jù)的平均值,這樣做主要是為了后續(xù)方便計算。所以我們要把上述代碼改為下面這樣。
print(np.dot(pca1.components_[0],?values.iloc[0]-values.mean(axis=0)))
其得到的結果是-2.684125625969536,這就和前面的-2.684126對應起來了(這里排除小數(shù)點精度問題)。接下來就是用我們降維后的數(shù)據(jù)來作圖。我們將原先的數(shù)據(jù)從4維降為2維,這正好方便繪制二維圖,代碼如下。結果如圖7所示。
setosa?=?pc1_df[pc1_df['species']=='setosa']?#找出setosa對應的主成分數(shù)據(jù)
virginica?=?pc1_df[pc1_df['species']=='virginica']
versicolor?=?pc1_df[pc1_df['species']=='versicolor']
fig,?ax?=?plt.subplots(figsize=(10,?8))
plt.scatter(setosa['pc_1'],?setosa['pc_2'],?alpha=0.7,?color?=?'red',?label='Setosa')?#繪制Setosa的散點圖
plt.scatter(virginica['pc_1'],?virginica['pc_2'],?alpha=0.7,?color?=?'green',?label='Virginica')
plt.scatter(versicolor['pc_1'],?versicolor['pc_2'],?alpha=0.7,?color?=?'blue',??label='Versicolor')
plt.legend(loc='best')
plt.xlabel('principal?component?1')
plt.ylabel('principal?component?2')

圖7 . 降維后的散點圖
主成分分析這種方法雖然簡單易用,但其也有自身的缺點,比如對降維最終得到數(shù)目,不能很好地估計,同時PCA對于維度之間非線性的依賴關系不能得到很好的結果。此外本例中筆者沒有對原數(shù)據(jù)進行標準化,因為標準化可能會損失一定信息,這個問題業(yè)界也爭論了很長時間,到底是否對數(shù)據(jù)進行標準化需要根據(jù)實際情況來判斷,因為本例中各維度之間的數(shù)據(jù)差異不大,所以筆者并未進行標準化。所以針對PCA的使用,大家還是要根據(jù)數(shù)據(jù)的要求來進行判斷。
作者簡介:Mort,數(shù)據(jù)分析愛好者,擅長數(shù)據(jù)可視化,比較關注機器學習領域,希望能和業(yè)內(nèi)朋友多學習交流。
贊 賞 作 者

Python中文社區(qū)作為一個去中心化的全球技術社區(qū),以成為全球20萬Python中文開發(fā)者的精神部落為愿景,目前覆蓋各大主流媒體和協(xié)作平臺,與阿里、騰訊、百度、微軟、亞馬遜、開源中國、CSDN等業(yè)界知名公司和技術社區(qū)建立了廣泛的聯(lián)系,擁有來自十多個國家和地區(qū)數(shù)萬名登記會員,會員來自以工信部、清華大學、北京大學、北京郵電大學、中國人民銀行、中科院、中金、華為、BAT、谷歌、微軟等為代表的政府機關、科研單位、金融機構以及海內(nèi)外知名公司,全平臺近20萬開發(fā)者關注。

▼點擊成為社區(qū)會員? ?喜歡就點個在看吧

