PCA算法數學原理及實現

數學原理參考:https://blog.csdn.net/aiaiai010101/article/details/72744713html

實現過程參考:https://www.cnblogs.com/eczhou/p/5435425.htmlpython

兩篇博文都寫的透徹明白。ide

本身用python實現了一下,有幾點疑問,主要是由於對基變換和座標變換理解不深。spa

先附上代碼和實驗結果:.net

code:3d

from numpy import *
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmat

cx = mat([[2.5, 2.4],
          [0.5, 0.7],
          [2.2, 2.9],
          [1.9, 2.2],
          [3.1, 3.0],
          [2.3, 2.7],
          [2, 1.6],
          [1, 1.1],
          [1.5, 1.6],
          [1.1, 0.9]])
# print(cx.shape)
sz = cx.shape
m = sz[0]
n = sz[1]

# 顯示原數據
def plot_oridata( cx ):
    plt.figure(num='原數據圖', figsize=(6, 6))
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.xlim((-1, 4))
    plt.ylim((-1, 4))
    new_ticks = np.arange(-1, 4, 0.5)
    plt.xticks(new_ticks)
    plt.yticks(new_ticks)
    plt.scatter(cx[:, 0].tolist(), cx[:, 1].tolist(), c='r', marker='+')
    plt.plot([0, 0], [-1, 4], 'k-')
    plt.plot([-1, 4], [0, 0], 'k-')
    plt.show()
    return

#求協方差矩陣
def get_covMat( cx ):
    print('+++++++++++++       求協方差矩陣     +++++++++++++++')
    # 零均值化
    ecol = np.mean(cx, axis=0)
    cx1 = (cx[:, 0]) - ecol[0, 0]
    cx2 = cx[:, 1] - ecol[0, 1]
    Mcx = np.column_stack((cx1, cx2))
    Covx = np.transpose(Mcx)*Mcx/(m-1)
    # print(Covx)
    return Covx, Mcx

#計算特徵值和特徵向量
def get_eign(Covx, k):
    eVals, eVecs = np.linalg.eig(Covx)
    # print(eVals)
    # print(eVecs, ' ', eVecs.shape)
    sorted_indices = np.argsort(eVals)
    topk_evecs = eVecs[:, sorted_indices[:-k-1:-1]]
    # print(topk_evecs)

    plt.figure(num='特徵向量', figsize=(6, 6))
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.xlim((-4, 4))
    plt.ylim((-4, 4))
    new_ticks = np.arange(-4, 4, 1)
    plt.xticks(new_ticks)
    plt.yticks(new_ticks)
    plt.scatter(cx[:, 0].tolist(), cx[:, 1].tolist(), c='r', marker='+')
    plt.plot([0, 0], [-4, 4], 'k-.')
    plt.plot([-4, 4], [0, 0], 'k-.')
    # print(eVecs[0, 0], eVecs[1, 0])
    # print(eVecs)
    plt.plot([0, eVecs[0, 0] * 6], [0, eVecs[1, 0] * 6], 'b:')
    plt.plot([0, eVecs[0, 1] * 6], [0, eVecs[1, 1] * 6], 'b:')
    plt.plot([0, eVecs[0, 0] * -6], [0, eVecs[1, 0] * -6], 'b:')
    plt.plot([0, eVecs[0, 1] * -6], [0, eVecs[1, 1] * -6], 'b:')
    plt.show()
    return eVecs, topk_evecs

#轉換數據
def transform_data(eVecs, Mcx):
    print("------------------轉換數據---------------------")
    tran_data = Mcx * eVecs
    plt.figure(num='轉換數據', figsize=(6, 6))
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.xlim((-2, 2))
    plt.ylim((-2, 2))
    new_ticks = np.arange(-2, 2, 0.5)
    plt.xticks(new_ticks)
    plt.yticks(new_ticks)
    plt.scatter(tran_data[:, 0].tolist(), tran_data[:, 1].tolist(), c='r', marker='+')#哪一維對應x,哪一維對應y
    plt.plot([0, 0], [-4, 4], 'k-.')
    plt.plot([-4, 4], [0, 0], 'k-.')
    # print(eVecs[0, 0], eVecs[1, 0])
    # print(eVecs)
    plt.show()
    return

#壓縮數據
def compress_data(Mcx, topkevecs, eVecs):
    print("------------------壓縮數據---------------------")
    comdata = Mcx * topkevecs
    c1 = np.zeros((10, 1), dtype=int)
    comdata1 = np.column_stack((c1, comdata))
    comdata2 = comdata1 * eVecs

    plt.figure(num='壓縮數據', figsize=(6, 6))
    plt.xlabel('Feature 1')
    plt.ylabel('Feature 2')
    plt.xlim((-4, 4))
    plt.ylim((-4, 4))
    new_ticks = np.arange(-4, 4, 0.5)
    plt.xticks(new_ticks)
    plt.yticks(new_ticks)
    plt.scatter(comdata2[:, 0].tolist(), comdata2[:, 1].tolist(), c='r', marker='+')  # 哪一維對應x,哪一維對應y
    plt.plot([0, 0], [-4, 4], 'k-.')
    plt.plot([-4, 4], [0, 0], 'k-.')
    plt.plot([0, eVecs[0, 0] * 6], [0, eVecs[1, 0] * 6], 'b:')
    plt.plot([0, eVecs[0, 1] * 6], [0, eVecs[1, 1] * 6], 'b:')
    plt.plot([0, eVecs[0, 0] * -6], [0, eVecs[1, 0] * -6], 'b:')
    plt.plot([0, eVecs[0, 1] * -6], [0, eVecs[1, 1] * -6], 'b:')
    # print(eVecs[0, 0], eVecs[1, 0])
    # print(eVecs)
    plt.show()
    return

plot_oridata(cx)
Covx, Mcx = get_covMat(cx)
eVecs, topk_evecs = get_eign(Covx, 1)
transform_data(eVecs, Mcx)
compress_data(Mcx, topk_evecs, eVecs)
print('end')
View Code

初學python,代碼確定很囉嗦,而且很醜。code

實驗結果:orm

 

疑問1:對數據進行特徵向量爲基的轉換時,公式以下。我獲得的座標是以原座標系爲參考的,那麼哪一維對應x,哪一維對應y,若是我將特徵向量按照特徵值降序的順序從新排列,是否有影響呢?htm

獲得的座標是新座標系下的。根據轉換向量對應。blog

            clip_image011[4]

疑問2:取最大特徵值對應的特徵向量爲基時,對數據進行降維,此時我獲得的一維座標是以這個特徵向量爲參考的嗎?此時我應該如何在原座標系show出這些數據?

個人代碼中,取第一維爲0,第二維爲獲得的座標,以此再進行以此疑問1中的二維基轉換,獲得座標,而且plot。不太理解道理。

對一維座標,分別對兩個座標軸投影便可獲得新座標系下的兩個座標。

相關文章
相關標籤/搜索