【機器學習】資料降維—主成分分析(PCA)
本文程式碼推薦使用Jupyter notebook跑,這樣得到的結果更為直觀。
主成分分析(PCA)
特徵抽取通常用於提高計算效率,降低維度災難。
主成分分析(Principe component analysis,PCA):
是一種廣泛應用於不同領域的無監督線性資料轉換技術,作用是降維。
常用領域:
股票交易市場資料的探索性分析和訊號去噪、生物資訊學領域的基因組和基因表達水平資料分析
PCA可以基於特徵之間的關係識別出資料內在模式
PCA的目標:在高維資料中找到最大方差的方向,並將資料對映到一個維度不大於原始資料的新的子空間上。
PCA圖:
新特徵的座標是相互正交為約束條件,子空間上的正交的座標軸(PC)為方差最大方向
x1和x2為原始特徵座標軸,pc1和pc2為主成分。
構建一個d x k維的轉換矩陣W,將一個樣本向量x對映到一個新的k維特徵子空間上,此空間維度小於原始的d維特徵空間。
完成從原始的d維資料到新的k維子空間轉換後,第一主成分的方差應該最大,由於各主成分是正交的,後續主成分也可能具備更大方差。
主成分方向對資料值的範圍高度敏感,如果特徵值不同維度應該先對特徵標準化處理,讓各特徵具有相同的重要性。
PCA演算法流程:
1、 對原始d維資料集做標準化
2、 構造樣本的協方差矩陣
3、 計算協方差矩陣的特徵值和相應的特徵向量
4、 選擇與前k個最大特徵值對應的特徵向量
5、 通過前k個特徵向量構建對映矩陣W
6、 通過對映矩陣W將d維的輸入資料集X轉換到新的k維特徵子空間
第一步,載入資料集,標準化資料集。
# 載入葡萄酒資料集 import pandas as pd df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None) # 將資料分成70%的培訓和30%的測試子集。 from sklearn.cross_validation import train_test_split X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values X_train, X_test, y_train, y_test = \ train_test_split(X, y, test_size=0.3, random_state=0) # 使用單位方差標準化 from sklearn.preprocessing import StandardScaler sc = StandardScaler() X_train_std = sc.fit_transform(X_train) X_test_std = sc.fit_transform(X_test)
第二步,構造協方差矩陣,dxd維協方差矩陣是沿對角線對稱,d為資料集的維度,矩陣儲存了不同特徵之間的協方差。
協方差公式:
μj和μk分別為特徵j和k的均值。
標準化後均值為0。
兩個特徵之間的協方差為正,則兩個特徵同時遞減。
協方差為負,則兩個特徵反向移動
協方差矩陣的特徵向量代表主成分,對應的特徵值大小決定特徵向量的重要性。
# 協方差矩陣的特徵分解,計算資料集協方差矩陣的特徵對。
import numpy as np
cov_mat = np.cov(X_train_std.T)
eigen_vals, eigen_vecs = np.linalg.eig(cov_mat)
print('\nEigenvalues \n%s' % eigen_vals)
cov函式得到標準化處理的訓練集協方差矩陣
eig函式進行特徵分解,得到特徵向量及其對應的特徵值。
只選擇包含最多資訊的特徵向量組成子集。
特徵值決定了特徵向量的重要性,需要將特徵值按降序排列,取排序在前k的特徵值對應的特徵向量。
繪製特徵值的方差貢獻率影象,某個特徵值與所有特徵值和的比較
# 使用NumPy的cumsum函式,計算累計方差。
tot = sum(eigen_vals)
var_exp = [(i / tot) for i in sorted(eigen_vals, reverse=True)]
cum_var_exp = np.cumsum(var_exp)
# 通過Plo的step繪製
import matplotlib.pyplot as plt
%matplotlib inline
plt.bar(range(1, 14), var_exp, alpha=0.5, align='center',
label='individual explained variance')
plt.step(range(1, 14), cum_var_exp, where='mid',
label='cumulative explained variance')
plt.ylabel('Explained variance ratio')
plt.xlabel('Principal components')
plt.legend(loc='best')
plt.tight_layout()
# plt.savefig('./figures/pca1.png', dpi=300)
plt.show()
第一主成分佔方差總和40%,前兩個主成分佔比近60%
PCA是一種無監督方法,可以忽略類標資訊
隨機森林通過類標資訊計算節點的不純度,方差度量的是特徵值在軸線是的分佈。
# 按特徵值的降序排列特徵對
# 列出(特徵值,特徵向量)元組。
eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:,i]) for i in range(len(eigen_vals))]
# 從高到低排序(特徵值,特徵向量)元組。
eigen_pairs.sort(reverse=True)
# 本案例只選擇前60%的兩個特徵向量
w = np.hstack((eigen_pairs[0][1][:, np.newaxis],
eigen_pairs[1][1][:, np.newaxis]))
print('Matrix W:\n', w)
# 通過計算矩陣點積,將整個訓練集轉換到包含兩個主成分的子空間上。
X_train_pca = X_train_std.dot(w)
# 視覺化
colors = ['r', 'b', 'g']
markers = ['s', 'x', 'o']
for l, c, m in zip(np.unique(y_train), colors, markers):
plt.scatter(X_train_pca[y_train==l, 0],
X_train_pca[y_train==l, 1],
c=c, label=l, marker=m)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
# plt.savefig('./figures/pca2.png', dpi=300)
plt.show()
# 使用Scikit-learn進行主成分分析
from sklearn.decomposition import PCA
pca = PCA()
X_train_pca = pca.fit_transform(X_train_std)
# pca.explained_variance_ratio_
plt.bar(range(1, 14), pca.explained_variance_ratio_, alpha=0.5, align='center')
plt.step(range(1, 14), np.cumsum(pca.explained_variance_ratio_), where='mid')
plt.ylabel('Explained variance ratio')
plt.xlabel('Principal components')
plt.show()
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train_std)
X_test_pca = pca.transform(X_test_std)
plt.scatter(X_train_pca[:,0], X_train_pca[:,1])
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.show()
# 使用plot_decision_regions函式進行視覺化決策區域
from matplotlib.colors import ListedColormap
def plot_decision_regions(X, y, classifier, resolution=0.02):
#設定標記生成器和顏色對映。
markers = ('s', 'x', 'o', '^', 'v')
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
cmap = ListedColormap(colors[:len(np.unique(y))])
# plot 決定表面
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
np.arange(x2_min, x2_max, resolution))
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
# plot 類樣本
for idx, cl in enumerate(np.unique(y)):
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
alpha=0.8, c=cmap(idx),
marker=markers[idx], label=cl)
# 使用前兩個主要元件訓練邏輯迴歸分類器
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr = lr.fit(X_train_pca, y_train)
plot_decision_regions(X_train_pca, y_train, classifier=lr)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
# plt.savefig('./figures/pca3.png', dpi=300)
plt.show()
SKlearn實現的PCA和之前實現的PCA是經過y軸旋轉後的。
特徵分析方法:特徵向量可以為正或者為負
有時候需要乘上-1在實現影象的映象。
# 繪製邏輯迴歸在轉換後的測試資料上得到的決策區域
plot_decision_regions(X_test_pca, y_test, classifier=lr)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.legend(loc='lower left')
plt.tight_layout()
# plt.savefig('./figures/pca4.png', dpi=300)
plt.show()
# 獲取相應的方差貢獻率
pca = PCA(n_components=None)
X_train_pca = pca.fit_transform(X_train_std)
pca.explained_variance_ratio_