機器學習之pca

零食7788發表於2024-06-17

1.pca簡介
PCA透過線性變換將高維資料轉換為低維資料,同時保留最大的資料方差。這樣做的目的是減少資料集的維度,儘可能保留原始資料的資訊。

2.演算法流程
1.資料中心化
對原始資料進行中心化處理,即將每個特徵的值減去該特徵的均值,以保證資料的均值為零。
pj = np.mean(X, axis=0)
X_pj = X - pj

2.計算協方差矩陣
找到一個軸,使得樣本空間的所有點對映到這個軸的協方差最大。

公式:cov(X,Y)=1/n−1∑ni=1(xi−x¯)(yi−y¯)

n = X.shape[0]
cov = np.dot(X_pj.T,X_pj) / (n - 1)
因為事先已經對他進行了資料中心化,所以得到的協方差就可以不用求解平均值,而直接np.dot(X_pj.T,X_pj)就得到第i個特徵和第j個特徵的協方差。除以(n-1)是為了得到無偏估計,這樣求解準確度會更高。

3.協方差矩陣分解計算特徵值和特徵向量
對矩陣A進行特徵值分解就是將方陣分解為其特徵值和特徵向量的過程。
公式:A=VΛV−1
原理:
上三角形是對角線下方的值全部為零,上三角形的對角線就是他的特徵值。我們透過不斷把A進行相似矩陣轉化,他的特徵值是不會變的,透過迭代多次最後吧矩陣A轉化為上三角形,就可以直接得到他的特徵值了,特徵向量就是變換過程中Q的累乘。

def qr_algorithm(A, num=1000, tol=1e-6):
n = A.shape[0]
tzxl = np.eye(n)

for i in range(num):
    Q, R = np.linalg.qr(A)
    A = np.dot(R, Q)
    tzxl = np.dot(tzxl, Q)

    t = np.sqrt(np.sum(np.square(A) - np.sum(np.square(np.diag(A)))))
    if t < tol:
        break

tzz = np.diag(A)
return tzz, tzxl

使用QR分解的迭代過程逐步將矩陣A轉換成上三角矩陣,同時累積了所有的正交變換矩陣,從而得到矩陣A的特徵值和特徵向量的近似解。
4.選擇主成分
t1 = np.argsort(-tzz)
tzxl = tzxl[:, t1]
cnt = 2
zcf = tzxl[:, :cnt]
X1 = np.dot(X_pj, zcf)

5.構建投影矩陣
6.資料投影
7.解釋主成分

3.程式碼展示
1.列印降維度後資料

label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)
print(X1)
plt.rcParams['font.sans-serif'] = ['SimHei']
rcParams['axes.unicode_minus'] = False
plt.scatter(X1[:, 0], X1[:, 1], c=y_encoded, cmap='viridis')
plt.xlabel('主成分一')
plt.ylabel('主成分二')
plt.title('PCA')
plt.show()
將y的標籤對映為數值。並且需要加上plt.rcParams['font.sans-serif'] = ['SimHei']和rcParams['axes.unicode_minus'] = False來保證中文和負號在影像中正常顯示

四、實驗中遇到的問題
因為這個實驗的流程相對比較簡短,主要的問題就是在特徵值分解的理解上,剛開始因為直接計算特徵值和特徵向量的難度太大,沒想到用相似矩陣來求解。後來使用QR分解法迭代求解特徵值和特徵向量就比較簡便。

五.pca的優缺點
優點
1.能夠降低模型的複雜度
2.有助於消除特徵之間的相關性,減少多重共線性對模型的影響
3.有助於提取保留需要的多個特徵
4.pca可以降低到三維或者二維有助於視覺化顯示
缺點
1.不一定需要,而且可能丟失有用資訊
2.對資料線性假設,當資料非線性的時候效果不好
3.計算複雜度較高
4.降維後的特徵通常難以解釋

六.實驗總程式碼

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from matplotlib import rcParams
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
train_data = pd.read_csv("C:\Users\李燁\Desktop\新建資料夾\6\iris.txt", sep='\s+')

假設資料集的最後一列是目標標籤

X = train_data.iloc[:, :-1].values # 特徵
y = train_data.iloc[:, -1].values # 標籤

pj = np.mean(X, axis=0)
X_pj = X - pj

n = X.shape[0]
cov = np.dot(X_pj.T, X_pj) / (n - 1)

def QR(A, num=1000, tol=1e-6):
n = A.shape[0]
tzxl = np.eye(n)

for i in range(num):
    Q, R = np.linalg.qr(A)
    A = np.dot(R, Q)
    tzxl = np.dot(tzxl, Q)

    t = np.sqrt(np.sum(np.square(A) - np.sum(np.square(np.diag(A)))))
    if t < tol:
        break

tzz = np.diag(A)
return tzz, tzxl

tzz, tzxl = QR(cov)

t1 = np.argsort(-tzz)
tzxl = tzxl[:, t1]
cnt = 2
zcf = tzxl[:, :cnt]
X1 = np.dot(X_pj, zcf)

label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)
print(X1)
plt.rcParams['font.sans-serif'] = ['SimHei']
rcParams['axes.unicode_minus'] = False
plt.scatter(X1[:, 0], X1[:, 1], c=y_encoded, cmap='viridis')
plt.xlabel('主成分一')
plt.ylabel('主成分二')
plt.title('PCA')
plt.show()

相關文章