Python3 PCA理解小攻略

主成分分析(Principal Component Analysis,PCA), 是一種多元統計方法,也廣泛應用於機器學習和其它領域。通過正交變換將一組可能存在相關性的變量轉換爲一組線性不相關的變量,轉換後的這組變量叫主成分。它的主要作用是對高維數據進行降維。PCA把原先的n個特徵用數目更少的k個特徵取代,新特徵是舊特徵的線性組合,這些線性組合最大化樣本方差,儘量使新的k個特徵互不相關。關於PCA的更多介紹,請參考:https://en.wikipedia.org/wiki/Principal_component_analysis.

PCA的主要算法如下
(1)組織數據爲矩陣形式,以便於模型使用,矩陣的一行表示一個樣本,矩陣的一列表示一個屬性;
(2)計算樣本每個特徵的平均值;
(3)每個樣本數據減去該特徵的平均值(歸一化處理);
(4)求協方差矩陣;
(5)找到協方差矩陣的特徵值和特徵向量;
(6)對特徵值和特徵向量重新排列(特徵值從大到小排列);
(7) 對特徵值求取累計貢獻率;
(8)對累計貢獻率按照某個特定比例選取特徵向量集的子集合;
(9)對原始數據(第三步後)進行轉換。

······其中協方差矩陣的分解可以通過按對稱矩陣的特徵向量來,也可以通過分解矩陣的SVD來實現,而在Scikit-learn中,也是採用SVD來實現PCA算法的。關於SVD的介紹及其原理,可以參考:矩陣的奇異值分解(SVD)
  本文將用三種方法來實現PCA算法,一種是原始算法,即上面所描述的算法過程,具體的計算方法和過程,可以參考:A tutorial on Principal Components Analysis, Lindsay I Smith. 一種是帶SVD的原始算法,在Python的Numpy模塊中已經實現了SVD算法,並且將特徵值從大從小排列,省去了對特徵值和特徵向量重新排列這一步。最後一種方法是用Python的Scikit-learn模塊實現的PCA類直接進行計算,來驗證前面兩種方法的正確性。
·······本文從代碼的角度,做了一次PCA獨立成分分析的小攻略,主要是爲了回答如下幾個問題:

  1. 經過PCA降維後數據變了沒有?變了沒有取決於最後訓練直接輸入機器學習的數據到底是PCA的輸出,還是通過PCA找出來的對應主屬性列的原始數據列。
  2. 在繼續使用機器學習算法做分類時,是直接使用PCA降維後的特徵?還是需要恢復數據到原始數據?本文針對主要針對此問題做攻略展開!
  3. 實現PCA的三種方式

代碼

# -*- coding: utf-8 -*-
import numpy as np
from sklearn.decomposition import PCA
import sys
#返回選擇多少個主要的特徵(屬性列)
def index_lst(lst, component=0, rate=0):
    #component: numbers of main factors
    #rate: rate of sum(main factors)/sum(all factors)
    #rate range suggest: (0.8,1)
    #if you choose rate parameter, return index = 0 or less than len(lst)
    if component and rate:
        print('Component and rate must choose only one!')
        sys.exit(0)
    if not component and not rate:
        print('Invalid parameter for numbers of components!')
        sys.exit(0)
    elif component:
        print('Choosing by component, components are %s......'%component)
        return component
    else:
        print('Choosing by rate, rate is %s ......'%rate)
        for i in range(1, len(lst)):
            #sum(lst[:i])/sum(lst)用於求解PCA的置信度,置信度=選取的k個最重要特徵的特徵值/所有屬性的特徵值之和
            if sum(lst[:i])/sum(lst) >= rate: 
                return i
        return 0


# test data
from sklearn import datasets
#導入分解模塊
from sklearn import decomposition
pca = decomposition.PCA() #初始化一個對象
pca
iris = datasets.load_iris()
mat = iris.data #iris的數據部分
y_pred=iris.target #iris的數標籤部分
# simple transform of test data
Mat = np.array(mat, dtype='float64')
#print('Before PCA transforMation, data is:\n', Mat)
print('\nMethod 1: PCA by original algorithm:')
p,n = np.shape(Mat) # shape of Mat 
t = np.mean(Mat, 0) # mean of each column
"""
4個屬性的均值t:
sepal length       5.84333
sepal width        3.054
petal length       3.75867
petal width        1.19867
"""

#1.平均值(歸一化處理),減去每一列屬性的均值
for i in range(p):
    for j in range(n):
        Mat[i,j] = float(Mat[i,j]-t[j]) 
        

在這裏插入圖片描述

  1. PCA by original algorithm
#2.協方差矩陣(covariance Matrix)
cov_Mat = np.dot(Mat.T, Mat)/(p-1) #協方差矩陣
# eigvalues and eigenvectors of covariance Matrix with eigvalues descending
U,V = np.linalg.eigh(cov_Mat)  #從U這裏來看特徵值的大小,從而確定應該選擇的主要屬性是那k個?如:component=2,則方差最大的屬性主屬性是2列和3列。

在這裏插入圖片描述

# Rearrange the eigenvectors and eigenvalues
U = U[::-1]
for i in range(n):
    V[i,:] = V[i,:][::-1]  #交換向量的位置,這裏是倒序
# choose eigenvalue by component or rate, not both of them euqal to 0
Index = index_lst(U, component=2)  # 只選取最重要的兩個屬性用於分類特徵
if Index:
    v = V[:,:Index]  # subset of Unitary matrix,酉矩陣的子集,即:選出最大k個特徵值對應的特徵向量
