ML10-PCA算法

PCA應(yīng)該是算法中比較簡單的算法之一,本主題主要介紹PCA的算法模型,應(yīng)用與數(shù)學(xué)基礎(chǔ);
??1. PCA算法與模型介紹;
??2.PCA算法的應(yīng)用;
??3.PCA數(shù)學(xué)基礎(chǔ)與相關(guān)概念;


PCA算法介紹

PCA(Principal Component Analysis)

  • PCA稱主成分分析,是一種常用的數(shù)據(jù)分析方法。
  • PCA的主要結(jié)果是降維,降低原始數(shù)據(jù)的維數(shù);
  • PCA降維的目的是去掉原始數(shù)據(jù)中不重要的特征(或者去掉相關(guān)的特征),保留重要特征。(或者去掉相關(guān)的特征,保留不相關(guān)特征)
  • PCA降維的數(shù)學(xué)理論是通過線性變換將原始數(shù)據(jù)變換為一組各維度線性無關(guān)的表示。

降維應(yīng)用背景介紹

  1. 降維背景說明
    • 在機器學(xué)習(xí)的很多應(yīng)用場景中(尤其是基于統(tǒng)計學(xué)習(xí)的機器學(xué)習(xí)中),從特征維度與數(shù)量,都需要盡量可能的多,多維度的特征與海量的數(shù)據(jù)包含更加豐富的信息;然后才能通過機器學(xué)習(xí)訓(xùn)練出更加可靠的規(guī)律與結(jié)果。

    • 多特證與海量數(shù)據(jù)的要求提高了數(shù)據(jù)采集的難度。更重要的是在很多情形下,許多特征之間可能存在相關(guān)性,從而增加了問題分析的復(fù)雜性,影響機器學(xué)習(xí)的效率,提高機器學(xué)習(xí)的成本。

    • 數(shù)據(jù)樣本中很多特征不是孤立的,盲目去除某些特征,就不能充分利用數(shù)據(jù)中的信息,會損失很多有用的信息,從而產(chǎn)生錯誤的結(jié)論。

    • 因此需要找到一種合理的方法,既減少需要分析特征,又減少原特征包含信息的損失,從而從分利用已經(jīng)采集的數(shù)據(jù)。

    • 由于各特征之間存在一定的相關(guān)關(guān)系,因此盡可能的對特征進(jìn)行融合。使得新特征維數(shù)減少,同時又不相關(guān),而且還盡量包含原始特征的信息。

  1. 降維的作用
    • 降維就是一種對高維特征數(shù)據(jù)預(yù)處理方法,是非常廣泛的數(shù)據(jù)預(yù)處理方法;降維是將高維度的數(shù)據(jù)保留下最重要的一些特征,去除噪聲(干擾結(jié)果的數(shù)據(jù))和不重要的特征; 降維可以提升數(shù)據(jù)處理速度;在實際的生產(chǎn)和應(yīng)用中,降維在一定的信息損失范圍內(nèi),可以為我們節(jié)省大量的時間和成本。作妖作用歸納如下:
      • 使得數(shù)據(jù)集更易使用。
      • 降低算法的計算開銷。
      • 去除噪聲。
      • 使得結(jié)果容易理解。

數(shù)據(jù)降維的技術(shù)

  • 降維的算法有很多,主要有:
    • 奇異值分解(SVD)
    • 主成分分析(PCA)
    • 因子分析(FA)
    • 獨立成分分析(ICA)
  • 提示
    • 這里主要講解PCA

Sklearn的PCA實現(xiàn)的應(yīng)用

  • 在sklearn中已經(jīng)提供PCA方法的實現(xiàn)

