1. 程式人生 > >【機器學習】資料降維—主成分分析(PCA)

【機器學習】資料降維—主成分分析(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個最大特徵值對應的特徵向量

,其中k為新特徵空間維度(k<=d)

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_