------------------------------PCA簡單使用------------------------------
一:回顧PCA
(一)主成分分析法是干什么用的?
數據降維,話句話說就是將數據地特征數量變少,但又不是簡單地刪除特征。
數據降維地目的可以是壓縮數據,減少數據的存儲空間,讓算法提速;
也可以是將數據降到二維或者三維進行可視化
(二)主成分分析法在做什么?
上面說到主成分分析法用於數據降維,大概理解一下它怎么做的。現在我們數據維度為n,我想通過降維讓數據變成k維。
那么PCA做的就是對於n維空間的數據,尋找一個K維的“面”,讓這些數據到這個“面”的距離最短,這個距離又叫做投影誤差。
找到這個“面”后,將n維空間的點投影到這個“面”,因此所有點都投影到了k維空間,因此可以特征數量變為了k。
假設n=2,k=1,那么就是將二維平面上的點投影到一個向量上。假設n=3,k=2,那么就是將三維空間的點投影到一個平面上。
(三)主成分分析法具體怎么做呢?---降維
對於數據要從n維降到k維
首先對數據進行feature scaling/mean normalization,也就是歸一化。
其次計算協方差矩陣:(列X行,得矩陣)
接着計算sigma矩陣的“特征向量”,這里使用奇異值分解(single value decomposition)。SVD奇異值分解得到特征向量和特征值。
取U矩陣(特征向量矩陣)中前k個向量得到一個n乘k維的矩陣Ureduce,其中訓練集x是一個(m,n)矩陣,樣本數為m,特征為n維,使用XUreduce就可得到降維后的數據
(四)主成分分析法具體怎么做呢?---重建數據
重建數據得到數據的近似值,因為U是特征向量矩陣,它由標准正交基組成,因此U.T@U為單位矩陣,所以這里要重建數據只需
然后再可視化投影,畫出標准化的數據以及投影之后又重建的數據,把對應點用虛線連接起來。然后看看降維后的數據保留了原始數據多少的差異性 。
二:數據集導入及可視化
import numpy as np import matplotlib.pyplot as plt import scipy.io as sio data = sio.loadmat("ex7data1.mat") X = data['X'] plt.figure() plt.scatter(X[:,0],X[:,1],marker="X",c="b") plt.show()
三:數據預處理
實現PCA首先要做的就是對數據的處理進行歸一化,注意這里的方差的計算,默認ddof為0,通常情況下是使用ddof=1,就是方差計算中最后除以m還是m-1的不同。ddof=0求解總體標准差,ddof=1求解樣本標准差
def data_preprocess(X): #數據預處理 return (X-np.mean(X,axis=0))/np.std(X,axis=0,ddof=1) #對特征進行均值求解(按列)
data = sio.loadmat("ex7data1.mat") X = data['X'] X = data_preprocess(X) print(X)
三:奇異值分解
其次計算協方差矩陣:
接着計算sigma矩陣的“特征向量”,這里使用奇異值分解(single value decomposition)。SVD奇異值分解得到特征向量和特征值
def PCA(X): sigma = X.T.dot(X)/len(X) U,S,V = np.linalg.svd(sigma) return U,S,V
X = data_preprocess(X) U,S,V = PCA(X) print(U) print(S) print(V)
四:使用PCA進行降維
取U矩陣(特征向量矩陣)中前k個向量得到一個n乘k維的矩陣Ureduce,其中訓練集x是一個(m,n)矩陣,樣本數為m,特征為n維,使用XUreduce就可得到降維后的數據
def PCA_process(X,U,K): #進行降維操作 傳入的K是我們目標維度 return X.dot(U[:, :K])
data = sio.loadmat("ex7data1.mat") X = data['X'] X = data_preprocess(X) U,S,V = PCA(X) K = 1 Z = PCA_process(X,U,K) print(Z)
print(Z.shape)
五:數據升維操作
重建數據得到數據的近似值,因為U是特征向量矩陣,它由標准正交基組成,因此U.T@U為單位矩陣,所以這里要重建數據只需
其中z是(m,k)維度,UreduceT是(k,n)矩陣,所以相乘后得到(m,n)維矩陣,達到升維目的。
def reconstruct_data(Z, U, K): #進行升維操作 return Z.dot(U[:,:K].T)
data = sio.loadmat("ex7data1.mat") X = data['X'] X = data_preprocess(X) U,S,V = PCA(X) K = 1 Z = PCA_process(X,U,K) X_approx = reconstruct_data(Z,U,K) print(X_approx)
注意:升維后的數據就是在二維空間中的一條直線(降維數據在二維空間的顯示)
plt.figure() plt.scatter(X_approx[:,0],X_approx[:,1],marker="X",c="r") #雖然降維到1維,但是我們要畫在二維空間中,所以我們需要使用X_approx繪制圖像 plt.show()
六: 繪制PCA可視化圖像
data = sio.loadmat("ex7data1.mat") X = data['X'] X = data_preprocess(X) K = 1 U,S,V = PCA(X) Z = PCA_process(X,U,K) X_approx = reconstruct_data(Z,U,K) plt.figure() plt.scatter(X[:,0],X[:,1],marker="X",c="b") #繪制原圖像 plt.scatter(X_approx[:,0],X_approx[:,1],marker="X",c="r") #雖然降維到1維,但是我們要畫在二維空間中,所以我們需要使用X_approx繪制圖像 #繪制降維路線 for i in range(len(X)): plt.plot([X[i][0],X_approx[i][0]],[X[i][1],X_approx[i][1]],'k--') plt.show()
------------------------------人臉像素降維之PCA使用------------------------------
將PCA應用到人類數據集上,當前的每張人臉圖片為1024像素,因此為1024維。我們的目標是將數據降維到36像素,也就是36維。
import numpy as np import matplotlib.pyplot as plt import scipy.io as sio def data_preprocess(X): #數據預處理 return (X-np.mean(X,axis=0))/np.std(X,axis=0,ddof=1) #對特征進行均值求解(按列) def PCA(X): sigma = X.T.dot(X)/len(X) U,S,V = np.linalg.svd(sigma) return U,S,V def PCA_process(X,U,K): #進行降維操作 傳入的K是我們目標維度 return X.dot(U[:, :K]) def reconstruct_data(Z, U, K): #進行升維操作 return Z.dot(U[:,:K].T) def visaulizing_images(X,r,d): #r表示顯示行數,d表示一行顯示圖片數 n = X.shape[1] p = int(np.sqrt(n)) for i in range(1,r*d+1): plt.subplot(r,d,i) #m/d行,d列,第i個位置子圖 plt.axis("off") #使得每個子圖不顯示坐標 plt.imshow(X[i-1].reshape(p,p).T,cmap='Greys_r') #人臉數據是倒着的,我們需要轉置來擺正 plt.show() data = sio.loadmat("ex7faces.mat") X = data['X'] visaulizing_images(X,2,5) #顯示原始圖像 X = data_preprocess(X) visaulizing_images(X,2,5) #顯示原始圖像(歸一化后的) K = 36 U,S,V = PCA(X) Z = PCA_process(X,U,K) X_approx = reconstruct_data(Z,U,K) visaulizing_images(X_approx,2,5) #顯示原始圖像
臉部基本特征還是被保留了。