簡介
要理解什么是降維,書上給出了一個很好但是有點抽象的例子。
說,看電視的時候屏幕上有成百上千萬的像素點,那么其實每個畫面都是一個上千萬維度的數據;但是我們在觀看的時候大腦自動把電視里面的場景放在我們所能理解的三維空間來理解,這個很自然的過程其實就是一個
降維(dimensionallity reduction)的過程
降維有什么作用呢?
- 數據在低維下更容易處理、更容易使用;
- 相關特征,特別是重要特征更能在數據中明確的顯示出來;如果只有兩維或者三維的話,更便於可視化展示;
- 去除數據噪聲
- 降低算法開銷
常見的降維算法有主成分分析(principal component analysis,PCA)、因子分析(Factor Analysis)和獨立成分分析(Independent Component Analysis,ICA),其中PCA是目前應用最為廣泛的方法。
PCA原理
在PCA中,數據從原來的坐標系轉換到新的坐標系,新坐標系的選擇是由數據本身決定的。第一個坐標軸的選擇是原始數據中方差最大的方向,從數據角度上來講,這其實就是最重要的方向,即下圖總直線B的方向。第二個坐標軸則是第一個的垂直或者說正交(orthogonal)方向,即下圖中直線C的方向。該過程一直重復,重復的次數為原始數據中特征的數目。而這些方向所表示出的數據特征就被稱為“主成分”。

那怎么來求出這些主成分呢?由線性代數的知識可以知道,通過數據集的協方差矩陣及其特征值分析,我們就可以求得這些主成分的值。一旦得到協方差矩陣的特征向量,就可以保留最大的N個值。然后可以通過把數據集乘上這N個特征向量轉換到新的空間。
PCA實現
在python的numpy包中linalg模塊的eig()方法可以用於求特征值和特征向量。
從上面的原理分析中我們可以得出講數據轉化成前N個主成分的偽代碼如下:
去除平均值
計算協方差矩陣
計算協方差矩陣的特征值和特征向量
將特征值從大到小排序
保留最上面的N個特征向量
將數據轉換到上述N個特征向量構建的新空間中
代碼實現如下:
# 加載數據的函數
def loadData(filename, delim = '\t'):
fr = open(filename)
stringArr = [line.strip().split(delim) for line in fr.readlines()]
datArr = [map(float,line) for line in stringArr]
return mat(datArr)
# =================================
# 輸入:dataMat:數據集
# topNfeat:可選參數,需要應用的N個特征,可以指定,不指定的話就會返回全部特征
# 輸出:降維之后的數據和重構之后的數據
# =================================
def pca(dataMat, topNfeat=9999999):
meanVals = mean(dataMat, axis=0)# axis = 0表示計算縱軸
meanRemoved = dataMat - meanVals #remove mean
covMat = cov(meanRemoved, rowvar=0)# 計算協方差矩陣
eigVals,eigVects = linalg.eig(mat(covMat))# 計算特征值(eigenvalue)和特征向量
eigValInd = argsort(eigVals) #sort, sort goes smallest to largest
eigValInd = eigValInd[:-(topNfeat+1):-1] #cut off unwanted dimensions
redEigVects = eigVects[:,eigValInd] #reorganize eig vects largest to smallest
lowDDataMat = meanRemoved * redEigVects#transform data into new dimensions
reconMat = (lowDDataMat * redEigVects.T) + meanVals
return lowDDataMat, reconMat
在數據集上進行PCA操作:
filename = r'E:\ml\machinelearninginaction\Ch13\testSet.txt'
dataMat = loadData(filename)
lowD, reconM = pca(dataMat, 1)
原始數據如下:

降維之后:
>>>shape(lowD)
得到(1000,1),可以看到兩維降成了一維的數據
通過如下代碼把降維后的數據和原始數據打印出來:
def plotData(dataMat,reconMat):
fig = plt.figure()
ax = fig.add_subplot(111)
# 繪制原始數據
ax.scatter(dataMat[:, 0].flatten().A[0], dataMat[:,1].flatten().A[0], marker='^', s = 90)
# 繪制重構后的數據
ax.scatter(reconMat[:,0].flatten().A[0], reconMat[:,1].flatten().A[0], marker='o', s = 10, c='red')
plt.show()
如下圖所示:
降維之后的方向和我們之前討論的最大方差方向是吻合的。
如果執行以下代碼:
lowD, reconM = pca(dataMat, 2)
和原始數據的維度數一樣,相當於沒有降維,重構之后的數據會和原始數據重合,如下圖所示:
小結
本文中只用了一個比較小的數據集來展示和驗證PCA算法。
在實際應用中,數據的維度都是很大的,這些維度的重要性不同,甚至有的維度沒有用,這種時候降維就能發揮很大的作用。它可以清除噪聲,實現很多比例的數據壓縮。
需要強調的是,在使用PCA的時候並不能一下就確定需要的主成分數量,要通過多次的嘗試才能確定能夠覆蓋足夠信息量的主成分數量,一般需要保證信息量在90%以上,而且根據不同的應用場景有所不同。
降維一般作為數據適用其他模型算法之前的預處理技術。