【機器學習基礎】無監督學習(1)——PCA

Uniqe發表於2022-01-22

前面對半監督學習部分作了簡單的介紹,這裡開始瞭解有關無監督學習的部分,無監督學習內容稍微較多,本節主要介紹無監督學習中的PCA降維的基本原理和實現。


PCA

0.無監督學習簡介

相較於有監督學習和半監督學習,無監督學習就是從沒有標籤的資料中進行知識發現的過程。

更具體地說,無監督學習可以分成兩個方面,一:稱之為化繁為簡,二稱之為無中生有。

所謂化繁為簡,就是將比較複雜的資料進行“簡單化”,此時將資料作為輸入,輸出則是從資料中所發現更為“簡單”的內容,如下圖所示:

【機器學習基礎】無監督學習(1)——PCA

圖片資料中各種各樣的樹,經過function後,被“概括”為統一的“樹”表示,此時就是一個化繁為簡的過程。

而所謂無中生有,則是與上面的過程相反,給定一個“簡單”的輸入,將輸出複雜的資料(這個複雜的資料就是原資料)的過程,如圖所示:

【機器學習基礎】無監督學習(1)——PCA

假設這個“簡單”的數字,經過function之後,則生成一系列的圖片的過程,這個過程稱之為無中生有。

上面兩個方面,原資料均是沒有標籤的,不同的是一個是將資料作為“輸入”,一個是將資料作為“輸出”(這裡輸入輸出是相對的,在訓練中其實都是輸入),

這個找出function的過程就是無監督學習的過程,這些經過function之後(之前)的簡單的資料,就是從資料中所發現的知識

在理解了化繁為簡之後,那麼就可以輕易想到常見的無監督學習中,聚類、降維就屬於這一類

無中生有中,則包括了一些深度自編碼(AutoEncoder)和深度生成模型

下面我們對上面的內容一一進行介紹,前面已經對聚類進行過總結,本節主要是降維演算法中最著名的PCA。

1.降維的簡單介紹

降維是機器學習中一種常見的方法,說到降維,其原理大概可以用下圖描述:

【機器學習基礎】無監督學習(1)——PCA

一個高維的資料,經過function之後,變成一個低維的資料,而這個低維的資料仍能保留原資料的資訊。那麼為什麼資料要進行降維呢?先看兩組圖片:

【機器學習基礎】無監督學習(1)——PCA

圖1中,一個3D的圖經過降維轉化為2D之後,變得更容易分類;

而圖2中,假設原資料全是不同角度的“3”,那麼在進行這組資料時,我們不必再用28*28表示每一條資料,只需要用一個角度來描述每一條資料即可。

因此,我們希望找到這樣一個function使得高維資料降到低維資料後還能保持原來資料的資訊。

可以說,降維就是將資料從一個高維座標系降到一個新的低維的座標系的過程(不屬於同一座標系),而在新的座標系中,這些資料也能夠用來描述原資料。

除了找出function之外,降維還有一種簡單的方法,就是直接選擇特徵,如下圖:

【機器學習基礎】無監督學習(1)——PCA

如上圖所示,假設二維資料像上面那樣子的分佈情況,則在圖中可以看到,只有在x2維有關,因此此時可以直接選擇x2維作為降維後的資料。

但是當資料維度過大,且維度之間無法直接觀察出來時,就無法直接進行特徵的選擇。

下面介紹另一種降維方法,也是本節的主要內容PCA。

2.PCA基本原理

2.1 PCA基本原理的一般描述

前面說到要找一個function對資料進行降維,並且降維後的資料還能儲存原來的資訊。假設變換前的資料為X,變換後的資料為Z,並且假設這個function是線性的,那麼:

【機器學習基礎】無監督學習(1)——PCA

Z表示降維後的資料,X表示降維前的資料,高維資料通過線性變換之後得到低維資料。

PCA的任務就是找到一個W,對原資料進行降維,並儘可能保留更多的資訊。那麼這個W是如何找到呢?

現在首先假設原資料X為二維的,我們希望降維後資料Z降到一維,原資料如下圖:

【機器學習基礎】無監督學習(1)——PCA

圖中藍色的點是原資料,現在我們想要找到一個新的座標系,將資料降到一維,也就是說,找一個一維的座標系,把這些資料放到新的座標系中,有儘可能保留原資料中的資訊。