PCA定義

  1. PCA類的定義說明

    class sklearn.decomposition.PCA(
        n_components=None,     # 指定保留的特征數(shù)量(降維以后的維數(shù))
        copy=True,                    # 訓(xùn)練過程中是否影響原始樣本數(shù)據(jù),也影響到最后降維數(shù)據(jù)的返回方式
        whiten=False,                # 是否對降維后的數(shù)據(jù)提供白化處理。(白化就是每一維的特征做一個標(biāo)準(zhǔn)差歸一化處理,除以一個標(biāo)準(zhǔn)偏差) 
        svd_solver=’auto’,          #  SVD分解的計算方法
        tol=0.0,                         # 計算奇異值的公差
        iterated_power=’auto’,    # 采用svd_solver采用randomized方式的迭代次數(shù)。
        random_state=None)      # 同來創(chuàng)建隨機數(shù)的實例,比如隨機種

  1. PCA參數(shù)說明

    • n_components : int, float, None or string

      • int:指定降維以后的維數(shù),如果不設(shè)置,則降維維數(shù)維去原始數(shù)據(jù)維數(shù)與樣本數(shù)的最小值:n_components == min(n_samples, n_features);

        • 如果svd_solver == 'arpack',則 n_components必須嚴(yán)格小于min(n_samples, n_features)
      • float:當(dāng)svd_solver == 'full'時,選擇的特征數(shù)大于n_components指定的百分比。

      • string:n_components == 'mle' 且svd_solver == 'full',使用Minka的MLE算法估算n_components的值。

      • None:n_components == min(n_samples, n_features) - 1

    • copy : bool (default True),

      • False:返回降維數(shù)據(jù)使用:fit_transform(X)
      • True:返回降維數(shù)據(jù)使用:fit(X).transform(X)
    • whiten : bool, optional (default False)

      • 降維后的數(shù)據(jù)進(jìn)行白化處理(標(biāo)準(zhǔn)差歸一化處理)。
    • svd_solver : string {‘a(chǎn)uto’, ‘full’, ‘a(chǎn)rpack’, ‘randomized’}

      • auto:根據(jù)基于x.shape和n_components選擇svd_solver:
        • 如果輸入數(shù)據(jù)大于500x500且要選擇的特征維數(shù)小于數(shù)據(jù)最小維數(shù)的80%,則使用更有效的“randomized”方法。
        • 否則完全使用SVD,并選擇性地選擇特征。
      • full:調(diào)用scipy.linalg.svd執(zhí)行svd奇異值分解,然后選擇特征
      • arpack:調(diào)用scipy.sparse.linalg.svds進(jìn)行奇異值分解,然后選擇特征;嚴(yán)格要求:0 < n_components < min(X.shape)
      • randomized:采用Halko的隨機SVD(隨機奇異值分解)
    • tol : float >= 0, optional (default .0)

      • 公差:在svd_solver == ‘a(chǎn)rpack’計算奇異值方法中需要使用的公差。
    • iterated_power : int >= 0, or ‘a(chǎn)uto’, (default ‘a(chǎn)uto’)

      • 使用svd_solver == ‘randomized’計算SVD需要用到的冪法迭代次數(shù)。
    • random_state : int, RandomState instance or None, optional (default None)

      • 如果為int,則隨機數(shù)生成器使用的種子;如果為random state實例,則隨機數(shù)生成器為randomstate;如果為none,則隨機數(shù)生成器為np.random使用的randomstate實例。當(dāng)svd_solver=='arpack'或'randomized'時使用。
  • 提示:
    • 盡管上面參數(shù)顯得有點復(fù)雜,并涉及數(shù)學(xué)計算的概念,但大部分情況下,除了第一個參數(shù),其他參數(shù)我們采用默認(rèn)參數(shù)即可。
  1. PCA主要方法與函數(shù)
    • 下面的所有y參數(shù)都是沒有意義,或者被忽略。這是sklearn統(tǒng)一調(diào)用接口的結(jié)果(屬于設(shè)計模式導(dǎo)致的瑕疵)。
  • fit(X[, y])
    • 訓(xùn)練數(shù)據(jù)。返回PCA對象
  • transform(X)
    • 使用訓(xùn)練的結(jié)果,對X降維
  • fit_transform(X[, y])
    • 訓(xùn)練數(shù)據(jù),并應(yīng)用降維到X。
  • get_covariance()
    -計算數(shù)據(jù)協(xié)方差( 用生成模型)。
  • get_precision()
    • 計算數(shù)據(jù)精度矩陣( 用生成模型)。
  • inverse_transform(X)
    • 計算降維以后的原始數(shù)據(jù)
  • score(X[, y])
    • 計算所有樣本的log似然平均值。
  • score_samples(X)
    • 返回每個樣本的對數(shù)似然值。
  • set_params(**params)
    • 設(shè)置PCA的參數(shù)。
  • get_params([deep])
    • 得到PCA的參數(shù)

