最近期末需要交的論文有些多,所以更新進度有些慢,爲了彌補空白期,以後也會給大家轉載一些好文,感謝各位哥哥姐姐一直以來的支持。
如果只對降維的代碼部分感興趣可以直接劃至文末
一直都在研究關於機器學習相關算法的理論,最近準備打算在Kaggle參加些競賽,但只會一些理論知識是不足以針對給定的數據建立一個比較不錯的模型,這其中還包括很多必要的操作,比如缺失值處理、特徵工程等等。
今天來說一下特徵降維,我們在練習時通常會用sklearn自帶的數據集,比如鳶尾花數據集,通常這類數據集是經過處理的,特點就是規模小且完整性強,但對於Kaggle競賽或者其他領域中給定的數據集一般都是規模偏大且具有很多缺失值。
規模大可分爲兩方面,一方面是數據多而特徵少,另一方面是數據少但特徵多。我們都知道數據多對於建模是有好處的,因爲數據越多覆蓋面就越廣,會提高模型的準確率,當然這可能會犧牲一些內存和計算時間。
但是特徵多可未必就是一件好的事情,如果將數據集映射至一個空間中,每一個特徵就對應一個維度,隨着維度的增加,學習器所需的樣本的數量通常以指數增加,但通常高維度數據集的樣本個數並不滿足要求,這樣的數據稀疏性也特別高,可能導致模型的準確率偏低,且對內存和計算時間很不友好。
特徵降維
對於多特徵數據集,我們可以有這麼一個設想就是會不會有一些特徵之間的相關性很高?比如學習時長和學習成績之間就會呈正相關,那麼刪去其中一個對數據集的影響可能特別微小,其他特徵做類似操作,最後剩下的特徵兩兩之間不相關,此操作就叫做降維。
降維是一種針對高維度數據集數據預處理方法,它的基本思想就是保留一些相對重要的特徵,除去剩下的特徵和數據中的噪聲,降維操作可以很大程度節省運行內存和計算時間,讓數據處理更加高效。
對數據降維還有以下一系列原因:
- 使數據集更易使用;
- 降低很多算法的計算開銷;
- 除去數據中的噪聲;
- 使得結果易懂。
常見的降維方法有主成分分析(PCA)、因子分析(FA)、獨立成分分析(ICA)和奇異值分解(SVD)。其中PCA和SVD是最常用的兩種,本文介紹第一種PCA降維法。
主成分分析
原理及對應操作
主成分分析顧名思義是對主成分進行分析,那麼找出主成分應該是key點。PCA的基本思想就是將初始數據集中的n維特徵映射至k維上,得到的k維特徵就可以被稱作主成分,k維不是在n維中挑選出來的,而是以n維特徵爲基礎重構出來的。
PCA會在已知數據的基礎上重構座標軸,它的原理是要最大化保留樣本間的方差,兩個特徵之間方差越大不就代表相關性越差嘛。比如:
- 第一個新座標軸就是原始數據中方差最大的方向。
- 第二個新座標軸要是與第一個新座標軸正交的平面中方差最大的方向。
- 第三個新座標軸要是與第一、第二新座標軸正交的平面中方差最大的方向。
- 第四、第五…依次類推直到第n個新座標軸(對應n維)。
爲了加深這部分理解,以二維平面先舉一個例子,二維平面中依據原始數據新建座標軸如下圖:
爲了更直觀的理解,若將方差換一個說法,那麼第一個新座標軸就是覆蓋樣本最多的一條(斜向右上),第二個新座標軸需要與第一新座標軸正交且覆蓋樣本最多(斜向左上),依次類推。
覆蓋的樣本多少並不是以座標軸穿過多少樣本點評判的,而是通過樣本點垂直映射至該軸的個數有多少,具體如下圖:
回到之前的n維重構座標軸,由於順序是由方差的大小依次排序的,所以越到後面方差越小,而方差越小代表特徵之間相關性越強,那麼這類特徵就可以刪去,只保留前k個座標軸(對應k維),這就相當於保留了含有數據集絕大部分方差的特徵,而除去方差幾乎爲0的特徵。
那麼問題來了,二維、三維可以根據樣本點的分佈畫出重構座標軸,但是更高維人的大腦是不接受的,我們不得不通過計算的方式求得特徵之間的方差,進而得到這些新座標軸的的方向。
具體方法就是通過計算原始數據矩陣對應的協方差矩陣,然後可以得到協方差矩陣對應的特徵值和特徵向量,選取特徵值最大的前k個特徵向量組成的矩陣,通過特徵矩陣就可以將原始數據矩陣從n維空間映射至k維空間,從而實現特徵降維。
方差、協方差及協方差矩陣
如果你曾經接觸過線性代數可能對這三個概念很熟悉,可能間隔時間太久有些模糊,下面再幫大家溫習一下:
方差(Variance)一般用來描述樣本集合中的各個樣本點到樣本均值的差的平方和的均值:
協方差(Covariance)目的是度量兩個變量(只能爲兩個)線性相關的程度:
爲可以說明兩個變量線性無關,但不能證明兩個變量相互獨立,當時,二者呈正相關,時,二者呈負相關。
協方差矩陣就是由兩兩變量之間的協方差組成,有以下特點:
- 協方差矩陣可以處理多維度問題。
- 協方差矩陣是一個對稱的矩陣,而且對角線是各個維度上的方差。
- 協方差矩陣計算的是不同維度之間的協方差,而不是不同樣本之間的。
- 樣本矩陣中若每行是一個樣本,則每列爲一個維度。
假設數據是3維的,那麼對應協方差矩陣爲:
這裏簡要概括一下協方差矩陣是怎麼求得的,假設一個數據集有3維特徵、每個特徵有m個變量,這個數據集對應的數據矩陣如下:
若假設他們的均值都爲0,可以得到下面等式:
可以看到對角線上爲每個特徵方差,其餘位置爲兩個特徵之間的協方差,求得的就爲協方差矩陣。
這裏敘述的有些簡略,感興趣的小夥伴可以自行查詢相關知識。
特徵值和特徵向量
得到了數據矩陣的協方差矩陣,下面就應該求協方差矩陣的特徵值和特徵向量,先了解一下這兩個概念,如果一個向量v是矩陣A的特徵向量,那麼一定存在下列等式:
其中A可視爲數據矩陣對應的協方差矩陣,是特徵向量v的特徵值。數據矩陣的主成分就是由其對應的協方差矩陣的特徵向量,按照對應的特徵值由大到小排序得到的。最大的特徵值對應的特徵向量就爲第一主成分,第二大的特徵值對應的特徵向量就爲第二主成分,依次類推,如果由n維映射至k維就截取至第k主成分。
實例操作
通過上述部分總結一下PCA降維操作的步驟:
- 去均值化
- 依據數據矩陣計算協方差矩陣
- 計算協方差矩陣的特徵值和特徵向量
- 將特徵值從大到小排序
- 保留前k個特徵值對應的特徵向量
- 將原始數據的n維映射至k維中
公式手推降維
原始數據集矩陣,每行代表一個特徵:
對每個特徵去均值化:
計算對應的協方差矩陣:
依據協方差矩陣計算特徵值和特徵向量,套入公式:
拆開計算如下:
可以求得兩特徵值:
當時,對應向量應該滿足如下等式:
對應的特徵向量可取爲:
同理當時,對應特徵向量可取爲:
這裏我就不對兩個特徵向量進行標準化處理了,直接合並兩個特徵向量可以得到矩陣P:
選取大的特徵值對應的特徵向量乘以原數據矩陣後可得到降維後的矩陣A:
綜上步驟就是通過PCA手推公式實現二維降爲一維的操作。
numpy實現降維
import numpy as np
def PCA(X,k):
'''
X:輸入矩陣
k:需要降低到的維數
'''
X = np.array(X) #轉爲矩陣
sample_num ,feature_num = X.shape #樣本數和特徵數
meanVals = np.mean(X,axis = 0) #求每個特徵的均值
X_mean = X-meanVals #去均值化
Cov = np.dot(X_mean.T,X_mean)/sample_num #求協方差矩陣
feature_val,feature_vec = np.linalg.eig(Cov)
#將特徵值和特徵向量打包
val_sort = [(np.abs(feature_val[i]),feature_vec[:,i]) for i in range(feature_num)]
val_sort.sort(reverse=True) #按特徵值由大到小排列
#截取至前k個特徵向量組成特徵矩陣
feature_mat = [feature[1] for feature in val_sort[:k]]
# 降n維映射至k維
PCA_mat = np.dot(X_mean,np.array(feature_mat).T)
return PCA_mat
if __name__ == "__main__":
X = [[1, 1], [1, 3], [2, 3], [4, 4], [2, 4]]
print(PCA(X,1))
運行截圖如下:
代碼部分就是公式的套用,每一步後都有註釋,不再過多解釋。可以看到得到的結果和上面手推公式得到的有些出入,上文曾提過特徵向量是可以隨意縮放的,這也是導致兩個結果不同的原因,可以在運行代碼時打印一下特徵向量feature_vec,觀察一下這個特點。
sklearn庫實現降維
from sklearn.decomposition import PCA
import numpy as np
X = [[1, 1], [1, 3], [2, 3], [4, 4], [2, 4]]
X = np.array(X)
pca = PCA(n_components=1)
PCA_mat = pca.fit_transform(X)
print(PCA_mat)
這裏只說一下參數n_components,如果輸入的是整數,代表數據集需要映射的維數,比如輸入3代表最後要映射至3維;如果輸入的是小數,則代表映射的維數爲原數據維數的佔比,比如輸入0.3,如果原數據20維,就將其映射至6維。
總結
上面用到的數據集特別簡單,建議在練習的時候用一些特徵較多的數據集,可以利用圖像繪製一下各個主成分佔總方差的比例,很直觀的一個結果就是排序較前的一些主成分佔比特別大,最後一些可能佔比只有零點幾,這也是我們上文敘述的內容最基本的原理。
關注公衆號【奶糖貓】第一時間獲取更多精彩好文