假設任意兩個一維座標系①和②,分別將原來的資料投影到①和②上,那麼投影到上面之後,究竟①和②哪一個能夠更好地描述原來的資料資訊呢?

顯然②對於原資料的資訊保留的更多,因為當把這麼資料投影到①上之後,會有更多的資料會發生重合,導致資料的辨識度不高。

原資料投影到②上之後,資料顯得更加散開,而在①上則更集中

那麼,到這裡我們用來描述好壞的指標變成了“散亂”還是“集中”,也就是方差Variance

好了,總結一下,現在我們想要找一個W,對X進行降維,使得降維之後的資料Z的方差越大越好。接下來就是如何求解這個問題了:

假設降維降到一維(注意這裡X並一定是2維,因為上面為了更好地說明問題和畫圖,假設X是二維),一條資料x降維後變成一個值(因為是1維)z1:

【機器學習基礎】無監督學習(1)——PCA

也就是說x在新的座標系的座標軸w1(注意這裡的表述,)上的投影就是z1,那麼降維後Z的方差表示為:

【機器學習基礎】無監督學習(1)——PCA

如果要把資料降維到二維(這時X就是大於2維的資料),那麼也就是我們需要在找一個座標軸w2,還要把原來的資料同時降到w2這條軸上(這裡我的理解是,想象成把原資料分別全都降到一維),那麼也就有:

【機器學習基礎】無監督學習(1)——PCA

但是這裡我們說過,w1和w2是同屬於同一座標系,因此還得保證兩個軸是相互垂直的,即:

【機器學習基礎】無監督學習(1)——PCA

同時還要保證每一個座標軸的長度為1,即:

【機器學習基礎】無監督學習(1)——PCA

同理,如果要是降維到三維,四維...則就可以把w串成一個“向量”的形式:

【機器學習基礎】無監督學習(1)——PCA

因此,只要我們找到了這個W,那麼就可以對資料進行降維了。接下來就是如何求出每一個小w了。

首先看w1,w1的方差上面已經給出了:

【機器學習基礎】無監督學習(1)——PCA

現在我們的目的是要最大化這個式子,並且有|w1|=1的約束條件,即:

【機器學習基礎】無監督學習(1)——PCA

接下來就是數學運算過程:

【機器學習基礎】無監督學習(1)——PCA

這裡Cov(x)為x的協方差,令其為S,那麼為題就變為:

【機器學習基礎】無監督學習(1)——PCA

這個問題用拉格朗日乘子進行求解,令g(x):

【機器學習基礎】無監督學習(1)——PCA

為了求解w1,這裡要對w1的每一個元素進行求導並令其為0:

【機器學習基礎】無監督學習(1)——PCA

最終再合併,得到:

【機器學習基礎】無監督學習(1)——PCA

也就是:

【機器學習基礎】無監督學習(1)——PCA

這裡S是一個矩陣,w1是一個向量,α是一個值,那麼根據線性代數內容,w1是S的一個特徵向量。

對上式再同時左乘一個(w1)T,得到:

【機器學習基礎】無監督學習(1)——PCA

因此要是其最大,需要找到最大的那個特徵值。

綜上w1就是矩陣S最大的特徵值α所對應的特徵向量

然後再看w2,同理對w2進行同樣的處理,可以得到求解w2所需要的原問題:

【機器學習基礎】無監督學習(1)——PCA

這裡和上邊求w1是一樣的,不過多了w1*w2=0的約束條件,同樣的方法,利用拉格朗日進行求解:

【機器學習基礎】無監督學習(1)——PCA

然後分別對w2中的每一個元素進行求導並令其為0:

【機器學習基礎】無監督學習(1)——PCA

得到:

【機器學習基礎】無監督學習(1)——PCA

於是:

【機器學習基礎】無監督學習(1)——PCA

得到β=0,帶回第一個式子:

【機器學習基礎】無監督學習(1)——PCA

同尋找w1一樣,這裡要想使得最大,需要找到最大的特徵值α,但由於w1已經佔了最大一個特徵值,那麼此時α為第二大的特徵。

因此,w2為矩陣S的第二大特徵值α所對應的特徵向量

以此類推,如果找w3則就是S第三大特徵值所對應的特徵向量,如果降到n維,則W就是矩陣S前n大特徵值所對應的特徵向量所組成的一個矩陣

