PCA實現教程

摘要: 手把手教你PCA降維技術!(有案例)

數據是機器學習模型的生命燃料。對於特定的問題,總有很多機器學習技術可供選擇,但如果沒有很多好的數據,問題將不能很好的解決。數據通常是大部分機器學習應用程序中性能提升背後的驅動因素。

有時,數據可能很複雜。在那麼多的數據中,知道哪些數據是真正重要的,具有一定的挑戰性。降維是一種可以幫助我們更好地瞭解數據的技術,它減少了數據集的特徵數量,因此只剩下最重要的部分特徵。

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

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

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

(3)通過特徵值和向量來只選擇最重要的特徵向量,然後將數據轉換爲這些向量以降低維度。

(1)計算協方差矩陣

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

from sklearn.preprocessing import 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 i in range(len(eig_vals))]
# Sort the (eigenvalue, eigenvector) tuples from high to low
eig_pairs.sort(key=lambda x: x[0], reverse=True)

(3)映射到新的向量上

此時,我們有一個特徵向量列表,這些特徵向量基於它們的特徵值按照數據集的“重要性”進行排序。現在要做的是選擇最重要的特徵向量並丟棄其餘的,可以通過查看向量的可解釋方差百分比來巧妙地做到這一點。該百分比量化了總100%中每個主成分可歸因於多少信息(方差)。

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

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

該數組的總和= 43.1359,但前6個值代表:43 / 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 i in sorted(eig_vals, reverse=True)]
cum_var_exp = np.cumsum(var_exp)
num_vec_to_keep = 0
for index, percentage in enumerate(cum_var_exp):
  if percentage > exp_var_percentage:
    num_vec_to_keep = index + 1
    break

最後一步是將我們的數據實際投射到決定保留的向量上。我們通過構建投影矩陣來做到這一點:我們將通過相乘將數據投影到新的向量上。爲了創建它,簡單地與決定保留的所有特徵向量進行連接,最後一步是簡單地在原始數據和投影矩陣之間取點積。

維度降低了!

# 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_idx in 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)

數據科學書推薦

想要了解更多有關數據科學的信息?這本書是我在這個主題上看到的最好的,提供了實用且易於理解的課程。



本文作者:【方向】

閱讀原文

本文爲雲棲社區原創內容,未經允許不得轉載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章