主成分分析(PCA)的教程和代碼

編譯:chux

出品:ATYUN訂閱號

數據是機器學習模型的燃料。也許你有很多ML技術可以選擇並應用於特定問題,但如果你沒有很多好的數據,你就無法做的深入。數據通常是機器學習應用程序中改善性能的最大驅動因素。

有時,數據可能很複雜。你有這麼多的數據想要理解這一切意味着什麼以及數據的哪些部分真正重要很有挑戰性。維度降低是一種技術,它可以幫助我們更好地瞭解我們的數據。它減少了我們數據集的特徵數量,使我們只留下最重要的部分。

主成分分析(PCA)是一種簡單而強大的降維技術。通過它,我們可以直接減少特徵變量的數量,進而縮小重要特徵並節省計算量。從高層次來看,PCA有三個主要步驟:

(1)計算數據的協方差矩陣

(2)計算該協方差矩陣的特徵值和向量

(3)使用特徵值和向量選擇最重要的特徵向量,然後將數據轉換爲這些向量以降低維數!

(1)計算協方差矩陣

PCA產生一個特徵子空間,使特徵向量的方差最大化。因此,爲了正確測量這些特徵向量的方差,必須對它們進行適當的平衡。爲實現此目的,我們首先將數據標準化爲零均值和單位方差,以便在我們的計算中對每個特性進行平均加權。假設我們的數據集名爲X:

from sklearn.preprocessingimport StandardScaler
X= StandardScaler().fit_transform(X)

兩個變量的協方差度量它們相關的程度如何。如果兩個變量的協方差爲正,那麼當一個變量增加時,另一個也會增加;如果兩個變量的協方差爲負,特徵變量的值變化的方向相反。協方差矩陣只是一個數組,其中每個值基於矩陣中的x-y位置指定兩個特徵變量之間的協方差。公式是:

其中帶有頂部線的x是X的每個特徵的平均值向量。請注意,當我們將轉置矩陣乘以原始矩陣時,我們最終將每個數據點的每個要素相乘!在numpy代碼中它看起來像這樣:

import numpy as np
# Compute the mean of the data
mean_vec= np.mean(X, axis=0)
# Compute the covariance matrix
cov_mat= (X- mean_vec).T.dot((X- mean_vec))/ (X.shape[0]-1)
# OR we can do this with one line of numpy:
cov_mat= np.cov(X.T)

(2)計算特徵值和向量

我們協方差矩陣的特徵向量(主成分)表示新特徵空間的向量方向,而特徵值表示這些向量的大小。由於我們正在研究協方差矩陣因此可以認爲特徵值量化了每個向量所貢獻出的方差。

如果特徵向量具有相應的高量級的特徵值,則意味着我們的數據在特徵空間中沿着該向量具有高方差。因此,該向量包含有關我們數據的大量信息,因爲沿着該向量的任何移動都會導致大的方差。另一方面,具有小特徵值的矢量具有低方差,也就是說當沿着該矢量移動時,我們的數據不會有很大變化。因爲沿着特定特徵向量移動時沒有多大變化,即改變該特徵向量的值不會對我們的數據產生很大影響,那麼我們可以說這個特徵不是很重要,我們可以刪除它而不會承擔多大的損失。

這是PCA中特徵值和向量的全部本質。找到在表示數據時最重要的向量,並丟棄其餘的向量。在numpy中,計算協方差矩陣的特徵向量和特徵值是非常簡單的。計算之後,我們將根據它們的特徵值按降序對特徵向量進行排序。

# Compute the eigen values and vectors using numpy
eig_vals, eig_vecs= np.linalg.eig(cov_mat)
# Make a list of (eigenvalue, eigenvector) tuples
eig_pairs= [(np.abs(eig_vals[i]), eig_vecs[:,i])for iin range(len(eig_vals))]
# Sort the (eigenvalue, eigenvector) tuples from high to low
eig_pairs.sort(key=lambda x: x[0], reverse=True)

(3)對新向量的投影

此時,我們有一個根據特徵值對數據集的“重要性”排序的特徵向量列表。現在我們要做的是選擇我們需要的最重要的特徵向量,然後捨棄剩下的向量。我們可以通過查看向量解釋方差(explained variance)的百分比以做到這一點。這個百分比量化了在全部100%的主成分中,每個主成分所包含的信息(方差)。

我們舉一個例子來說明。假設我們有一個數據集最初有10個特徵向量。在計算協方差矩陣之後,我們發現特徵值是:

[12,10,8,7,5,1,0.1,0.03,0.005,0.0009]

該數組的總和= 43.1359。但前6個 值代表:42 / 43.1359 =總數的99.68%!

這意味着我們的前6個特徵向量有效地保有了關於數據集的99.68%的方差或者說信息。因此,我們可以捨棄最後4個特徵向量,因爲它們只包含0.32%的信息,爲了節省40%的計算,值得犧牲它們!

因此,我們可以簡單地定義一個閾值,我們可以用這個閾值決定每個特徵向量是保留還是丟棄。在下面的代碼中,我們簡單地根據選擇的97%的閾值來計算希望保留的特徵向量的數量。

# Only keep a certain number of eigen vectors based on
# the "explained variance percentage" which tells us how
# much information (variance) can be attributed to each
# of the principal components
exp_var_percentage= 0.97 # Threshold of 97% explained variance
tot= sum(eig_vals)
var_exp= [(i/ tot)*100 for iin sorted(eig_vals, reverse=True)]
cum_var_exp= np.cumsum(var_exp)
num_vec_to_keep= 0
for index, percentagein enumerate(cum_var_exp):
  if percentage > exp_var_percentage:
    num_vec_to_keep= index+ 1
    break

最後一步是將數據實際投影到我們決定保留的向量上。我們通過構建投影矩陣(表示我們要乘以一個矩陣把數據投影到新的向量上)來做到這一點。爲了創建這個矩陣,我們連接我們決定保留的所有特徵向量。最後,求原始數據和投影矩陣之間的點積。

view source

# Compute the projection matrix based on the top eigen vectors
num_features= X.shape[1]
proj_mat= eig_pairs[0][1].reshape(num_features,1)
for eig_vec_idxin range(1, num_vec_to_keep):
  proj_mat= np.hstack((proj_mat, eig_pairs[eig_vec_idx][1].reshape(num_features,1)))
# Project the data
pca_data= X.dot(proj_mat)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章