上面就是求解W的過程,找到了W就可以對資料進行降維了,降維後的資料Z:

【機器學習基礎】無監督學習(1)——PCA

【機器學習基礎】無監督學習(1)——PCA

那麼Z的協方差矩陣Cov(Z)則是一個對角矩陣。即降維後的資料的每一個維度將會是線性無關的

證明如下:

【機器學習基礎】無監督學習(1)——PCA

2.2 另一個角度看待PCA

上面是PCA的原理的一般說明,也是通常很多資料所描述的原理,為了弄清PCA究竟是在做什麼,下面從另一個角度來看PCA。

首先,假設一個元素x是由一些基本的“零件”構成的,類似漢字的寫法等,假設在數字識別時,每一個數字是由多個筆畫所組成的,如下圖:

【機器學習基礎】無監督學習(1)——PCA

先忽略右上角的0和1數字,我們假設手寫數字識別的基本元素為u1、u2、u3...,可以看到每一個組成部分是一個簡單的筆畫,稱之為basic component。

那麼一個手寫數字我們可以認為是由這些筆畫組合而成的,比如說:

【機器學習基礎】無監督學習(1)——PCA

“7”這個資料可以看成是由u1、u3、u5構成的,那麼“7”我們用向量表示為:[1, 0, 1, 0, 1....]

原本“7”的表示維度為28*28維的,也就是說現在我們只需要找到這些component就可以用更低維度的資料來表示“7”這個數字了。那麼,這個過程就稱為降維

而上述的basic component即為上一節中的W,降維後的資料Z就是我們用這些component所表示成的向量

那麼上面的過程,一般性地,我們描述成如下這樣:

【機器學習基礎】無監督學習(1)——PCA

其中u表示basic component,c表示用basic component所組成的資料,即降維後的資料,x平均表示去中心化。

移項一下,得到:

【機器學習基礎】無監督學習(1)——PCA

於是,這裡問題就是我們想要找到一組{u1,u2,u3......}來對x進行變換,把原來的式子每一個元素都表示出來:

【機器學習基礎】無監督學習(1)——PCA

上標數字表示數量,下標表示維度。x1(上標)表示第一個樣本,c11(上標1,小標1)表示樣本x1對應u1上的那一個值。那麼上面的式子,寫成矩陣的形式:

【機器學習基礎】無監督學習(1)——PCA

每個矩陣對應的維度為:

【機器學習基礎】無監督學習(1)——PCA

因此,上面的U、Σ、V即是U和C的解,這也是PCA的一般解法,即奇異值分解。由此可以得到{u1、u2、u3...}就是Cov(X)的前K個特徵向量

上面根據奇異值分解已經求出了W,那麼可以求c,c就是降維後的資料,對於每一筆資料,我們希望它進行降維後與原來的越接近越好:

【機器學習基礎】無監督學習(1)——PCA

其實PCA可以看成是一個神經網路,假設K=2,降維前資料有3維,降到2維,那麼可以表示成下面這樣子:

【機器學習基礎】無監督學習(1)——PCA

如果,現在我們想要通過c1、c2再解回x(hat),也就是:

【機器學習基礎】無監督學習(1)——PCA

從上邊來看,整件事情我們可以把它當做一個神經網路來看,上面的式子則稱之為reconstruction error。也就是使這個損失越小越好。用數學的方式描述上面的問題:

【機器學習基礎】無監督學習(1)——PCA

這裡通過最小化L利用梯度下降進行訓練和求解:

【機器學習基礎】無監督學習(1)——PCA

這個其實就是AutoEncoder的資料重構。通過損失函式最小化,可以一同訓練引數W和c,當然中間也可以新增多個隱藏層,就成為了Deep AutoEncoder

通過這種方式也可以實現PCA的全部降維過程,只是不同於PCA的是,利用NN所求解得到的w並不能保證是垂直的,即沒有了約束條件w1*w2=0。因此得到的解與奇異值分解是不一樣的

小結:上面就是PCA的基本原理,從PCA的一般解法進行了與NN的聯絡的擴充套件理解,能夠更好地理解PCA是在做什麼事情,下面舉個PCA的例項進一步說明

3 PCA的例項

3.1 簡單資料Pokémon例項

