機器學習實戰筆記4——主成分分析

任務安排

1、機器學習導論       8、稀疏表示
2、KNN及其實現       9、核方法
3、K-means聚類      10、高斯混合模型
4、主成分分析          11、嵌入學習
5、線性判別分析      12、強化學習
6、貝葉斯方法          13、PageRank
7、邏輯迴歸              14、深度學習

主成分分析(PCA)

Ⅰ算法背景:維數災難

      維數災難最早是由理查德·貝爾曼(Richard E. Bellman)在考慮優化問題時提出來的 ,它用來描述當(數學)空間維度增加時,分析和組織高維空間(通常有成百上千維)中的數據,因體積指數增加而遇到各種問題場景。
      維數災難這個概念具有的共同特點是:當維度增加時,空間的體積增加得很快,使得可用的數據變得稀疏。

      生活中多維數據比較的例子很多,比如人的三圍及身高體重、遊戲角色的六維屬性等等。我們拿大家最熟悉的成績來說,小學時,我們可能只有語數英三科(三維),想要和小夥伴比較成績,關鍵看到底是哪一個科目某一特徵值)具體影響了我們之間的差距,因爲科目不多,還比較容易,但到了中學,我們可能要學八科、九科、十科…,身邊小夥伴也變多了,想要比較起來就沒有之前那麼容易了,而當分析某一數學問題時,可能有成百上千維的數據,樣本個數也不在少數,那麼總體分析就顯得舉步維艱。因此,我們就想讓數據變得簡單一些,就有了維數約簡思想。

Ⅱ 維數約簡

      維數約簡又稱降維,是機器學習的一種必要手段。若數據X=X={xix_i}是屬於nn維空間的,通過特徵提取或者特徵選擇的方法,將原空間的維數降至kk維,要求kk遠小於nn,並滿足:kk維空間的特性能反映原空間數據的特徵,這個過程稱之爲維數約簡
      維數約簡即通過某種數學變換,將原始高維屬性空間轉變爲一個低維子空間,在這個子空間中樣本密度大幅度提高,距離計算也變得容易起來
在這裏插入圖片描述
      由線性代數的知識我們知道,空間維度的改變依賴於變換矩陣,如XX是一個nn維列向量X=[1,2,...,n]TX=[1,2,...,n]^T,我們想要把它變成Y=[1,2,...,m]TY=[1,2,...,m]^T,即在XX前面乘上一個m×nm×n變換矩陣AA
      而主成分分析,就是降維裏的一種重要方法。

      既然要對已有的特徵值進行降維變換,那麼首先,我們要先得到原樣本集的特徵值,回顧一下線性代數的知識。
      有一個nn階矩陣AA,若存在數λλ和非零nn維列向量XX,滿足AX=λXAX=λX,則稱λ爲A的一個特徵值,X爲A的對應於λ的一個特徵向量

Ⅲ 核心思想

      主成分分析(Principal Component Analysis)的出發點是從一組特徵(nn維)中計算出一組按重要性從大到小排列的新特徵(kk維,knk≤n,通常取遠小於nn),它們是原有特徵的線性組合,並且相互之間不相關。(比如你和小夥伴的理科成績非常接近,那麼決定你們之間差距的主要科目(新特徵值PC)就是文科類的了,只關注這幾科,即降維了)

①主成分特點

      1. 源於質心的矢量
      2. 主成分①指向最大方差的方向
      3. 各後續主成分與前一主成分正交,且指向殘差(剩餘)子空間最大方差的方向

②舉例(二維)

爲了便於分析說明,我們舉二維樣本集的例子:
      如下圖所示,紅色的兩向量表示“藍色橢圓”的長軸短軸,很明顯可以看出,假如我們把樣本集的點投影到長軸上更能反映出樣本集整體的分佈,故在這個例子裏我們把長軸記爲主成分#1與長軸正交(互不相關)的短軸記爲主成分#2,理想情況下,短軸的模(高維情況下稱範數)爲0,即僅通過長軸就可以完全分析出樣本集的分佈,這就實現了完美的降維,因而我們容易知道,長短軸的模(範數)相差越大,即降維的效果越好,所以我們的目標就是,找出儘量長的長軸(標號靠前的主成分)
