機器學習之PCA

1、PCA概述

在很多實際數據中,通常涉及很多的變量。大量的變量不但增加了計算的複雜度,而且有些變量有可能是噪聲,
從而將數據中的主要數據“淹沒”。此外雖然每一個變量都提供了相應的信息,但是很多變量可能存在一定的
相關性。因此,我們希望從數據中提取主要變量信息,用較少的新變量來表達數據中的主要信息。在主成分分析
(pricipal component analysis,PCA)中,我們使用舊變量的線性組合構建新變量。換言之,主成分分析的基本思想是利用線性變換將高維空間中的數據投影到低維空間中,並保留最主要信息。

2、PCA算法介紹

簡單來說,就是將數據從原始的空間轉換到新的特徵空間中,例如原始的空間是三維的(x,y,z),x,y,z分別是原始的三個基,我們可以通過某種方法,用新的座標系(a,b,c)來表示原始的數據,那麼a,b,c就是新的基,它們可以組成新的特徵向量空間。在新的特徵向量空間中,可能所有的數據在C上的投影都接近於0,即可以忽略,那麼我們就直接用(a,b)來表示數據,這樣數據就從三維的(x,y,z)降到了二維的(a,b)。

如何求新的基(a,b)?

般步驟是這樣的:先對原始數據零均值化,然後求協方差矩陣,接着對協方差矩陣求特徵向量和特徵值,這些特徵向量組成了新的特徵空間。

參考:http://blog.codinglabs.org/articles/pca-tutorial.html
通俗易懂

3、選擇主成分個數

我們該如何選擇k,即保留多少個PCA主成分?對於高維數據來說就沒那麼簡單:如果k過大,數據壓縮率不高,在極限情況k=n 時,等於是在使用原始數據;相反地,如果k過小,那數據的近似誤差太大。決定k 值時,我們通常會考慮不同 k 值可保留的方差百分比。具體來說,如果k=n ,那麼我們得到的是對數據的完美近似,也就是保留了100%的方差,即原始數據的所有變化都被保留下來;相反,如果k=0,那等於是使用零向量來逼近輸入數據,也就是隻有0%的方差被保留下來。這個百分比也叫貢獻率,通常取高於80%。

這裏寫圖片描述

#參數:特徵值,百分比
def percentage2k(featValue,percentage):
    sortArray = np.sort(featValue)    # 降序
    sortArray=sortArray[-1::-1]  #逆轉,即降序 
    print("sortArray: ",sortArray)
    arraySum = sum(sortArray)
    tmpSum = 0
    num = 0
    for i in sortArray:
        tmpSum += i
        num += 1
        if tmpSum >= arraySum*percentage:
            return num

4、PCA的python實現