例子來源於李宏毅老師課程,假設現在有800個寶可夢資料集,每個資料有6個維度的特徵,每一條資料代表一隻寶可夢,那麼現在對資料進行PCA降維。

首先這個6維的資料,我們要降到多少維合適呢?

一個方法就是計算協方差矩陣的6個特徵值,然後分別計算每個特徵值所佔的比例,即主成分的貢獻的程度大小:

【機器學習基礎】無監督學習(1)——PCA

特徵值的大小也就是主成分方差的大小,準確來說協方差的特徵值也就是主成分的方差(這點是可以進行證明的),特徵值越大說明主成分的貢獻程度就越大。那麼計算得到的6個特徵值如下:

【機器學習基礎】無監督學習(1)——PCA

可以看到,當選擇前四個特徵值(已排序)已經佔了大部分的比例,那麼此時可以將資料降維到4維

降維時所用的轉換矩陣W如下(注意這裡不是降維後的資料,而是四個特徵值所對應的特徵向量,也就是主成分,4個向量PC1、PC2、PC3、PC4,每個向量是6維):

【機器學習基礎】無監督學習(1)——PCA

可以看到主成分PC1全是正值,可能代表的是表示戰鬥力,主成分PC2在speed上是負的,在防禦上是正的,表示一種犧牲速度來換取防禦的屬性,以此類推。下面點雲圖是經降維後的資料,其中兩個維度及其所代表的的寶可夢(其實我沒怎麼看過),比如最上邊那個海龜,防禦力很強,但是對應的速度就很慢。

從上面的例子可以看出,PCA可以從資料中抽取一些內在的無法直觀看到的一些特徵,用這些特徵來重新表示資料,形成新的資料

3.2 PCA在手寫數字辨識上的例項

下面我們來看一下PCA在手寫數字辨識上的例子,資料跟前面深度學習中的資料集一致,先讀取一部分資料來看:

from sklearn.datasets import fetch_openml
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib as mpl

# 讀取資料
data_x, data_y = fetch_openml('mnist_784', version=1, return_X_y=True)

# 畫圖的函式
def plot_digits(instances, image_per_row=10, **options):
    size = 28
    image_per_row = min(len(instances), image_per_row)
    images = [instance.reshape(28, 28) for instance in instances]

    n_rows = (len(instances) - 1)//image_per_row + 1
    row_images = []
    n_empty = n_rows * image_per_row - len(instances)
    images.append(np.zeros((size, size * n_empty)))
    for row in range(n_rows):
        rimages = images[row*image_per_row:(row+1)*image_per_row]
        row_images.append(np.concatenate(rimages, axis=1))

    image = np.concatenate(row_images, axis=0)
    plt.imshow(image, cmap=mpl.cm.binary, **options)
    plt.axis("off")


data_x = np.array(data_x.values.tolist())
# 取前100個數字
example_images = []
for idx in range(100):
    example_images.append(data_x[idx])

plot_digits(example_images, image_per_row=10)

【機器學習基礎】無監督學習(1)——PCA

上面是原資料的圖片內容,下面開始寫一個PCA的函式,這裡主要為了理解PCA的步驟,實現以下PCA,並沒有封裝和規範化:

def pca(data, top_n_feature=9999):
    """
    :param data: 原始資料
    :param top_n_feature: 保留前n個特徵
    :return: 降維後的資料和變換矩陣w
    """

    # 去中心化,減去每一列的均值
    mean_vals = data.mean(axis=0)
    mean_std = data - mean_vals

    # 計算X的協方差矩陣
    cov_x = np.cov(mean_std, rowvar=0)

    # 計算特徵值,及其對應的特徵向量,返回的特徵值有784個,特徵向量784*784
    eig_vals, eig_vectors = np.linalg.eig(np.mat(cov_x))
    eig_vals = eig_vals.astype(float)
    eig_vectors = eig_vectors.astype(float)


    # 對特徵值進行排序,返回索引
    eig_vals_idx = np.argsort(eig_vals)

    # 找出前n大特徵值的索引
    eig_vals_idx_max_n = eig_vals_idx[:-(top_n_feature + 1): -1]

    # 找到前n大特徵值對應的特徵向量, 一個特徵向量是1列,返回維度(784, top_n)
    eig_vals_max_vec = eig_vectors[:, eig_vals_idx_max_n]

    # 前n個特徵向量為w,對高維資料進行降維z=wx, z = (100, 784) * (784, top_n)
    new_data = mean_std * eig_vals_max_vec

    # 資料的重構,根據前n個特徵重構回原資料 (100, top_n) * (top_n, 784) + (784)
    data_reconstruction = (new_data * eig_vals_max_vec.T) + mean_vals

    return new_data, eig_vals_max_vec, data_reconstruction