在這裏插入圖片描述

③最大方差理論

      通常,我們認爲信號具有較大的方差,噪聲具有較小的方差,信噪比就是信號與噪聲的功率之差(10lgPsPn10lg(\frac{P_s}{P_n})),越大越好。如下圖所示,我們把紫色線上的數據認爲是信號,而藍色線上的數據認爲是噪聲,因此我們的目的就是最大化投影數據的方差(樣本點在紫線上最分散)最小化數據點與投影之間的均方距離(藍線和越小)
在這裏插入圖片描述

④目的

      PCA的目的就是“降噪”和“去冗餘”。
      “降噪”即使保留下來的維度間的相關性儘可能小
      “去冗餘”即使保留下來的維度含有的方差(能量)儘可能大

★Ⅳ 算法剖析

輸入:樣本集{xixi}i=1n^n_{i=1},低維空間維數k(即所要保留的新特徵值個數)
輸出:投影矩陣W=[w1,w2,...,wk]W=[w_1,w_2,...,w_k]
下面介紹兩種PCA的實現方法:

①順序排列

      1.對所有樣本進行中心化(和期望作差)xixi1ni=1nxix_i←x_i-\frac{1}{n}∑^n_{i=1}x_i
      2.對中心化的數據{x1,x2,...,xnx_1,x_2,...,x_n},計算主成分#1:(即目標函數)
