【python】sklearn PCA對人臉資料降維與識别
- 1. PCA
-
- 1.1 PCA原理
- 1.2 sklearn PCA使用方法
- 2. 人臉資料降維
-
- 2.1 讀取圖檔
- 2.2 使用PCA進行降維
- 參考文獻
1. PCA
PCA(Principal Component Analysis),即主成分分析方法,是一種使用最廣泛的資料降維算法。PCA的主要思想是将n維特征映射到k維上,這k維是全新的正交特征也被稱為主成分,是在原有n維特征的基礎上重新構造出來的k維特征。
1.1 PCA原理
PCA算法步驟是從原始的空間中順序地找一組互相正交的坐标軸,其中第一個新坐标軸選擇是原始資料中方差最大的方向,第二個新坐标軸選取是與第一個坐标軸正交的平面中使得方差最大的,第三個軸是與第1,2個軸正交的平面中方差最大的。以此類推,得到n個這樣的坐标軸。通過這種方式獲得的新的坐标軸,大部分方差都包含在前面k個坐标軸中,後面的坐标軸所含的方差幾乎為0。于是,我們可以忽略餘下的坐标軸,隻保留前面k個含有絕大部分方差的坐标軸。事實上,這相當于隻保留包含絕大部分方差的次元特征,而忽略包含方差幾乎為0的特征次元,進而實作對資料特征的降維處理。
1.2 sklearn PCA使用方法
這裡介紹一下sklearn中的PCA使用方法。
PCA的一般步驟是:先對原始資料零均值化,然後求協方差矩陣,接着對協方差矩陣求特征向量和特征值,這些特征向量組成了新的特征空間。
sklearn.decomposition.PCA(n_components=None, copy=True, whiten=False)
參數:
n_components:
意義:PCA算法中所要保留的主成分個數n,也即保留下來的特征個數n
類型:
- int,指定将原始資料降到的次元。比如n_components=2,将原始資料降到二維
- float,指定主成分的方差和所占的最小比例門檻值,讓PCA類自己去根據樣本特征方差來決定降維到的次元數,此時n_components是一個(0, 1)之間的數
- string,比如n_components=‘mle’,将自動選取特征個數n,使得滿足所要求的方差百分比。
- 預設時預設為None,所有成分被保留。
copy:
意義:表示是否在運作算法時,将原始訓練資料複制一份。若為True,則運作PCA算法後,原始訓練資料的值不 會有任何改變,因為是在原始資料的副本上進行運算;若為False,則運作PCA算法後,原始訓練資料的 值會改,因為是在原始資料上進行降維計算。
類型:bool,True或者False,預設時預設為True。
whiten:
類型:bool,預設時預設為False
意義:判斷是否進行白化。所謂白化,就是對降維後的資料的每個特征進行歸一化,讓方差都為1.對于PCA降維本身來說,一般不需要白化。如果你PCA降維後有後續的資料處理動作,可以考慮白化。預設值是False,即不進行白化。
PCA常用屬性:
- components_ :傳回具有最大方差的成分
- explained_variance_ratio_:傳回所保留的n個成分各自的方差百分比
- n_components_:傳回所保留的成分個數n
- mean_: 原始資料中每個特征的均值
- n_features_ : 原始資料中特征的數量
- noise_variance_:噪聲方差
PCA常用方法:
-
fit(X,y=None):fit(X),表示用資料X來訓練PCA模型。
函數傳回值:調用fit方法的對象本身。比如pca.fit(X),表示用X對pca這個對象進行訓練。
拓展:fit()可以說是scikit-learn中通用的方法,每個需要訓練的算法都會有fit()方法,它其實就是算法中的“訓練”這一步驟。因為PCA是無監督學習算法,此處y自然等于None。
- fit_transform(X):用X來訓練PCA模型,同時傳回降維後的資料。newX=pca.fit_transform(X),newX就是降維後的資料。
- inverse_transform():将降維後的資料轉換成原始資料,X=pca.inverse_transform(newX)。
- transform(X):将資料X轉換成降維後的資料。當模型訓練好後,對于新輸入的資料,都可以用transform方法來降維。
2. 人臉資料降維
這裡使用了Orl_faces資料集。ORL人臉資料集共包含40個不同人的400張圖像,是在1992年4月至1994年4月期間由英國劍橋的Olivetti研究實驗室建立。
此資料集下包含40個目錄,每個目錄下有10張圖像,每個目錄表示一個不同的人。所有的圖像是以PGM格式存儲,灰階圖,圖像大小寬度為92,高度為112。對每一個目錄下的圖像,這些圖像是在不同的時間、不同的光照、不同的面部表情(睜眼/閉眼,微笑/不微笑)和面部細節(戴眼鏡/不戴眼鏡)環境下采集的。所有的圖像是在較暗的均勻背景下拍攝的,拍攝的是正臉(有些帶有略微的側偏)。
2.1 讀取圖檔
這裡讀取所有圖檔,同時将每張圖檔拉伸為一維數組友善後續使用PCA進行降維。傳回一個包含了Orl_faces資料集所有人臉資料的的二維數組,數組大小為
(400, 10304)
。
import os
import cv2
import matplotlib.pyplot as plt
import numpy as np
from sklearn.decomposition import PCA
# 為友善顯示圖檔,采用opencv讀取、處理圖檔,用matplotlib顯示圖檔
# 讀取所有圖檔
root = 'orl_faces' # 根目錄
listdir = os.listdir(root)
listdir.sort(key=lambda s: int(s[1:])) # listdir讀取的目錄清單無序,按數字大小進行排序
data = []
# 讀取所有圖檔傳回一個(m, n)數組,m為圖檔數量,n為圖檔一維size
for i in listdir:
path = os.path.join(root, i)
tmp_dir = os.listdir(path)
tmp_dir.sort(key=lambda s: int(s.split('.')[0])) # 按圖檔名稱數字大小進行排序
for j in tmp_dir:
img_path = os.path.join(path, j)
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
if img is None:
print('Failed to load image.')
else:
# print(img.shape)
img = img.reshape(1, -1)
data.append(img)
# 壓縮後的全部圖檔 (400, 112*92)
data = np.array(data).reshape(len(data), -1)
# 展示其中n張
def show_img(figure_num, n, img_set):
fig = plt.figure(figure_num)
for i in range(n):
tmp_img = img_set[i * 10].reshape(112, 92)
plt.subplot(int(np.ceil(n/5)), 5, i + 1)
plt.imshow(tmp_img, cmap='gray')
plt.show()
show_img(1, 20, data)
這裡顯示了前20個人的第一張圖像。
2.2 使用PCA進行降維
這裡使用PCA對人臉降維,
n_components
參數設定為0.9,即主成分方差占原始資料的90%。降維後
pca = PCA(n_components=0.9)
new_data = pca.fit_transform(data)
print(data.shape)
print(new_data.shape)
data_inverse = pca.inverse_transform(new_data)
show_img(1, 20, data_inverse)
(400, 10304)
(400, 100)
可以看到原始資料次元從10304降到了100,但将降維後的資料映射回原始資料後,仍能較為清晰地分辨出人臉,說明前100個主成分特征保留了大部分資料資訊。
參考文獻
[1] https://blog.csdn.net/qq_20135597/article/details/95247381
[2] https://blog.csdn.net/program_developer/article/details/80632779