data = data_x[:100, :]
new_data, eig_vals_max_vec, data_reconstruction = pca(data, 40)

# 重構後的資料,即降維後再原路返回的資料
plt.figure()
plot_digits(data_reconstruction, image_per_row=10)

# 主成分
plt.figure()
plot_digits(eig_vals_max_vec.T, image_per_row=10)

【機器學習基礎】無監督學習(1)——PCA【機器學習基礎】無監督學習(1)——PCA

上面將資料降到40維,再將這40維資料 進行還原,可以看到,重構回的數字已經相當的清晰可辨識;

同時第2張圖是主成分,也就是basic component,除了前兩張勉強可以辨識出來筆畫之外,後面幾乎看不出來,這也是機器所提取出來的特徵。

這裡注意,前面說到一個圖片可以看做是這些basic component的疊加組成的,但現在根據這些主成分似乎很難拼出一張圖片,這主要是因為不僅僅是疊加,還有可能主成分之間相減

如果單純做筆畫的識別,可以用非負矩陣分解NMF,還有一種方法叫Nonnegative PCA,即約束這些降維後的c值均為正值,文獻參考http://machinelearning.wustl.edu/mlpapers/paper_files/NIPS2006_415.pdf,這裡暫時不多說了。而且這個NSPCA效果比一般PCA效果好。

當然對於Python而言,PCA有對應的工具包可以實現,sklearn中有可以呼叫的PCA工具,下面是利用sklearn進行PCA的程式碼,有關主要引數和說明已在註釋中給出。

from sklearn import decomposition
model = decomposition.PCA(n_components=40)
"""
https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html
引數:
    n_components: 可以指定降維後的維度數目,此時為大於等於1的整數;
                  也可以是指定主成分的方差和所佔的最小比例閾值,讓PCA根據樣本方差決定降維的維數,此時引數為(0, 1];
                  也可以指定引數為"mle",此時PCA會根據MLE演算法根據方差特徵的分佈情況,自主選擇一定的主成分數量;
                  當不輸入任何時,即預設n_components=min(n_examples, n_features).
    copy: bool,True或者False,預設時預設為True。表示是否在執行演算法時,將原始訓練資料複製一份。
    whiten: bool,True或者False, 是否對降維後的每一維特徵進行歸一化。
屬性:
    components_: 降維所用的轉換矩陣W,即主軸方向
    explained_variance_: 降維後各主成分的方差值,方差越大,越是主成分;
    explained_variance_ratio_: 降維後的主成分的方差值佔總方差的比例;
方法:
    fit(X): 用X訓練模型;
    fit_transform(X): 用X訓練模型,並在X上進行降維;
    transform(X): 對X進行降維,前提要先fit;
    inverse_transform: 將降維後的資料返回原來的空間;
    
"""
mew_data = model.fit_transform(data)
transform_matrix = model.components_

4.PCA的侷限性

PCA由於是無監督學習,無法完全保留樣本的資訊。比如說,下面一組資料:

【機器學習基礎】無監督學習(1)——PCA

當採用PCA降維降到1維時,為紅色的線,而加入這兩邊的資料分別屬於兩個不同的類別的話,那麼同時投影到紅色的線上時,則會產生混淆的情況,難以區分。

另外PCA是線性的,無法對空間的資料進行“拉直”,比如:

【機器學習基礎】無監督學習(1)——PCA

如果用在數字辨識上面,最終形成的結果由於其線性的原因,可能不會很好:

【機器學習基礎】無監督學習(1)——PCA

圖1是利用PCA降維的結果,圖2是一種非線性降維的方法(TSNE)這個後面會繼續說這種方法。明顯利用非線性降維的效果好於線性降維。


有關PCA的內容就先到這裡了,後面繼續對降維的方法進行總結,關於非線性的降維方法等。

相關文章