w1=arg(maxw1=11ni=1n(w1Txi)2)w_1=arg(\underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}(w^T_1x_i)^2)
w1Txiw^T_1x_i即內積運算(w1w_1爲單位向量),求的是xix_iw1w_1上的投影,平方是爲了省去求絕對值
利用拉格朗日乘數法求解最優λλ,約束條件爲||w||=1(即wTw=1w^Tw=1
L(w,λ)=1n(wTxi)2λ(wTw1)L(w,λ)=\frac{1}{n}(w^Tx_i)^2-λ(w^Tw-1)
(矩陣求導)對ww求導Lw=(1ni=1nxixiT)wλw\frac{\partial L}{\partial w}=(\frac{1}{n}∑^n_{i=1}x_ix_i^T)w-λw
實際上,令X=[x1,x2,...,xn]X=[x_1,x_2,...,x_n],則XXT=1ni=1nxixiTXX^T=\frac{1}{n}∑^n_{i=1}x_ix_i^T
      3.最大化投影方差
wk=arg(maxw1=11ni=1n[wkT(xij=1k1wjwjTxixi)]2)w_k=arg(\underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}[w^T_k(\underbrace{x_i-∑^{k-1}_{j=1}w_jw_j^Tx_i}_{\text{$x_i'$}})]^2)
後面一串 xij=1k1wjwjTxix_i-∑^{k-1}_{j=1}w_jw_j^Tx_i 可以簡單點理解爲,扣掉前面那個主成分的方向,在剩下的殘差子空間裏求新的主成分在這裏插入圖片描述

②協方差矩陣法

      1.對所有樣本進行去中心化(和期望作差)xixi1ni=1nxix_i←x_i-\frac{1}{n}∑^n_{i=1}x_i
      2.計算樣本的協方差矩陣CC
C=(cij)n×n=[c11c12...c1nc21c22...c2n............cn1cn2...cnn]C=(c_{ij})_{n×n}=\left[ \begin{matrix} c_{11} & c_{12} & ... & c_{1n}\\ c_{21} & c_{22} & ... & c_{2n} \\ ... & ... & ... & ... \\ c_{n1} & c_{n2} & ... & c_{nn} \end{matrix} \right]
                         cij=Cov(Xi,Yj)c_{ij}=Cov(X_i,Y_j)     i,j=1,2,...,ni,j=1,2,...,n
      (對角線元素爲某一維度的方差)
      3.對協方差矩陣C做特徵值分解(即求所有滿足的特徵值和特徵向量)CW=λWCW'=λW'(也可以用拉格朗日乘數法只求所需的最大的k個)
      4.取最大的k個特徵值所對應的特徵向量w1,w2,...,wkw_1,w_2,...,w_k

比較詳細的PCA數學推導過程主成分分析(PCA)原理詳解

——————————這節課的理論理解是真的費勁啊!————————

今日任務

1.給定的圖像數據集,可視化並輸出聚類性能(上節課還想偷懶,沒想到該來的這麼快就來了)
在這裏插入圖片描述

2.給定的圖像數據集,計算相應的特徵臉(Eigenfaces)
注:不是每一組20張算一個特徵臉,是200張取前十個特徵臉(這特徵臉有點恐怖,不是說好提取完是張偉嗎)
在這裏插入圖片描述

3.給定圖像數據集,探討PCA降維後特徵個數與聚類性能的關係
在這裏插入圖片描述

任務解決

1、今天要用到python的庫cv2(版本更新被合併到opencv_python裏了),提前裝一下

pip install opencv_python -i https://pypi.tuna.tsinghua.edu.cn/simple

在這裏插入圖片描述

import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.cluster import KMeans
from PIL import Image
from ML_clustering_performance import clusteringMetrics

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20  # 列
IMAGE_ROW = 10  # 行
to_image = Image.new('RGB', (IMAGE_COLUMN * w, IMAGE_ROW * h))


def createDatabase(path):
    # 查看路徑下所有文件
    TrainFiles = os.listdir(path)  # 遍歷每個子文件夾
    # 計算有幾個文件(圖片命名都是以 序號.jpg方式)
    Train_Number = len(TrainFiles)  # 子文件夾個數
    train = []
    y_sample = []
    # 把所有圖片轉爲1維並存入T中
    for k in range(0, Train_Number):
        Trainneed = os.listdir(path + '/' + TrainFiles[k])  # 遍歷每個子文件夾裏的每張圖片
        Trainneednumber = len(Trainneed)  # 每個子文件裏的圖片個數
        for i in range(0, Trainneednumber):
            img = Image.open(path + '/' + TrainFiles[k] + '/' + Trainneed[i])
            to_image.paste(img, (i * w, k * h))  # 把讀出來的圖貼到figure上
            image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)  # 數據類型轉換
            image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)  # RGB變成灰度圖
            train.append(image)
            y_sample.append(k)
    train = np.array(train)
    y_sample = np.array(y_sample)
    return train, y_sample


# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
# print(X.shape)
X_ = X.reshape(X.shape[0], h*w)

kms = KMeans(n_clusters=10)
y_sample = kms.fit_predict(X_, y)
print(clusteringMetrics(y, y_sample))

plt.imshow(to_image)
plt.show()

別人家的代碼系列)

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import matplotlib.image as imgplt
import os
import pandas as pd
from ML_clustering_performance import clusteringMetrics

name = []
target = []


def getimage():
    # 獲取文件並構成向量
    # 預測值爲1維,把一張圖片的三維(RGB)壓成1維,那麼n張圖片就是二維
    global total_photo
    file = os.listdir('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images')  # 遍歷face_images裏每個子文件夾
    i = 0
    for subfile in file:
        photo = os.listdir('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images\\' + subfile)  # 遍歷每個子文件夾裏的照片
        for name in photo:
            photo_name.append('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images\\' + subfile+'\\'+name)
            target.append(i)
        i += 1
    print(photo_name)
    for path in photo_name:
        photo = imgplt.imread(path)
        # photo = cv.imread(path)
        photo = photo.reshape(1, -1)
        photo = pd.DataFrame(photo)
        total_photo = total_photo.append(photo, ignore_index=True)
    total_photo = total_photo.values


def kmeans():
    clf = KMeans(n_clusters=10)
    clf.fit(total_photo)
    y_predict = clf.predict(total_photo)
    centers = clf.cluster_centers_
    result = centers[y_predict]
    result = result.astype("int64")
    result = result.reshape(200, 200, 180, 3)  # 圖像的矩陣大小爲200,180,3
    return result, y_predict


def draw():
    fig, ax = plt.subplots(nrows=10, ncols=20, sharex=True, sharey=True, figsize=[15, 8], dpi=80)
    plt.subplots_adjust(wspace=0, hspace=0)
    count = 0
    for i in range(10):
        for j in range(20):
            ax[i, j].imshow(result[count])
            count += 1
    plt.show()


def score():
    print(clusteringMetrics(target, y_predict))


total_photo = pd.DataFrame()
getimage()
result, y_predict = kmeans()
draw()
score()

效果圖(就這,也跑了十幾秒T∩T)
在這裏插入圖片描述
在這裏插入圖片描述

2、直接放代碼吧,PCA理論分析比較難,但用起來挺簡單的,學着別人的例子用改改參數就行了(Python真香)
參考了Scikit-learn實例之Pca+Svm人臉識別(AT&T數據集)

import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.decomposition import PCA

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20
IMAGE_ROW = 10


def createDatabase(path):
    TrainFiles = os.listdir(path)
    Train_Number = len(TrainFiles)
    train = []
    y_sample = []
    for k in range(0, Train_Number):
        Trainneed = os.listdir(path + '/' + TrainFiles[k])
        Trainneednumber = len(Trainneed)
        for i in range(0, Trainneednumber):
            image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)
            image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
            train.append(image)
            y_sample.append(k)
    train = np.array(train)
    y_sample = np.array(y_sample)
    return train, y_sample


# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
X_ = X.reshape(X.shape[0], h*w)

# 從200張圖裏挑出特徵值前10的特徵臉
n_components = 10
pca = PCA(n_components).fit(X_)  # svd_solver='randomized', whiten=True
eigenfaces = pca.components_.reshape((n_components, h, w))

# 將輸入數據投影到特徵面正交基上
X_train_pca = pca.transform(X_)


def plot_gallery(images, titles, h, w, n_row=1, n_col=10):
    """Helper function to plot a gallery of portraits"""
    plt.figure(figsize=(1.8 * n_col, 2 * n_row))
    plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)  # 圖片位置佈局
    for i in range(10):
        plt.subplot(n_row, n_col, i + 1)
        plt.imshow(images[i].reshape((h, w)))
        # plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
        plt.title(titles[i], size=12)
        # 把座標去了
        plt.xticks(())
        plt.yticks(())