"""
date       2017-08
Author     ggwcr
theory     http://blog.codinglabs.org/articles/pca-tutorial.html    
Note       PCA source code 
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#加載數據
def loaddata(datafile):
    return np.array(pd.read_csv(datafile,sep="\t",header=-1)).astype(np.float)


# 將數據歸一化
# 返回:歸一化後的矩陣與極差
def autoNorm(dataSet):
    #獲取列的最小值
    minVals = dataSet.min(0)
    #獲取列的最大值
    maxVals = dataSet.max(0)  
    #獲得極差
    ranges = maxVals -minVals  
    #創建以傳入數據集同結構的零矩陣
    normDataSet = np.zeros(np.shape(dataSet))  
    #獲取列的長度
    m,n = np.shape(dataSet)
    #得到一個原矩陣與最小值相減所得的矩陣{oldValue- min )
    normDataSet = dataSet - np.tile(minVals,(m,1))
    #計算{oldValue- min ) / (max-min)
    normDataSet = normDataSet/np.tile(ranges,(m,1))
    return normDataSet,ranges

# 零均值化
def zeroMean(dataSet):
    meanVal = np.mean(dataSet,axis=0)  # axis = 0 表示按照列來求均值 
    ZMDataSet = dataSet - meanVal
    return ZMDataSet,meanVal

# 指定k值
def pca(dataSet,k):
    # 先將數據歸一化
    normDataSet,ranges = autoNorm(dataSet)
    # 對歸一化後的數據進行零均值化
    ZMDataSet,meanVal = zeroMean(normDataSet)
    m,n = np.shape(ZMDataSet)
    # 求零均值化後的協方差矩陣
    covMat = np.cov(ZMDataSet,rowvar=0)  #若rowvar=0,說明傳入的數據一行代表一個樣本
    #求解協方差矩陣的特徵值和特徵向量
    #返回值爲:特徵值和特徵向量
    featValue, featVec=  np.linalg.eig(np.mat(covMat))  
    #按照featValue進行從大到小排序
    index = np.argsort(-featValue) 
    finalData = []
    # 對需要降到的維數大小進行判斷
    if k > n:
        print ("kmust lower than feature number")
        return
    else:
        #注意特徵向量時列向量,而numpy的二維矩陣(數組)a[m][n]中,a[1]表示第1行值
        selectVec = np.matrix(featVec.T[index[:k]]) #所以這裏需要進行轉置
        lowDataMat = ZMDataSet* selectVec.T 
        reconDataMat = (lowDataMat* selectVec) +meanVal  
    return lowDataMat, reconDataMat    

# 根據貢獻率,自己找k值
def pcaNK(dataSet,percentage):
    # 先將數據歸一化
    normDataSet,ranges = autoNorm(dataSet)
    # 對歸一化後的數據進行零均值化
    ZMDataSet,meanVal = zeroMean(normDataSet)
    m,n = np.shape(ZMDataSet)
    # 求零均值化後的協方差矩陣
    covMat = np.cov(ZMDataSet,rowvar=0)  #若rowvar=0,說明傳入的數據一行代表一個樣本
    #求解協方差矩陣的特徵值和特徵向量
    #返回值爲:特徵值和特徵向量
    featValue, featVec=  np.linalg.eig(np.mat(covMat))  
    print("featValue: ",featValue)
    #根據percentage求k值
    k = percentage2k(featValue,percentage)
    print("k is :",k)
    #按照featValue進行從大到小排序
    index = np.argsort(-featValue) 
    finalData = []
    #注意特徵向量時列向量,而numpy的二維矩陣(數組)a[m][n]中,a[1]表示第1行值
    selectVec = np.matrix(featVec.T[index[:k]]) #所以這裏需要進行轉置
    lowDataMat = ZMDataSet* selectVec.T 
    reconDataMat = (lowDataMat* selectVec) +meanVal  
    return lowDataMat, reconDataMat 

def plotBestFit(data1, data2):
    dataArr1 = np.array(data1)
    dataArr2 = np.array(data2)

    m = np.shape(dataArr1)[0]
    axis_x1 = []
    axis_y1 = []
    axis_x2 = []
    axis_y2 = []
    for i in range(m):
        axis_x1.append(dataArr1[i,0])
        axis_y1.append(dataArr1[i,1])
        axis_x2.append(dataArr2[i,0]) 
        axis_y2.append(dataArr2[i,1])             
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(axis_x1, axis_y1, s=50, c='red', marker='s')
    ax.scatter(axis_x2, axis_y2, s=50, c='blue')
    plt.xlabel('x1'); plt.ylabel('x2');
    plt.savefig("outfile.png")
    plt.show() 

def test():
    X = [[2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1],
        [2.4, 0.7, 2.9, 2.2, 3.0, 2.7, 1.6, 1.1, 1.6, 0.9]]
    XMat = np.matrix(X).T  
    k = 2
    return pca(XMat, k)

#根據數據集data.txt
def main():    
    datafile = "c:\data.csv"
    XMat = loaddata(datafile)
    k = 2
    return pca(XMat, k)
if __name__ == "__main__":
    finalData, reconMat = main()
    plotBestFit(finalData, reconMat)

這裏寫圖片描述

藍色部分爲重構後的原始數據,紅色則是提取後的二維特徵!

發佈了31 篇原創文章 · 獲贊 8 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章