PCA應(yīng)用

% matplotlib inline
import matplotlib.pyplot as plt
import sklearn.datasets  as ds
import sklearn.decomposition  as de

# 加載數(shù)據(jù)集
data, target = ds.load_iris(return_X_y=True)

# 構(gòu)建PCA對象
pca = de.PCA(n_components=2)   #, svd_solver='arpack',copy=True)
# 訓(xùn)練數(shù)據(jù)
pca.fit(data)    # 返回pca本身

# 對數(shù)據(jù)降維
# data_de = pca.transform(data)
# data_de = pca.fit_transform(data)
data_de

# 數(shù)據(jù)可視化
fig = plt.figure('PCA降維', figsize=(6, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])

ax.scatter(data_de[0:50, 0], data_de[0:50:, 1], s=9, c='r')
ax.scatter(data_de[50:100, 0], data_de[50:100:, 1], s=9, c='g')
ax.scatter(data_de[100:150, 0], data_de[100:150:, 1], s=9, c='b')

plt.show()

IRIS數(shù)據(jù)集降維以后的可視化效果
print(pca.get_precision())
print('-------')
print(pca.get_covariance())
print('-------')
print(pca.singular_values_)
print('-------')
print(pca.explained_variance_)
print('-------')
print(pca.explained_variance_ratio_)
print('-------')
print(pca.noise_variance_)

# 均值處理
print(np.mean(data_de))
[[10.38525514 -6.82204502 -4.20572606 -1.7510368 ]
 [-6.82204502 11.21577598  3.34261     1.41240052]
 [-4.20572606  3.34261     4.90734692 -6.14476038]
 [-1.7510368   1.41240052 -6.14476038 16.99268128]]
-------
[[ 0.67919741 -0.03258618  1.27066452  0.5321852 ]
 [-0.03258618  0.18113034 -0.31863564 -0.13363564]
 [ 1.27066452 -0.31863564  3.11934547  1.28541527]
 [ 0.5321852  -0.13363564  1.28541527  0.58961806]]
-------
[25.08986398  6.00785254]
-------
[4.22484077 0.24224357]
-------
[0.92461621 0.05301557]
-------
0.05110346761007829
1.5395092608135505e-16
  • 降維后的數(shù)據(jù)再用于其他機器學(xué)習(xí)算法,可以提高計算速度,降低計算成本。

PCA算法模型

數(shù)據(jù)與符號表示

  • 假設(shè)數(shù)據(jù)樣本為(m, n),特征維數(shù)是n,樣本總數(shù)是m