eigenface_titles = ["eigenface %d" % (i+1) for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()

效果圖
在這裏插入圖片描述
3、循環聚類下畫個圖就OK了

import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from PIL import Image
from ML_clustering_performance import clusteringMetrics

path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20
IMAGE_ROW = 10


def createDatabase(path):
    TrainFiles = os.listdir(path)
    Train_Number = len(TrainFiles)
    train = []
    y_sample = []
    for k in range(0, Train_Number):
        Trainneed = os.listdir(path + '/' + TrainFiles[k])
        Trainneednumber = len(Trainneed)
        for i in range(0, Trainneednumber):
            img = Image.open(path + '/' + TrainFiles[k] + '/' + Trainneed[i])
            image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)
            image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
            train.append(image)
            y_sample.append(k)
    train = np.array(train)
    y_sample = np.array(y_sample)
    return train, y_sample


# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
X_ = X.reshape(X.shape[0], h*w)

n_components = 10

ACCS = []
NMIS = []
ARIS = []

for i in range(1, 9):
    n_components = i
    pca = PCA(n_components=n_components).fit(X_)  # svd_solver='randomized', whiten=True
    eigenfaces = pca.components_.reshape((n_components, h, w))
    # 將輸入數據投影到特徵面正交基上
    X_train_pca = pca.transform(X_)
    # 聚類
    kms = KMeans(n_clusters=10)
    y_sample = kms.fit_predict(X_train_pca, y)
    ACC, NMI, ARI = clusteringMetrics(y, y_sample)
    ACCS.append(ACC)
    NMIS.append(NMI)
    ARIS.append(ARI)

fig, ax = plt.subplots()
bar_width = 0.35
opacity = 0.4  # 不透明度
index = np.arange(8)
# error_config = {'ecolor': '0.3'}

rects1 = ax.bar(index, ACCS, bar_width, alpha=opacity, color='r', label='ACC')  # error_kw=error_config
rects2 = ax.bar(index + bar_width, NMIS, bar_width, alpha=opacity, color='g', label='NMI')
rects3 = ax.bar(index + 2*bar_width, ARIS, bar_width, alpha=opacity, color='b', label='ARI')

ax.set_xticks(index + bar_width / 2)
ax.set_xticklabels(('1', '2', '3', '4', '5', '6', '7', '8'))
ax.legend()
plt.show()

效果圖
在這裏插入圖片描述

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