else:  # improper rate choice may return Index=0
    print('Invalid rate choice.\nPlease adjust the rate.')
    print('Rate distribute follows:')
    print([sum(U[:i])/sum(U) for i in range(1, len(U)+1)]) 
    #iris 數據集中選擇最重要的第1個,第1-2個,第1-3個,第1-4個特徵屬性列分類達到的置信度大小分別如下:
    #[0.9246162071742683, 0.9776317750248034, 0.99481691454981, 1.0]
    sys.exit(0)
# data transformation
T1 = np.dot(Mat, v) #150x4*4*2=150x2
# print the transformed data
print('We choose %d main factors.'%Index)
print('After PCA transformation, data becomes:\n',T1)
  1. PCA by original algorithm using SVD
print('\nMethod 2: PCA by original algorithm using SVD:')
# u: Unitary matrix,  eigenvectors in columns 
# d: list of the singular values, sorted in descending order
u,d,v = np.linalg.svd(cov_Mat)
Index = index_lst(d, rate=0.95)  # choose how many main factors
T2 = np.dot(Mat, u[:,:Index])  # transformed data
print('We choose %d main factors.'%Index)
print('After PCA transformation, data becomes:\n',T2)
  1. PCA by Scikit-learn
pca = PCA(n_components=2) # n_components can be integer or float in (0,1)
pca.fit(mat)  # fit the model
print('\nMethod 3: PCA by Scikit-learn:')
print('After PCA transformation, data becomes:')
print(pca.fit_transform(mat))  # transformed data
pca.explained_variance_ratio_  #可解釋性方差,最大特徵值對應的屬性列的可解釋方差是0.92461621,最大告知是已經排過序的了
T3=pca.fit_transform(mat) 

4.畫出iris數據

#顯示iris鳶尾花的PCA的數據
import pandas as pd
import matplotlib.pyplot as plt

def plot_pca_scatter():
    colors=['black','blue','purple','yellow','white','red','lime','cyan','orange','gray']
    for i in range(len(colors)):
        px=T3[:,0][y_pred==i]
        py=T3[:,1][y_pred==i] #DataFrame.as_matrix(),將df轉換爲Numpy表示
        #py=T3[:,1][y_pred.as_matrix==i] #報錯啦,y_pred已經是numpy.array()啦,直接使用即可。
        plt.scatter(px,py,c=colors[i])
    plt.legend(np.arange(3).astype(str))
    plt.xlabel('First PCA')
    plt.ylabel('Second PCA')
    plt.show()
plot_pca_scatter()

在這裏插入圖片描述
5.分類中的PCA
5.1. 情況1:使用PCA降維後的輸出作爲特徵進行分類

from sklearn.svm import LinearSVC
from sklearn.cross_validation import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report
#情況1:使用PCA降維後的輸出作爲特徵進行分類
X_train,X_test,y_train,y_test=train_test_split(T3,iris.target)
ss=StandardScaler()
X_train=ss.fit_transform(X_train)
X_test=ss.transform(X_test)
pca_svc=LinearSVC()
pca_svc.fit(X_train,y_train) #模型訓練
svc_pred=pca_svc.predict(X_test)
print('得分: ',pca_svc.score(X_test,y_test))
#綜合評分
print('綜合評分: ',classification_report(y_test,svc_pred,target_names=np.arange(3).astype(str)))
print('pca的可解釋性方差: ',pca.explained_variance_ratio_)  #特徵重要性權重,降序

得分:  0.8947368421052632
綜合評分:               precision    recall  f1-score   support

          0       1.00      1.00      1.00        17
          1       0.86      0.67      0.75         9
          2       0.79      0.92      0.85        12

avg / total       0.90      0.89      0.89        38

pca的可解釋性方差:  [0.92461621 0.05301557]

5.2. 情況2:使用PCA降維後對應的,最重要的,幾列原始數據作爲特徵進行分類

#情況2:使用PCA降維後對應的,最重要的,幾列原始數據作爲特徵進行分類
print('pca的可解釋性方差: ',pca.explained_variance_ratio_)  #特徵重要性權重,降序,從這裏並不能得到方差最大的主屬性列
#[0.92461621 0.05301557 0.01718514 0.00518309]
train11=iris.data[:,:2] 
X_train,X_test,y_train,y_test=train_test_split(train11,iris.target)
ss=StandardScaler()
X_train=ss.fit_transform(X_train)
X_test=ss.transform(X_test)
pca_svc=LinearSVC()
pca_svc.fit(X_train,y_train) #模型訓練
svc_pred=pca_svc.predict(X_test)
print('得分: ',pca_svc.score(X_test,y_test))
#綜合評分
print('綜合評分: ',classification_report(y_test,svc_pred,target_names=np.arange(3).astype(str)))

#錯誤更正
train11=iris.data[:,2:] 
#train11=iris.data
X_train,X_test,y_train,y_test=train_test_split(train11,iris.target)
ss=StandardScaler()
X_train=ss.fit_transform(X_train)
X_test=ss.transform(X_test)
pca_svc=LinearSVC()
pca_svc.fit(X_train,y_train) #模型訓練
svc_pred=pca_svc.predict(X_test)
print('得分: ',pca_svc.score(X_test,y_test))
#綜合評分
print('綜合評分: ',classification_report(y_test,svc_pred,target_names=np.arange(3).astype(str)))

得分:  0.9736842105263158
綜合評分:               precision    recall  f1-score   support

          0       1.00      1.00      1.00        15
          1       0.92      1.00      0.96        12
          2       1.00      0.91      0.95        11

avg / total       0.98      0.97      0.97        38

參考鏈接

1.超好理解的PCA 特徵選擇
https://blog.csdn.net/qq_36336522/article/details/79765558

2.PCA的數學原理
https://blog.csdn.net/shulixu/article/details/52894413 https://blog.csdn.net/shulixu/article/details/52894413

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章