【机器学习】降维技术-PCA
寫在篇前
??PCA即主成分分析技術,又稱主分量分析,旨在利用降維的思想,把多指標轉化為少數幾個綜合指標,其主要目的是為了減少數據的維數,而同時保持數據集最多的信息。這篇文章主要是整理PCA算法的理論、思想,然后通過Scikit-learn中的例子講解PCA的使用。
數學基礎
??首先,我們需要了解幾個重要的數學概念,其中均值、標準差、方差協方差應該是比較好理解的,主要是要注意對特征向量和特征值的理解。關于更詳細的數學原理,可以直接參考博客 PCA的數學原理
均值(mean)
Xˉ=∑i=1nXin\bar{X} = \frac{\sum_{i=1}^nX_i}{n} Xˉ=n∑i=1n?Xi??
- \bar{X}:均值
- X_i:樣本數據
- nnn:樣本數
標準差(std)
?衡量隨機變量與其數學期望(均值)之間的偏離程度,注意區分樣本方差、總體方差
s=∑i=1n(Xi?Xˉ)2n?1s = \sqrt{\frac{\sum_{i=1}^n(X_i-\bar{X})^2}{n-1}} s=n?1∑i=1n?(Xi??Xˉ)2??
方差(var)
?衡量隨機變量與其數學期望(均值)之間的偏離程度
s2=∑i=1n(Xi?Xˉ)2n?1s^2 = \frac{\sum_{i=1}^n(X_i-\bar{X})^2}{n-1} s2=n?1∑i=1n?(Xi??Xˉ)2?
協方差(cov)
?衡量變量之間的相關性,協方差為0時,表示兩隨機變量不相關,>0表示正相關,反之負相關
cov(X,Y)=∑i=1n(Xi?Xˉ)(Yi?Yˉ)n?1cov(X,Y) = \frac{\sum_{i=1}^n(X_i-\bar{X})(Y_i-\bar{Y})}{n-1} cov(X,Y)=n?1∑i=1n?(Xi??Xˉ)(Yi??Yˉ)?
C=(cov(1,1)cov(1,2)cov(1,3)?cov(1,n)cov(2,1)cov(2,2)cov(2,3)?cov(2,n)cov(3,1)cov(3,2)cov(3,3)?cov(3,n)?????cov(n,1)cov(n,2)cov(n,3)?cov(n,n))C = \begin{pmatrix} \color{#F00}{cov(1,1)} & \color{#0F0}{cov(1,2)} & \color{#F0F}{cov(1,3)} & \cdots & cov(1,n) \\ \color{#0F0}{cov(2,1)} & \color{#F00}{cov(2,2)} & cov(2,3) & \cdots & cov(2,n) \\ \color{#F0F}{cov(3,1)} & cov(3,2) &\color{#F00}{cov(3,3)} & \cdots & cov(3,n) \\ \vdots & \vdots& \vdots & \ddots & \vdots \\ cov(n,1) & cov(n,2) & cov(n,3) & \cdots & \color{#F00}{cov(n,n)} \end{pmatrix} C=????????cov(1,1)cov(2,1)cov(3,1)?cov(n,1)?cov(1,2)cov(2,2)cov(3,2)?cov(n,2)?cov(1,3)cov(2,3)cov(3,3)?cov(n,3)???????cov(1,n)cov(2,n)cov(3,n)?cov(n,n)?????????
特征向量(Eigenvectors)和特征值(Eigenvalues)
Av=λvA是一個方陣,λ是一個標量。此處λ是特征值,v是特征向量Av = \lambda v \qquad A是一個方陣,\lambda是一個標量。此處\lambda是特征值,v是特征向量 Av=λvA是一個方陣,λ是一個標量。此處λ是特征值,v是特征向量
需要注意的是,只有方陣才能求出特征向量,但是,并不是每個方陣都有特征向量。假設我有一個n * n的矩陣,那么就有n個特征向量,并且一個矩陣中的所有特征向量都是相互垂直的,無論你的數據集中有多少特征。
實現PCA
???上面數學概念解釋比較模糊,具體一定要參考博客PCA的數學原理,下面用一個實例來實現PCA,數據集我們采用有名的Wine數據集
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler import numpy as np import matplotlib.pyplot as pltdf_wine = pd.read_csv('./wine', header=None) # 請自行下載數據 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) # 歸一化,mean=0, var=1 sc = StandardScaler() X_train_std = sc.fit_transform(X_train) X_test_std = sc.fit_transform(X_test)# 計算協方差,需要轉置,注意理解 X_train_std_cov = np.cov(X_train_std.T) # (13, 13) eigen_vals, eigen_vecs = np.linalg.eig(X_train_std_cov) # (13,) 、(13, 13) draw_cum_explained_var(eigen_vals)eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i]) for i in range(len(eigen_vals))] # 把特征值和對應的特征向量組成對 eigen_pairs.sort(reverse=True) # 用特征值排序 first = eigen_pairs[0][1] second = eigen_pairs[1][1] first = first[:, np.newaxis] second = second[:, np.newaxis] W = np.hstack((first, second)) # 映射矩陣W.shape:13×2X_train_pca = X_train_std.dot(W) # 轉換訓練集 draw_PCA_res(X_train_pca, y_train) draw_PCA_res(X_test_std.dot(W), y_test)上面我們使用了兩個繪圖函數,代碼如下:
def draw_cum_explained_var(eigen_vals):"""繪制累計方差貢獻率圖:param eigen_vals: numpy 特征值:return:"""total = sum(eigen_vals) # 求出特征值的和var_exp = [(i / total) for i in sorted(eigen_vals, reverse=True)] # 求出每個特征值占的比例(降序)cum_var_exp = np.cumsum(var_exp) # 返回var_exp的累積和plt.bar(range(len(eigen_vals)), var_exp, width=1.0, bottom=0.0, alpha=0.5, label='individual explained variance')plt.step(range(len(eigen_vals)), cum_var_exp, where='post', label='cumulative explained variance')plt.ylabel('Explained variance ratio')plt.xlabel('Principal components')plt.legend(loc='best')plt.show()def draw_PCA_res(data_pca, labes):"""繪制pca結果圖:param data_pca: pca映射后的數據:param labes: 標簽:return:"""colors = ['r', 'b', 'g']markers = ['s', 'x', 'o']for l, c, m in zip(np.unique(labes), colors, markers):plt.scatter(data_pca[labes == l, 0], data_pca[labes == l, 1],c=c, label=l, marker=m) # 散點圖plt.xlabel('PC 1')plt.ylabel('PC 2')plt.legend(loc='lower left')plt.show()?
Fig1:累計方差貢獻圖
?
Fig2:訓練數據PCA圖
?
Fig3.測試集PCA圖
SKlearn實例
Basic-PCA
??我們先來看看在sklearn中,PCA Model 的基本屬性:
from sklearn import datasets from sklearn.decomposition import PCAiris = datasets.load_iris()X = iris.data y = iris.target target_names = iris.target_namespca = PCA(n_components=None) # fit方法就相當于訓練,通過訓練建立有效模型 pca.fit(X)# pca object的一些函數 # print('get_covariance', pca.get_covariance()) # 獲取協方差矩陣 # print('get_precision', pca.get_precision()) # print('get_params', pca.get_params()) # 獲取pca參數,于set_params對應 # print('get_score', pca.score(X)) # 平均得分 # print('get_score_samples', pca.score_samples(X)) # 得分矩陣# pca object的一些屬性 print('n_samples_: %s' % str(pca.n_samples_)) # 樣本數 print('n_features_: %s' % str(pca.n_features_)) # 特征數 print('mean_: %s' % str(pca.mean_)) # 均值 print('n_components: %s' % str(pca.n_components)) # 函數調用參數的值n_components print('n_components_: %s' % str(pca.n_components_)) # 實際n_components的值 print('explained variance ratio: %s' % str(pca.explained_variance_ratio_)) # 方差貢獻率 print('explained_variance_: %s' % str(pca.explained_variance_)) # 方差貢獻# 下面的參數均來自pca = PCA(n_components=None)初始化的參數值 print('copy: %s' % str(pca.copy)) print('iterated_power: %s' % str(pca.iterated_power)) print('whiten: %s' % str(pca.whiten)) print('random_state: %s' % str(pca.random_state)) print('noise_variance_: %s' % str(pca.noise_variance_)) print('singular_values_: %s' % str(pca.singular_values_)) print('svd_solver: %s' % str(pca.svd_solver)) print('tol: %s' % str(pca.tol))# n_samples_: 150 # n_features_: 4 # mean_: [5.84333333 3.054 3.75866667 1.19866667] # n_components: None # n_components_: 4 # explained variance ratio: [0.92461621 0.05301557 0.01718514 0.00518309] # explained_variance_: [4.22484077 0.24224357 0.07852391 0.02368303] # copy: True # iterated_power: auto # whiten: False # random_state: None # noise_variance_: 0.0 # singular_values_: [25.08986398 6.00785254 3.42053538 1.87850234] # svd_solver: auto # tol: 0.0??既然我們已經建立好了PCA Model,那我們繼續利用Model可視化我們的pca結果:
X_r = pca.transform(X) # transform函數將數據X應用于模型,實際上就是完成了映射過程# 繪圖可視化 plt.figure() colors = ['navy', 'turquoise', 'darkorange'] lw = 2 for color, i, target_name in zip(colors, [0, 1, 2], target_names):plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, alpha=.8, lw=lw,label=target_name) plt.legend(loc='best', shadow=False, scatterpoints=1) plt.title('PCA of IRIS dataset') plt.show() 
Fig4.iris-PCA
Incremental-PCA
??這個PCA模式(對,我稱之為模式)對熟悉深度學習的同學應該非常熟悉,就是設置一個batch-size,一個batch,一個batch來訓練,為什么?因為有時候數據集很大,主機內存不夠,這個時候我們就應該采取這個策略。貼一個 toy example
""" IncrementalPCA makes it possible to implement out-of-core Principal Component Analysis either by:1、Using its partial_fit method on chunks of data fetched sequentially from the local harddrive or a network database.2、Calling its fit method on a memory mapped file using numpy.memmap. """import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.decomposition import PCA, IncrementalPCAiris = load_iris() X = iris.data y = iris.targetn_components = 2 ipca = IncrementalPCA(n_components=n_components, batch_size=10) X_ipca = ipca.fit_transform(X) pca = PCA(n_components=n_components) X_pca = pca.fit_transform(X)colors = ['navy', 'turquoise', 'darkorange']for X_transformed, title in [(X_ipca, "Incremental PCA"), (X_pca, "PCA")]:plt.figure(figsize=(8, 8))for color, i, target_name in zip(colors, [0, 1, 2], iris.target_names):plt.scatter(X_transformed[y == i, 0], X_transformed[y == i, 1],color=color, lw=2, label=target_name)if "Incremental" in title:err = np.abs(np.abs(X_pca) - np.abs(X_ipca)).mean()plt.title(title + " of iris dataset\nMean absolute unsigned error ""%.6f" % err)else:plt.title(title + " of iris dataset")plt.legend(loc="best", shadow=False, scatterpoints=1)plt.axis([-4, 4, -1.5, 1.5])plt.show()Kernel-PCA
??Kernel-PCA是PCA的擴展,通過使用內核實現非線性降維,這個其實有點類似SVM,先升維再降維,它有許多應用,包括去噪,壓縮和結構化預測。同樣,貼一個例子
#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/11/7 16:15'import numpy as np import matplotlib.pyplot as pltfrom sklearn.decomposition import PCA, KernelPCA from sklearn.datasets import make_circlesnp.random.seed(0)X, y = make_circles(n_samples=400, factor=.3, noise=.05)kpca = KernelPCA(kernel="rbf", fit_inverse_transform=True, gamma=10) X_kpca = kpca.fit_transform(X) X_back = kpca.inverse_transform(X_kpca)pca = PCA() X_pca = pca.fit_transform(X)# Plot resultsplt.figure() plt.subplot(2, 2, 1, aspect='equal') plt.title("Original space") reds = y == 0 blues = y == 1plt.scatter(X[reds, 0], X[reds, 1], c="red",s=20, edgecolor='k') plt.scatter(X[blues, 0], X[blues, 1], c="blue",s=20, edgecolor='k') plt.xlabel("$x_1$") plt.ylabel("$x_2$")# 構建平面采樣點 X1, X2 = np.meshgrid(np.linspace(-1.5, 1.5, 50), np.linspace(-1.5, 1.5, 50)) X_grid = np.array([np.ravel(X1), np.ravel(X2)]).T # (2500, 2)# 空間投射 Z_grid = kpca.transform(X_grid)[:, 1].reshape(X1.shape) # 原Z_grid.shape (2500, 393) plt.contour(X1, X2, Z_grid, colors='grey', linewidths=1, origin='lower') plt.subplot(2, 2, 2, aspect='equal') plt.scatter(X_pca[reds, 0], X_pca[reds, 1], c="red",s=20, edgecolor='k') plt.scatter(X_pca[blues, 0], X_pca[blues, 1], c="blue",s=20, edgecolor='k') plt.title("Projection by PCA") plt.xlabel("1st principal component") plt.ylabel("2nd component")plt.subplot(2, 2, 3, aspect='equal') plt.scatter(X_kpca[reds, 0], X_kpca[reds, 1], c="red",s=20, edgecolor='k') plt.scatter(X_kpca[blues, 0], X_kpca[blues, 1], c="blue",s=20, edgecolor='k') plt.title("Projection by KPCA") plt.xlabel("1st principal component in space induced by $\phi$") plt.ylabel("2nd component")plt.subplot(2, 2, 4, aspect='equal') plt.scatter(X_back[reds, 0], X_back[reds, 1], c="red",s=20, edgecolor='k') plt.scatter(X_back[blues, 0], X_back[blues, 1], c="blue",s=20, edgecolor='k') plt.title("Original space after inverse transform") plt.xlabel("$x_1$") plt.ylabel("$x_2$")plt.subplots_adjust(0.02, 0.10, 0.98, 0.94, 0.04, 0.35)plt.show()其他
??SKlearn中還實現了MiniBatchSparsePCA, SparsePCA, RandomizedPCA。
- RandomizedPCA, 這個就是樸素PCA參數中svd_solver=randomized,我們默認是auto
- SparsePCA 是樸素PCA的一個變種,處理稀疏數據,常與SparsePCACoder連用。參考06年論文:Sparse principal component analysis
- MiniBatchSparsePCA,是SparsePCA ,支持minibatch
寫在篇后
??在本篇中,我們介紹了PCA相關的核心數學概念、手動實現PCA,以及SKlearn中實現的PCA算法,包括PCA、IncrementalPCA、 KernelPCA、MiniBatchSparsePCA, SparsePCA, RandomizedPCA。
總結
以上是生活随笔為你收集整理的【机器学习】降维技术-PCA的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Numpy学习记录】np.cov详解
- 下一篇: 【机器学习】Kmeans聚类