X = \begin{bmatrix} {x_{11}}&{x_{12}}&{\cdots}&{x_{1n}}\\ {x_{21}}&{x_{22}}&{\cdots}&{x_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {x_{m1}}&{x_{m2}}&{\cdots}&{x_{mn}}\\ \end{bmatrix} = \begin{bmatrix} {X_{1}}\\ {X_{2}}\\ {\vdots}\\ {X_{m}}\\ \end{bmatrix}

  • 其中

    • X表示所有樣本形成的矩陣。
    • X_i標(biāo)識一個具有n維特征的樣本。
    • 整個數(shù)據(jù)集樣本個數(shù)是m個。
    • x_{ij}表示第i個樣本的第j個特征。
  • 如果使用特征來表示

X = \begin{bmatrix} {x_{11}}&{x_{12}}&{\cdots}&{x_{1n}}\\ {x_{21}}&{x_{22}}&{\cdots}&{x_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {x_{m1}}&{x_{m2}}&{\cdots}&{x_{mn}}\\ \end{bmatrix} = \begin{bmatrix} {Y_{1}}&{Y_{2}}&{\vdots}&{Y_{n}} \end{bmatrix}

  • 其中
    • X表示所有樣本形成的矩陣。
    • Y_i標(biāo)識一個具有m樣本的特征變量。
    • 整個數(shù)據(jù)集樣本特征維數(shù)是n個。

數(shù)據(jù)樣本例子

  • 鳶尾花數(shù)據(jù)集
import sklearn.datasets  as ds

# 加載數(shù)據(jù)集
data, target = ds.load_iris(return_X_y=True)
data.shape    # 150就是樣本個數(shù),4就是特征維數(shù),每一行表示一個樣本,每列表示一個特征
(150, 4)

協(xié)方差矩陣模型

協(xié)方差模型公式

  • 假設(shè)Y_i, Y_j是表示兩個樣本總數(shù)為m的特征(再數(shù)學(xué)上稱呼為特征變量)。

cov(Y_i, Y_j) = \dfrac {\sum \limits _{k=1} ^{m} (Y_{ik} - \bar{Y_i})(Y_{jk} - \bar{Y_j}) } {m-1}

  • 如果使用向量或者矩陣表示,則是下面公式

cov(Y_i, Y_j)= \dfrac{(Y_i-\bar{Y_i})(Y_j - \bar{Y_j})^T}{m-1}

協(xié)方差實現(xiàn)

import sklearn.datasets  as ds
import numpy as np

# 加載數(shù)據(jù)集
data, target = ds.load_iris(return_X_y=True)

# 取前面兩個特征做例子
Y_0 = data[:,0]
Y_1 = data[:,1]
Y_0,Y_1
(array([5.1, 4.9, 4.7, 4.6, 5. , 5.4, 4.6, 5. , 4.4, 4.9, 5.4, 4.8, 4.8,
        4.3, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 4.6, 5.1, 4.8, 5. ,
        5. , 5.2, 5.2, 4.7, 4.8, 5.4, 5.2, 5.5, 4.9, 5. , 5.5, 4.9, 4.4,
        5.1, 5. , 4.5, 4.4, 5. , 5.1, 4.8, 5.1, 4.6, 5.3, 5. , 7. , 6.4,
        6.9, 5.5, 6.5, 5.7, 6.3, 4.9, 6.6, 5.2, 5. , 5.9, 6. , 6.1, 5.6,
        6.7, 5.6, 5.8, 6.2, 5.6, 5.9, 6.1, 6.3, 6.1, 6.4, 6.6, 6.8, 6.7,
        6. , 5.7, 5.5, 5.5, 5.8, 6. , 5.4, 6. , 6.7, 6.3, 5.6, 5.5, 5.5,
        6.1, 5.8, 5. , 5.6, 5.7, 5.7, 6.2, 5.1, 5.7, 6.3, 5.8, 7.1, 6.3,
        6.5, 7.6, 4.9, 7.3, 6.7, 7.2, 6.5, 6.4, 6.8, 5.7, 5.8, 6.4, 6.5,
        7.7, 7.7, 6. , 6.9, 5.6, 7.7, 6.3, 6.7, 7.2, 6.2, 6.1, 6.4, 7.2,
        7.4, 7.9, 6.4, 6.3, 6.1, 7.7, 6.3, 6.4, 6. , 6.9, 6.7, 6.9, 5.8,
        6.8, 6.7, 6.7, 6.3, 6.5, 6.2, 5.9]),
 array([3.5, 3. , 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3. ,
        3. , 4. , 4.4, 3.9, 3.5, 3.8, 3.8, 3.4, 3.7, 3.6, 3.3, 3.4, 3. ,
        3.4, 3.5, 3.4, 3.2, 3.1, 3.4, 4.1, 4.2, 3.1, 3.2, 3.5, 3.1, 3. ,
        3.4, 3.5, 2.3, 3.2, 3.5, 3.8, 3. , 3.8, 3.2, 3.7, 3.3, 3.2, 3.2,
        3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7, 2. , 3. , 2.2, 2.9, 2.9,
        3.1, 3. , 2.7, 2.2, 2.5, 3.2, 2.8, 2.5, 2.8, 2.9, 3. , 2.8, 3. ,
        2.9, 2.6, 2.4, 2.4, 2.7, 2.7, 3. , 3.4, 3.1, 2.3, 3. , 2.5, 2.6,
        3. , 2.6, 2.3, 2.7, 3. , 2.9, 2.9, 2.5, 2.8, 3.3, 2.7, 3. , 2.9,
        3. , 3. , 2.5, 2.9, 2.5, 3.6, 3.2, 2.7, 3. , 2.5, 2.8, 3.2, 3. ,
        3.8, 2.6, 2.2, 3.2, 2.8, 2.8, 2.7, 3.3, 3.2, 2.8, 3. , 2.8, 3. ,
        2.8, 3.8, 2.8, 2.8, 2.6, 3. , 3.4, 3.1, 3. , 3.1, 3.1, 3.1, 2.7,
        3.2, 3.3, 3. , 2.5, 3. , 3.4, 3. ]))
# 計算平均值
Y_0_mean = np.mean(Y_0)   # 按照行計算均值(就是樣本均值)
Y_1_mean = np.mean(Y_1) 
Y_0_mean,Y_1_mean
(5.843333333333334, 3.0540000000000003)
# 中心化(中心化以后的樣本均值為0:因為誤差,實際計算中是接近0)
Y_0 = Y_0 - Y_0_mean     
Y_1 = Y_1 - Y_1_mean
Y_0.shape, Y_1.shape
((150,), (150,))
# 計算協(xié)方差
cv = np.dot(Y_0, Y_1)/(len(Y_0)-1)
cv
-0.03926845637583892
# numpy的計算結(jié)果
# 注意下面計算的結(jié)果是協(xié)方差矩陣,觀察上面計算的值與下面計算的對應(yīng)的值
np.cov(data[:,0:2].T),    np.cov(Y_0),      np.cov(Y_1),
(array([[ 0.68569351, -0.03926846],
        [-0.03926846,  0.18800403]]), array(0.68569351), array(0.18800403))

協(xié)方差矩陣模型

  • 根據(jù)上面的計算細(xì)節(jié),可以把協(xié)方差矩陣的計算公式表示如下。

對特征中心化

  • 注意:

    • 不是對樣本去中心化,而是特征,這里鳶尾花4個特征,每個特征150個數(shù)據(jù)樣本。
  • \bar{Y} 表示對某個特征的所有樣本求均值,去中心化公式:

    • Y_c = Y - \bar{Y}
    • 其中Y_c表示去中心化后的特征變量
import sklearn.datasets  as ds
import numpy as np

# 加載數(shù)據(jù)集
data, target = ds.load_iris(return_X_y=True)
data = np.mat(data)    # 使用矩陣類型,可以保持形狀
data_mean = np.mean(data, axis=0)
data_mean    # 這個維數(shù)應(yīng)該是樣本個數(shù)(150, 1)
matrix([[5.84333333, 3.054     , 3.75866667, 1.19866667]])
# 去中心化
Y = data - data_mean
data[0], data_mean, data[0] - data_mean, Y[0]   # 驗證上面的計算結(jié)果

(matrix([[5.1, 3.5, 1.4, 0.2]]),
 matrix([[5.84333333, 3.054     , 3.75866667, 1.19866667]]),
 matrix([[-0.74333333,  0.446     , -2.35866667, -0.99866667]]),
 matrix([[-0.74333333,  0.446     , -2.35866667, -0.99866667]]))

計算協(xié)方差矩陣

  • 協(xié)方差矩陣公式
    • \dfrac{Y_c Y_c^T}{m-1}
    • 其中m表示的是樣本個數(shù)。(不是特征維數(shù))
Y_cov = np.matmul(Y.T,Y)/ (Y.shape[0]-1)
Y_cov
matrix([[ 0.68569351, -0.03926846,  1.27368233,  0.5169038 ],
        [-0.03926846,  0.18800403, -0.32171275, -0.11798121],
        [ 1.27368233, -0.32171275,  3.11317942,  1.29638747],
        [ 0.5169038 , -0.11798121,  1.29638747,  0.58241432]])
  • 這是PCA算出來的協(xié)方差(降維為2的計算結(jié)果)
[[ 0.67919741 -0.03258618  1.27066452  0.5321852 ]
 [-0.03258618  0.18113034 -0.31863564 -0.13363564]
 [ 1.27066452 -0.31863564  3.11934547  1.28541527]
 [ 0.5321852  -0.13363564  1.28541527  0.58961806]]
  • 這是PCA算出來的協(xié)方差(降維為2的計算結(jié)果)
[[ 0.68569351 -0.03926846  1.27368233  0.5169038 ]
 [-0.03926846  0.18800403 -0.32171275 -0.11798121]
 [ 1.27368233 -0.32171275  3.11317942  1.29638747]
 [ 0.5169038  -0.11798121  1.29638747  0.58241432]]
# 使用numpy計算的協(xié)方差矩陣驗證
np.cov(Y.T)    # 與上面比對,驗證計算的正確性
array([[ 0.68569351, -0.03926846,  1.27368233,  0.5169038 ],
       [-0.03926846,  0.18800403, -0.32171275, -0.11798121],
       [ 1.27368233, -0.32171275,  3.11317942,  1.29638747],
       [ 0.5169038 , -0.11798121,  1.29638747,  0.58241432]])
Y_cov[3,0],Y_cov[0,3]   # 這是一個對稱矩陣
(0.5169038031319912, 0.5169038031319912)

特征向量模型

  • 特征向量與特征值,通過矩陣的奇異值分解得到。

特征方程的定義

  • 特征方程值得是對一個矩陣M,如果存在一個標(biāo)量\lambda與列向量u,滿足如下等式:
    • Mu=\lambda u

    • \lambda 為矩陣M的特征值,u為矩陣M的特征向量

  • 求解特征值與特征向量的方法就是奇異值分解算法。
    • 其中\lambda與列向量u不是唯一的。所有的特征值與特征向量可以表達(dá)成如下公式。

M [u_1, u_2, \dots, u_n ] = [u_1, u_2, \dots, u_n ] \begin{bmatrix} {\lambda_1}&{0}&{\cdots}&{0}\\ {0}&{\lambda_2}&{\cdots}&{0}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {0}&{0}&{\cdots}&{\lambda_n}\\ \end{bmatrix}

  • 如果全部使用矩陣表達(dá),則可以表達(dá)如下:
    • MU=U\Sigma
  • 如果對于方陣 ,推導(dǎo)一下可以得到:

    • M = U \Sigma U^{-1}
  • SVD自己實現(xiàn)比較痛苦,對這種完全已經(jīng)理解,并信任的實現(xiàn),可以調(diào)用第三方實現(xiàn),這里調(diào)用numpy的函數(shù)實現(xiàn)。

    numpy.linalg.svd(
        a,     # 被求解的矩陣(方陣)
        full_matrices=True,    # 影響輸出的特征向量的維度,采用默認(rèn)值即可
        compute_uv=True)     # 計算特征向量
  • 返回左特征向量矩陣 , 特征值矩陣,右特征向量(在方陣情況下,就是左特征向量矩陣的逆)
import numpy.linalg  as la
u,s,v = la.svd(Y_cov)
u.shape
(4, 4)
v.shape
(4, 4)
s.shape
(4,)
s    # 這里的特征值與PCA計算出來的有差異
array([4.22484077, 0.24224357, 0.07852391, 0.02368303])
# 使用PCA降維為2的協(xié)方差的結(jié)果
import numpy as  np
import numpy.linalg  as la
M = np.mat(
    [[ 0.67919741, -0.03258618,  1.27066452,  0.5321852 ],
    [-0.03258618,  0.18113034, -0.31863564, -0.13363564],
    [ 1.27066452, -0.31863564,  3.11934547,  1.28541527], 
    [ 0.5321852,  -0.13363564,  1.28541527,  0.58961806]]
)
la.svd(M)
(matrix([[-0.36158968, -0.65653989,  0.50672256, -0.42595836],
         [ 0.08226889, -0.72971236, -0.51869935,  0.43783865],
         [-0.85657211,  0.17576741, -0.47327155, -0.10678992],
         [-0.35884393,  0.07470646,  0.50019723,  0.78450794]]),
 array([4.22484077, 0.24224357, 0.05110347, 0.05110347]),
 matrix([[-0.36158968,  0.08226889, -0.85657211, -0.35884393],
         [-0.65653989, -0.72971236,  0.17576741,  0.07470646],
         [ 0.50672256, -0.51869935, -0.47327155,  0.50019723],
         [-0.42595836,  0.43783865, -0.10678992,  0.78450794]]))
# 使用scipy的奇異值分解
import scipy.linalg as sla
import numpy.linalg  as la
M = np.mat(
    [[ 0.67919741, -0.03258618,  1.27066452,  0.5321852 ],
    [-0.03258618,  0.18113034, -0.31863564, -0.13363564],
    [ 1.27066452, -0.31863564,  3.11934547,  1.28541527], 
    [ 0.5321852,  -0.13363564,  1.28541527,  0.58961806]]
)
sla.svd(M)

(array([[-0.36158968, -0.65653989,  0.50672256, -0.42595836],
        [ 0.08226889, -0.72971236, -0.51869935,  0.43783865],
        [-0.85657211,  0.17576741, -0.47327155, -0.10678992],
        [-0.35884393,  0.07470646,  0.50019723,  0.78450794]]),
 array([4.22484077, 0.24224357, 0.05110347, 0.05110347]),
 array([[-0.36158968,  0.08226889, -0.85657211, -0.35884393],
        [-0.65653989, -0.72971236,  0.17576741,  0.07470646],
        [ 0.50672256, -0.51869935, -0.47327155,  0.50019723],
        [-0.42595836,  0.43783865, -0.10678992,  0.78450794]]))

降維模型

  • 選擇對應(yīng)最大特征值的兩個特征向量
[-0.36158968, -0.65653989,  0.50672256, -0.42595836],
[ 0.08226889, -0.72971236, -0.51869935,  0.43783865],
# 選擇的特征
e = v[:, 0:2]   # 在V中取兩列,或者u中取兩行。
e
matrix([[-0.36158968,  0.08226889],
        [-0.65653988, -0.72971237],
        [ 0.58099728, -0.59641809],
        [ 0.31725455, -0.32409435]])
# 計算降維后的數(shù)據(jù)樣本

de_data = np.matmul(data, e)
de_data.shape
(150, 2)
% matplotlib inline
import matplotlib.pyplot as plt
import sklearn.datasets  as ds
import sklearn.decomposition  as de

# 數(shù)據(jù)可視化
fig = plt.figure('PCA降維', figsize=(6, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])

ax.scatter(list(de_data[0:50, 0]), list(de_data[0:50:, 1]), s=9, c='r')
ax.scatter(list(de_data[50:100, 0]), list(de_data[50:100:, 1]), s=9, c='g')
ax.scatter(list(de_data[100:150, 0]), list(de_data[100:150:, 1]), s=9, c='b')

plt.show()
通過矩陣分解后的降維可視化

PCA算法數(shù)學(xué)基礎(chǔ)

數(shù)據(jù)集準(zhǔn)備

import sklearn.datasets  as ds
import numpy as np

# 加載數(shù)據(jù)集
data, target = ds.load_iris(return_X_y=True)

均值的概念

  1. 樣本總體的均值
np.mean(data,axis=0)
array([5.84333333, 3.054     , 3.75866667, 1.19866667])
  1. 一個樣本的均值
np.mean(data[0])
2.55

方差的概念

# numpy的計算
np.var(data,axis=0)
array([0.68112222, 0.18675067, 3.09242489, 0.57853156])
# 手工計算
m = np.mean(data,axis=0)
s = np.zeros(shape=4)
for d in data:
    c = (d - m) * (d-m)
    s += c

r = s /len(data)
r
array([0.68112222, 0.18675067, 3.09242489, 0.57853156])

協(xié)方差的概念

  1. 相同向量的協(xié)方差
# numpy的實現(xiàn)
np.cov(data[:,0])
array(0.68569351)
# 手工計算的結(jié)果

# 使用向量的每個特征 - 向量特征均值
a1 = data[:,0]-np.mean(data[:,0])    

#  計算每個特征的平方
a2 = a1 * a1

# 計算平方和
a3 = a2.sum()

#  求均值(無偏:除以n-1)
a4 = a3 / (len(data[:,0]) - 1)
a4
0.6856935123042507
  1. 不同向量的協(xié)方差
  • numpy中自動形成對稱的矩陣(就是協(xié)方差矩陣)
# numpy的實現(xiàn)(使用兩個參數(shù))
np.cov(data[:,0],data[:,1])
array([[ 0.68569351, -0.03926846],
       [-0.03926846,  0.18800403]])
# numpy的實現(xiàn)(使用一個參數(shù):等同于上面參數(shù)的合并)
np.cov(data[:,0:2].T)
array([[ 0.68569351, -0.03926846],
       [-0.03926846,  0.18800403]])
# 手工計算的結(jié)果

# 使用向量的每個特征 - 向量特征均值
x1 = data[:,0]-np.mean(data[:,0])    
y1 = data[:,1]-np.mean(data[:,1])    
#  計算每個特征的平方
a2 = x1 * y1

# 計算平方和
a3 = a2.sum()

#  求均值(無偏:除以n-1)
a4 = a3 / (len(data[:,0]) - 1)
a4

-0.03926845637583893

協(xié)方差矩陣的概念

  • numpy的cov函數(shù)返回的協(xié)方差矩陣,協(xié)方差矩陣是向量與向量的轉(zhuǎn)置,對應(yīng)求方差得到的矩陣,現(xiàn)在說明如下(使用上面的符號):

X = \begin{bmatrix} {x_{11}}&{x_{12}}&{\cdots}&{x_{1n}}\\ {x_{21}}&{x_{22}}&{\cdots}&{x_{2n}}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {x_{m1}}&{x_{m2}}&{\cdots}&{x_{mn}}\\ \end{bmatrix} = \begin{bmatrix} {Y_{1}}&{Y_{2}}&{\vdots}&{Y_{n}} \end{bmatrix}

  • 其中

    • X表示所有樣本形成的矩陣。
    • Y_i標(biāo)識一個具有m樣本的特征變量。
    • 整個數(shù)據(jù)集樣本特征維數(shù)是n個。
  • X的協(xié)方差矩陣cov(X)就是:

X = \begin{bmatrix} {Y_{1}} & {Y_{2}} & {\dots} & {Y_{n}}\\ \end{bmatrix}

cov(X)= \begin{bmatrix} {cov(Y_1,Y_1)}&{cov(Y1,Y2)}&{\cdots}&{cov(Y_1,Y_n)}\\ {cov(Y_2,Y_1)}&{cov(Y_2,Y_1)}&{\cdots}&{cov(Y_2,Y_n)}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {cov(Y_n,Y_1)}&{cov(Y_n,Y_1)}&{\cdots}&{cov(Y_n,Y_n)}\\ \end{bmatrix}

  • 協(xié)方差矩陣的維數(shù)為
    • (n, n),其中n為特征維數(shù))

    • 對鳶尾花數(shù)據(jù)而言就是(4,4)

# numpy的實現(xiàn)
np.cov(data.T).shape
np.cov(data.T)
array([[ 0.68569351, -0.03926846,  1.27368233,  0.5169038 ],
       [-0.03926846,  0.18800403, -0.32171275, -0.11798121],
       [ 1.27368233, -0.32171275,  3.11317942,  1.29638747],
       [ 0.5169038 , -0.11798121,  1.29638747,  0.58241432]])

PCA算法完整實現(xiàn)(numpy實現(xiàn))

% matplotlib inline
import matplotlib.pyplot as plt
import sklearn.datasets  as ds
import numpy as np
import numpy.linalg  as la

# 加載數(shù)據(jù)集
data, target = ds.load_iris(return_X_y=True)
data = np.mat(data)    # 使用矩陣類型,可以保持形狀
# 計算均值
data_mean = np.mean(data, axis=0)  # 按照特征,返回(1,4)向量
# 使用均值中心化
Y = data - data_mean
# 計算Y的協(xié)方差
Y_cov = np.matmul(Y.T,Y)/ (Y.shape[0]-1)

# 求奇異值分解
u,s,v = la.svd(Y_cov)

# 選擇特征向量
e = u[:, 0:2]   # 在V中取兩列,或者u中取兩行。

# 計算降維后的數(shù)據(jù)樣本
de_data = np.matmul(data, e)
de_data = np.mean(de_data)-de_data   #中心化處理的算法中做了一個簡單的中心化處理
# 可視化降維以后的數(shù)據(jù)
fig = plt.figure('PCA降維', figsize=(6, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])

ax.scatter(list(de_data[0:50, 0]), list(de_data[0:50:, 1]), s=9, c='r')
ax.scatter(list(de_data[50:100, 0]), list(de_data[50:100:, 1]), s=9, c='g')
ax.scatter(list(de_data[100:150, 0]), list(de_data[100:150:, 1]), s=9, c='b')

plt.show()
完整的代碼運行結(jié)果
  • 對比下PCA可視化降維的效果


    sklearn模塊運算可視化結(jié)果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容