要理解什麼是降維,書上給出了一個很好可是有點抽象的例子。
說,看電視的時候屏幕上有成百上千萬的像素點,那麼其實每一個畫面都是一個上千萬維度的數據;可是咱們在觀看的時候大腦自動把電視裏面的場景放在咱們所能理解的三維空間來理解,這個很天然的過程其實就是一個
降維(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)
和原始數據的維度數同樣,至關於沒有降維,重構以後的數據會和原始數據重合,以下圖所示: