PCA對象的主要成分都保存在components_.shape屬性中,其屬性中的每一行對應一個主成分,他們按重要性來排序(第一主成分排在首位,以此類推)。列對應PCA的原始特徵屬性,如下:
print("PCA component shape: {}".format(pca.components_.shape))
print("PCA components:\n{}".format(pca.components_))
運行結果為:
PCA component shape: (2, 30)
PCA components:
[[ 0.21890244 0.10372458 0.22753729 0.22099499 0.14258969 0.23928535
0.25840048 0.26085376 0.13816696 0.06436335 0.20597878 0.01742803
0.21132592 0.20286964 0.01453145 0.17039345 0.15358979 0.1834174
0.04249842 0.10256832 0.22799663 0.10446933 0.23663968 0.22487053
0.12795256 0.21009588 0.22876753 0.25088597 0.12290456 0.13178394]
[-0.23385713 -0.05970609 -0.21518136 -0.23107671 0.18611302 0.15189161
0.06016536 -0.0347675 0.19034877 0.36657547 -0.10555215 0.08997968
-0.08945723 -0.15229263 0.20443045 0.2327159 0.19720728 0.13032156
0.183848 0.28009203 -0.21986638 -0.0454673 -0.19987843 -0.21935186
0.17230435 0.14359317 0.09796411 -0.00825724 0.14188335 0.27533947]]
我們還可以用熱圖將其數據可視化,這樣可能更加容易理解,對應代碼如下:
plt.matshow(pca.components_, cmap='viridis')
plt.yticks([0, 1], ["First component", "Second components"])
plt.colorbar()
plt.xticks(range(len(cancer.feature_names)), cancer.feature_names, rotation=60, ha='left')
plt.xlbael("feature")
plt.ylabel("principal components")
運行後結果如下:
乳腺癌數據集前兩個主成分熱圖
可以看到,在第一個主成分中,所有的特徵符號相同(均為正,但是前面我們提到過,箭頭只想那個方向無關緊要)。這意味著在所有特徵之間存在普遍性和相關性。如果一個測量值較大的話,其他測量值可能也較大。第二個主成分則有正有負,且兩個主成分都包含有30個特徵,這種所有特徵會和使得解釋其過程變得十分困難。
特徵提取的特徵臉:前面提到過,PCA的另一個應用是特徵提取,特徵提取背後的思想是,可以找到一種數據表示,比給定的原始表示更適合分析。特徵提取很有用,一個很好的應用就是圖形。因為圖像是由像素組成,通常存儲為紅藍綠(RGB)強度。不過一般圖片都是由上千個像素組成,只有將其存放到一起才有意義。
下面我們來看一個利用PCA對圖像做特徵提取的應用——處理Wild數據集Labeled faces(標記人臉)中的人臉對象。對應代碼如下:
from sklearn.datasets import fetch_lfw_people
people = fetch_lfw_people(min_faces_per_person=40, resize=0.7)
image_shape = people.images[0].shape
fix, axes = plt.subplots(2, 5,figsize=(15, 8),subplot_kw={'xticks': (), 'yticks': ()})
for target, image, ax in zip(people.target, people.images, axes.ravel()):
ax.imshow(image)
ax.set_title(people.target_names[target])
運行後結果如下:
來自Wild數據集中Labeled faces的一些圖像
我們來看看總共有多少張圖像、有多少個不同的人,並對任務出現的次數進行統計,對應的代碼如下:
for target, image, ax in zip(people.target, people.images, axes.ravel()):
ax.imshow(image)
ax.set_title(people.target_names[target])
print("the number of pictures and pixel are:{}".format(people.images.shape))
print("number of classes: {}".format(len(people.target_names)))
#計算目標出現的次數
counts = np.bincount(people.target)
#將次數與目標名稱一列印出來
for i, (count, name) in enumerate(zip(counts, people.target_names)):
print("{0:25}, {1:3}".format(name, count), end=' ')
if(i+1)%3 == 0:
print()
運行後結果如下:
labeled中出現的人物數及每個人物出現的次數
由運行結果可以看出,該數據集收錄了24個人物共1985張照片,照片的像素是87*65。
人臉識別的一個常見任務就是看某個人是否屬於資料庫中某個已知人物。這在照片收集、社交媒體和安全應用中都常用到。解決這個問題的方法之一是構建一個分類器,每個人都是一個單獨的類別,但人臉資料庫中通常有許多不同的人,而同一個人的圖像很多(也就是說,每個類別的訓練樣例很少)。這使得大多數分類器的訓練都很困難。
為了解決此類問題,我們可以使用單一的近鄰分類器,尋找與你要分類的人臉最為相似的人臉,這個分類器原則上可以處理每個類別只有一個訓練樣例的情況,我們下面來看一下KneighborsClassifier的表現如何:
mask = np.zeros(people.target.shape, dtype=np.bool)
for target in np.unique(people.target):
mask[np.where(people.target == target)[0][:50]] = 1
x_people = people.data[mask]
y_people = people.target[mask]
#將灰度值縮放到0-1之間,而不是0-255,以便得到更好的穩定性
x_people =x_people/255
from sklearn.neighbors import KNeighborsClassifier
#將數據分為訓練集和測試集
x_train , x_test, y_train, y_test = train_test_split(x_people, y_people, stratify=y_people, random_state=0)
#使用一個鄰居構建KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(x_train, y_train)
print("test set score of 1-knn: {:.2f}".format(knn.score(x_test, y_test)))
運行結果如下:
test set score of 1-knn: 0.35
由此可見,我們的預測精度為35%,對於包含24個類別的分類問題來說,其結果算是馬馬虎虎。下面我們嘗試一下通過PCA,比較兩張圖的灰度(這裡如果比較兩張的像素之間的空間距離是不行的,因為照片中像素和像素之間的空間距離不具有代表性)。
我們首先啟用PCA 的白化(whitening):mglearn.plots.plot_pca_whitening()
效果如下圖:
啟用白化的PCA對數據進行變換
由運行結果我們可以看出,PCA白化將主成分縮放到相同的尺度。變換後的結果與使用StandardScaler相同,白化不僅對應於數據旋轉,還對應於縮放數據使其形狀是圓而不是橢圓。我們訓練數據擬合PCA對象,並提取前100個主成分,然後對數據進行變換:
pca = PCA(n_components=100, whiten=True, random_state=0).fit(x_train)
x_train_pca = pca.transform(x_train)
x_test_pca = pca.transform(x_test)
#列印對應的PCA數據特徵及主成分結果
print("x_train_pca.shape: {}".format(x_train_pca.shape))
knn = KNeighborsClassifier(n_neighbors=1)
knn.fit(x_train_pca, y_train)
print("Test set accuracy: {:.2f}".format(knn.score(x_test_pca, y_test)))
運行後其精度結果如下:
Test set accuracy: 0.44
由此可以看出,通過pca選擇主要成分來進行預測時,精度有了一定的提高。