《Scikit-Learn與TensorFlow機器學習實用指南》 第08章 降維

很多機器學習的問題都會涉及到有着幾千甚至數百萬維的特徵的訓練實例。這不僅讓訓練過程變得非常緩慢,同時還很難找到一個很好的解,我們接下來就會遇到這種情況。這種問題通常被稱爲維數災難(curse of dimentionality)。

幸運的是,在現實生活中我們經常可以極大的降低特徵維度,將一個十分棘手的問題轉變成一個可以較爲容易解決的問題。例如,對於 MNIST 圖片集(第 3 章中提到):圖片四周邊緣部分的像素幾乎總是白的,因此你完全可以將這些像素從你的訓練集中扔掉而不會丟失太多信息。圖 7-6 向我們證實了這些像素的確對我們的分類任務是完全不重要的。同時,兩個相鄰的像素往往是高度相關的:如果你想要將他們合併成一個像素(比如取這兩個像素點的平均值)你並不會丟失很多信息。

警告:降維肯定會丟失一些信息(這就好比將一個圖片壓縮成 JPEG 的格式會降低圖像的質量),因此即使這種方法可以加快訓練的速度,同時也會讓你的系統表現的稍微差一點。降維會讓你的工作流水線更復雜因而更難維護。所有你應該先嚐試使用原始的數據來訓練,如果訓練速度太慢的話再考慮使用降維。在某些情況下,降低訓練集數據的維度可能會篩選掉一些噪音和不必要的細節,這可能會讓你的結果比降維之前更好(這種情況通常不會發生;它只會加快你訓練的速度)。

降維除了可以加快訓練速度外,在數據可視化方面(或者 DataViz)也十分有用。降低特徵維度到 2(或者 3)維從而可以在圖中畫出一個高維度的訓練集,讓我們可以通過視覺直觀的發現一些非常重要的信息,比如聚類。

在這一章裏,我們將會討論維數災難問題並且瞭解在高維空間的數據。然後,我們將會展示兩種主要的降維方法:投影(projection)和流形學習(Manifold Learning),同時我們還會介紹三種流行的降維技術:主成分分析(PCA),核主成分分析(Kernel PCA)和局部線性嵌入(LLE)。

維數災難

我們已經習慣生活在一個三維的世界裏,以至於當我們嘗試想象更高維的空間時,我們的直覺不管用了。即使是一個基本的 4D 超正方體也很難在我們的腦中想象出來(見圖 8-1),更不用說一個 200 維的橢球彎曲在一個 1000 維的空間裏了。

圖 8-1 點,線,方形,立方體和超正方體(0D 到 4D 超正方體)

這表明很多物體在高維空間表現的十分不同。比如,如果你在一個正方形單元中隨機取一個點(一個1×1的正方形),那麼隨機選的點離所有邊界大於 0.001(靠近中間位置)的概率爲 0.4%(1 - 0.998^2)(換句話說,一個隨機產生的點不大可能嚴格落在某一個維度上。但是在一個 1,0000 維的單位超正方體(一個1×1×...×1的立方體,有 10,000 個 1),這種可能性超過了 99.999999%。在高維超正方體中,大多數點都分佈在邊界處。

還有一個更麻煩的區別:如果你在一個平方單位中隨機選取兩個點,那麼這兩個點之間的距離平均約爲 0.52。如果您在單位 3D 立方體中選取兩個隨機點,平均距離將大致爲 0.66。但是,在一個 1,000,000 維超立方體中隨機抽取兩點呢?那麼,平均距離,信不信由你,大概爲 408.25(大致

)!這非常違反直覺:當它們都位於同一單元超立方體內時,兩點是怎麼距離這麼遠的?這一事實意味着高維數據集有很大風險分佈的非常稀疏:大多數訓練實例可能彼此遠離。當然,這也意味着一個新實例可能遠離任何訓練實例,這使得預測的可靠性遠低於我們處理較低維度數據的預測,因爲它們將基於更大的推測(extrapolations)。簡而言之,訓練集的維度越高,過擬合的風險就越大。

理論上來說,維數爆炸的一個解決方案是增加訓練集的大小從而達到擁有足夠密度的訓練集。不幸的是,在實踐中,達到給定密度所需的訓練實例的數量隨着維度的數量呈指數增長。如果只有 100 個特徵(比 MNIST 問題要少得多)並且假設它們均勻分佈在所有維度上,那麼如果想要各個臨近的訓練實例之間的距離在 0.1 以內,您需要比宇宙中的原子還要多的訓練實例。

降維的主要方法

在我們深入研究具體的降維算法之前,我們來看看降低維度的兩種主要方法:投影和流形學習。

投影(Projection)

在大多數現實生活的問題中,訓練實例並不是在所有維度上均勻分佈的。許多特徵幾乎是常數,而其他特徵則高度相關(如前面討論的 MNIST)。結果,所有訓練實例實際上位於(或接近)高維空間的低維子空間內。這聽起來有些抽象,所以我們不妨來看一個例子。在圖 8-2 中,您可以看到由圓圈表示的 3D 數據集。

圖 8-2 一個分佈接近於2D子空間的3D數據集

注意到所有訓練實例的分佈都貼近一個平面:這是高維(3D)空間的較低維(2D)子空間。現在,如果我們將每個訓練實例垂直投影到這個子空間上(就像將短線連接到平面的點所表示的那樣),我們就可以得到如圖8-3所示的新2D數據集。鐺鐺鐺!我們剛剛將數據集的維度從 3D 降低到了 2D。請注意,座標軸對應於新的特徵z1z2(平面上投影的座標)。

圖 8-3 一個經過投影后的新的 2D 數據集

但是,投影並不總是降維的最佳方法。在很多情況下,子空間可能會扭曲和轉動,比如圖 8-4 所示的着名瑞士滾動玩具數據集。

圖 8-4 瑞士滾動數玩具數據集

簡單地將數據集投射到一個平面上(例如,直接丟棄x3)會將瑞士捲的不同層疊在一起,如圖 8-5 左側所示。但是,你真正想要的是展開瑞士捲所獲取到的類似圖 8-5 右側的 2D 數據集。

圖 8-5 投射到平面的壓縮(左)vs 展開瑞士捲(右)

流形學習

瑞士捲一個是二維流形的例子。簡而言之,二維流形是一種二維形狀,它可以在更高維空間中彎曲或扭曲。更一般地,一個d維流形是類似於d維超平面的n維空間(其中d < n)的一部分。在我們瑞士捲這個例子中,d = 2n = 3:它有些像 2D 平面,但是它實際上是在第三維中捲曲。

許多降維算法通過對訓練實例所在的流形進行建模從而達到降維目的;這叫做流形學習。它依賴於流形猜想(manifold assumption),也被稱爲流形假設(manifold hypothesis),它認爲大多數現實世界的高維數據集大都靠近一個更低維的流形。這種假設經常在實踐中被證實。

讓我們再回到 MNIST 數據集:所有手寫數字圖像都有一些相似之處。它們由連線組成,邊界是白色的,大多是在圖片中中間的,等等。如果你隨機生成圖像,只有一小部分看起來像手寫數字。換句話說,如果您嘗試創建數字圖像,那麼您的自由度遠低於您生成任何隨便一個圖像時的自由度。這些約束往往會將數據集壓縮到較低維流形中。

流形假設通常包含着另一個隱含的假設:你現在的手上的工作(例如分類或迴歸)如果在流形的較低維空間中表示,那麼它們會變得更簡單。例如,在圖 8-6 的第一行中,瑞士捲被分爲兩類:在三維空間中(圖左上),分類邊界會相當複雜,但在二維展開的流形空間中(圖右上),分類邊界是一條簡單的直線。

但是,這個假設並不總是成立。例如,在圖 8-6 的最下面一行,決策邊界位於x1 = 5(圖左下)。這個決策邊界在原始三維空間(一個垂直平面)看起來非常簡單,但在展開的流形中卻變得更復雜了(四個獨立線段的集合)(圖右下)。

簡而言之,如果在訓練模型之前降低訓練集的維數,那訓練速度肯定會加快,但並不總是會得出更好的訓練效果;這一切都取決於數據集。

希望你現在對於維數爆炸以及降維算法如何解決這個問題有了一定的理解,特別是對流形假設提出的內容。本章的其餘部分將介紹一些最流行的降維算法。

圖 8-6 決策邊界並不總是會在低維空間中變的簡單

主成分分析(PCA)

主成分分析(Principal Component Analysis)是目前爲止最流行的降維算法。首先它找到接近數據集分佈的超平面,然後將所有的數據都投影到這個超平面上。

保留(最大)方差

在將訓練集投影到較低維超平面之前,您首先需要選擇正確的超平面。例如圖 8-7 左側是一個簡單的二維數據集,以及三個不同的軸(即一維超平面)。圖右邊是將數據集投影到每個軸上的結果。正如你所看到的,投影到實線上保留了最大方差,而在點線上的投影只保留了非常小的方差,投影到虛線上保留的方差則處於上述兩者之間。

圖 8-7 選擇投射到哪一個子空間

選擇保持最大方差的軸看起來是合理的,因爲它很可能比其他投影損失更少的信息。證明這種選擇的另一種方法是,選擇這個軸使得將原始數據集投影到該軸上的均方距離最小。這是就 PCA 背後的思想,相當簡單。

主成分(Principle Componets)

PCA 尋找訓練集中可獲得最大方差的軸。在圖 8-7 中,它是一條實線。它還發現了一個與第一個軸正交的第二個軸,選擇它可以獲得最大的殘差。在這個 2D 例子中,沒有選擇:就只有這條點線。但如果在一個更高維的數據集中,PCA 也可以找到與前兩個軸正交的第三個軸,以及與數據集中維數相同的第四個軸,第五個軸等。

定義第i個軸的單位矢量被稱爲第i個主成分(PC)。在圖 8-7 中,第一個 PC 是c1,第二個 PC 是c2。在圖 8-2 中,前兩個 PC 用平面中的正交箭頭表示,第三個 PC 與上述 PC 形成的平面正交(指向上或下)。

概述: 主成分的方向不穩定:如果稍微打亂一下訓練集並再次運行 PCA,則某些新 PC 可能會指向與原始 PC 方向相反。但是,它們通常仍位於同一軸線上。在某些情況下,一對 PC 甚至可能會旋轉或交換,但它們定義的平面通常保持不變。

那麼如何找到訓練集的主成分呢?幸運的是,有一種稱爲奇異值分解(SVD)的標準矩陣分解技術,可以將訓練集矩陣X分解爲三個矩陣U·Σ·V^T的點積,其中V^T包含我們想要的所有主成分,如公式 8-1 所示。

公式 8-1 主成分矩陣

下面的 Python 代碼使用了 Numpy 提供的svd()函數獲得訓練集的所有主成分,然後提取前兩個 PC:

X_centered=X-X.mean(axis=0)
U,s,V=np.linalg.svd(X_centered)
c1=V.T[:,0]
c2=V.T[:,1]

警告:PCA 假定數據集以原點爲中心。正如我們將看到的,Scikit-Learn 的PCA類負責爲您的數據集中心化處理。但是,如果您自己實現 PCA(如前面的示例所示),或者如果您使用其他庫,不要忘記首先要先對數據做中心化處理。

投影到d維空間

一旦確定了所有的主成分,你就可以通過將數據集投影到由前d個主成分構成的超平面上,從而將數據集的維數降至d維。選擇這個超平面可以確保投影將保留儘可能多的方差。例如,在圖 8-2 中,3D 數據集被投影到由前兩個主成分定義的 2D 平面,保留了大部分數據集的方差。因此,2D 投影看起來非常像原始 3D 數據集。

爲了將訓練集投影到超平面上,可以簡單地通過計算訓練集矩陣XWd的點積,Wd定義爲包含前d個主成分的矩陣(即由V^T的前d列組成的矩陣),如公式 8-2 所示。

公式 8-2 將訓練集投影到d維空間

下面的 Python 代碼將訓練集投影到由前兩個主成分定義的超平面上:

W2=V.T[:,:2]
X2D=X_centered.dot(W2)

好了你已經知道這個東西了!你現在已經知道如何給任何一個數據集降維而又能儘可能的保留原數據集的方差了。

使用 Scikit-Learn

Scikit-Learn 的 PCA 類使用 SVD 分解來實現,就像我們之前做的那樣。以下代碼應用 PCA 將數據集的維度降至兩維(請注意,它會自動處理數據的中心化):

from sklearn.decomposition import PCA

pca=PCA(n_components=2)
X2D=pca.fit_transform(X)

將 PCA 轉化器應用於數據集後,可以使用components_訪問每一個主成分(注意,它返回以 PC 作爲水平向量的矩陣,因此,如果我們想要獲得第一個主成分則可以寫成pca.components_.T[:,0])。

方差解釋率(Explained Variance Ratio)

另一個非常有用的信息是每個主成分的方差解釋率,可通過explained_variance_ratio_變量獲得。它表示位於每個主成分軸上的數據集方差的比例。例如,讓我們看一下圖 8-2 中表示的三維數據集前兩個分量的方差解釋率:

>>> print(pca.explained_variance_ratio_)
array([0.84248607, 0.14631839])

這表明,84.2% 的數據集方差位於第一軸,14.6% 的方差位於第二軸。第三軸的這一比例不到1.2%,因此可以認爲它可能沒有包含什麼信息。

選擇正確的維度

通常我們傾向於選擇加起來到方差解釋率能夠達到足夠佔比(例如 95%)的維度的數量,而不是任意選擇要降低到的維度數量。當然,除非您正在爲數據可視化而降低維度 -- 在這種情況下,您通常希望將維度降低到 2 或 3。

下面的代碼在不降維的情況下進行 PCA,然後計算出保留訓練集方差 95% 所需的最小維數:

pca=PCA()
pac.fit(X)
cumsum=np.cumsum(pca.explained_variance_ratio_)
d=np.argmax(cumsum>=0.95)+1

你可以設置n_components = d並再次運行 PCA。但是,有一個更好的選擇:不指定你想要保留的主成分個數,而是將n_components設置爲 0.0 到 1.0 之間的浮點數,表明您希望保留的方差比率:

pca=PCA(n_components=0.95)
X_reduced=pca.fit_transform(X)

另一種選擇是畫出方差解釋率關於維數的函數(簡單地繪製cumsum;參見圖 8-8)。曲線中通常會有一個肘部,方差解釋率停止快速增長。您可以將其視爲數據集的真正的維度。在這種情況下,您可以看到將維度降低到大約100個維度不會失去太多的可解釋方差。

圖 8-8 可解釋方差關於維數的函數

PCA 壓縮

顯然,在降維之後,訓練集佔用的空間要少得多。例如,嘗試將 PCA 應用於 MNIST 數據集,同時保留 95% 的方差。你應該發現每個實例只有 150 多個特徵,而不是原來的 784 個特徵。因此,儘管大部分方差都保留下來,但數據集現在還不到其原始大小的 20%!這是一個合理的壓縮比率,您可以看到這可以如何極大地加快分類算法(如 SVM 分類器)的速度。

通過應用 PCA 投影的逆變換,也可以將縮小的數據集解壓縮回 784 維。當然這並不會返回給你最原始的數據,因爲投影丟失了一些信息(在5%的方差內),但它可能非常接近原始數據。原始數據和重構數據之間的均方距離(壓縮然後解壓縮)被稱爲重構誤差(reconstruction error)。例如,下面的代碼將 MNIST 數據集壓縮到 154 維,然後使用inverse_transform()方法將其解壓縮回 784 維。圖 8-9 顯示了原始訓練集(左側)的幾個數字在壓縮並解壓縮後(右側)的對應數字。您可以看到有輕微的圖像質量降低,但數字仍然大部分完好無損。

pca=PCA(n_components=154)
X_mnist_reduced=pca.fit_transform(X_mnist)
X_mnist_recovered=pca.inverse_transform(X_mnist_reduced)

圖 8-9 MNIST 保留 95 方差的壓縮

逆變換的公式如公式 8-3 所示

公式 8-3 PCA逆變換,回退到原來的數據維度

增量 PCA(Incremental PCA)

先前 PCA 實現的一個問題是它需要在內存中處理整個訓練集以便 SVD 算法運行。幸運的是,我們已經開發了增量 PCA(IPCA)算法:您可以將訓練集分批,並一次只對一個批量使用 IPCA 算法。這對大型訓練集非常有用,並且可以在線應用 PCA(即在新實例到達時即時運行)。

下面的代碼將 MNIST 數據集分成 100 個小批量(使用 NumPy 的array_split()函數),並將它們提供給 Scikit-Learn 的IncrementalPCA類,以將 MNIST 數據集的維度降低到 154 維(就像以前一樣)。請注意,您必須對每個最小批次調用partial_fit()方法,而不是對整個訓練集使用fit()方法:

from sklearn.decomposition import IncrementalPCA

n_batches=100
inc_pca=IncrementalPCA(n_components=154)
for X_batch in np.array_spplit(X_mnist,n_batches):
    inc_pca.partial_fit(X_batch)
X_mnist_reduced=inc_pca.transform(X_mnist)

或者,您可以使用 NumPy 的memmap類,它允許您操作存儲在磁盤上二進制文件中的大型數組,就好像它完全在內存中;該類僅在需要時加載內存中所需的數據。由於增量 PCA 類在任何時間內僅使用數組的一小部分,因此內存使用量仍受到控制。這可以調用通常的fit()方法,如下面的代碼所示:

X_mm=np.memmap(filename,dtype='float32',mode='readonly',shape=(m,n))
batch_size=m//n_batches
inc_pca=IncrementalPCA(n_components=154,batch_size=batch_size)
inc_pca.fit(X_mm)

隨機 PCA(Randomized PCA)

Scikit-Learn 提供了另一種執行 PCA 的選擇,稱爲隨機 PCA。這是一種隨機算法,可以快速找到前d個主成分的近似值。它的計算複雜度是O(m × d^2) + O(d^3),而不是O(m × n^2) + O(n^3),所以當d遠小於n時,它比之前的算法快得多。

rnd_pca=PCA(n_components=154,svd_solver='randomized')
X_reduced=rnd_pca.fit_transform(X_mnist)

核 PCA(Kernel PCA)

在第 5 章中,我們討論了核技巧,一種將實例隱式映射到非常高維空間(稱爲特徵空間)的數學技術,讓支持向量機可以應用於非線性分類和迴歸。回想一下,高維特徵空間中的線性決策邊界對應於原始空間中的複雜非線性決策邊界。

事實證明,同樣的技巧可以應用於 PCA,從而可以執行復雜的非線性投影來降低維度。這就是所謂的核 PCA(kPCA)。它通常能夠很好地保留投影后的簇,有時甚至可以展開分佈近似於扭曲流形的數據集。

例如,下面的代碼使用 Scikit-Learn 的KernelPCA類來執行帶有 RBF 核的 kPCA(有關 RBF 核和其他核的更多詳細信息,請參閱第 5 章):

from sklearn.decomposition import KernelPCA

rbf_pca=KernelPCA(n_components=2,kernel='rbf',gamma=0.04)
X_reduced=rbf_pca.fit_transform(X)

圖 8-10 展示了使用線性核(等同於簡單的使用 PCA 類),RBF 核,sigmoid 核(Logistic)將瑞士捲降到 2 維。

圖 8-10 使用不同核的 kPCA 將瑞士捲降到 2 維

選擇一種核並調整超參數

由於 kPCA 是無監督學習算法,因此沒有明顯的性能指標可以幫助您選擇最佳的核方法和超參數值。但是,降維通常是監督學習任務(例如分類)的準備步驟,因此您可以簡單地使用網格搜索來選擇可以讓該任務達到最佳表現的核方法和超參數。例如,下面的代碼創建了一個兩步的流水線,首先使用 kPCA 將維度降至兩維,然後應用 Logistic 迴歸進行分類。然後它使用Grid SearchCV爲 kPCA 找到最佳的核和gamma值,以便在最後獲得最佳的分類準確性:

from sklearn.model_selection import GridSearchCV 
from sklearn.linear_model import LogisticRegression 
from sklearn.pipeline import Pipeline

clf = Pipeline([
        ("kpca", KernelPCA(n_components=2)),
        ("log_reg", LogisticRegression())
])
param_grid = [{
        "kpca__gamma": np.linspace(0.03, 0.05, 10),
        "kpca__kernel": ["rbf", "sigmoid"]
    }]
grid_search = GridSearchCV(clf, param_grid, cv=3)
grid_search.fit(X, y)

你可以通過調用best_params_變量來查看使模型效果最好的核和超參數:

>>> print(grid_search.best_params_)
{'kpca__gamma': 0.043333333333333335, 'kpca__kernel': 'rbf'}

另一種完全爲非監督的方法,是選擇產生最低重建誤差的核和超參數。但是,重建並不像線性 PCA 那樣容易。這裏是原因:圖 8-11 顯示了原始瑞士捲 3D 數據集(左上角),並且使用 RBF 核應用 kPCA 後生成的二維數據集(右上角)。由於核技巧,這在數學上等同於使用特徵映射φ將訓練集映射到無限維特徵空間(右下),然後使用線性 PCA 將變換的訓練集投影到 2D。請注意,如果我們可以在縮減空間中對給定實例實現反向線性 PCA 步驟,則重構點將位於特徵空間中,而不是位於原始空間中(例如,如圖中由x表示的那樣)。由於特徵空間是無限維的,我們不能找出重建點,因此我們無法計算真實的重建誤差。幸運的是,可以在原始空間中找到一個貼近重建點的點。這被稱爲重建前圖像(reconstruction pre-image)。一旦你有這個前圖像,你就可以測量其與原始實例的平方距離。然後,您可以選擇最小化重建前圖像錯誤的核和超參數。

圖 8-11 核 PCA 和重建前圖像誤差

您可能想知道如何進行這種重建。一種解決方案是訓練一個監督迴歸模型,將預計實例作爲訓練集,並將原始實例作爲訓練目標。如果您設置了fit_inverse_transform = True,Scikit-Learn 將自動執行此操作,代碼如下所示:

rbf_pca = KernelPCA(n_components = 2, kernel="rbf", gamma=0.0433,fit_inverse_transform=True)
X_reduced = rbf_pca.fit_transform(X)
X_preimage = rbf_pca.inverse_transform(X_reduced)

概述:默認條件下,fit_inverse_transform = False並且KernelPCA沒有inverse_tranfrom()方法。這種方法僅僅當fit_inverse_transform = True的情況下才會創建。

你可以計算重建前圖像誤差:

>>> from sklearn.metrics import mean_squared_error
>>> mean_squared_error(X, X_preimage) 32.786308795766132

現在你可以使用交叉驗證的方格搜索來尋找可以最小化重建前圖像誤差的核方法和超參數。

LLE

局部線性嵌入(Locally Linear Embedding)是另一種非常有效的非線性降維(NLDR)方法。這是一種流形學習技術,不依賴於像以前算法那樣的投影。簡而言之,LLE 首先測量每個訓練實例與其最近鄰(c.n.)之間的線性關係,然後尋找能最好地保留這些局部關係的訓練集的低維表示(稍後會詳細介紹) 。這使得它特別擅長展開扭曲的流形,尤其是在沒有太多噪音的情況下。

例如,以下代碼使用 Scikit-Learn 的LocallyLinearEmbedding類來展開瑞士捲。得到的二維數據集如圖 8-12 所示。正如您所看到的,瑞士捲被完全展開,實例之間的距離保存得很好。但是,距離不能在較大範圍內保留的很好:展開的瑞士捲的左側被擠壓,而右側的部分被拉長。儘管如此,LLE 在對流形建模方面做得非常好。

from sklearn.manifold import LocallyLinearEmbedding

lle=LocallyLinearEmbedding(n_components=2,n_neighbors=10)
X_reduced=lle.fit_transform(X)

圖 8-12 使用 LLE 展開瑞士捲

這是LLE的工作原理:首先,對於每個訓練實例

,該算法識別其最近的k個鄰居(在前面的代碼中k = 10中),然後嘗試將

重構爲這些鄰居的線性函數。更具體地,找到權重

從而使

之間的平方距離儘可能的小,假設如果

不是

k個最近鄰時

。因此,LLE 的第一步是方程 8-4 中描述的約束優化問題,其中W是包含所有權重

的權重矩陣。第二個約束簡單地對每個訓練實例

的權重進行歸一化。

公式 8-4 LLE 第一步:對局部關係進行線性建模

在這步之後,權重矩陣

(包含權重

對訓練實例的線形關係進行編碼。現在第二步是將訓練實例投影到一個d維空間(d < n)中去,同時儘可能的保留這些局部關係。如果

在這個d維空間的圖像,那麼我們想要

之間的平方距離儘可能的小。這個想法讓我們提出了公式8-5中的非限制性優化問題。它看起來與第一步非常相似,但我們要做的不是保持實例固定並找到最佳權重,而是恰相反:保持權重不變,並在低維空間中找到實例圖像的最佳位置。請注意,Z是包含所有

的矩陣。

公式 8-5 LLE 第二步:保持關係的同時進行降維

Scikit-Learn 的 LLE 實現具有如下的計算複雜度:查找k個最近鄰爲O(m log(m) n log(k)),優化權重爲O(m n k^3),建立低維表示爲O(d m^2)。不幸的是,最後一項m^2使得這個算法在處理大數據集的時候表現較差。

其他降維方法

還有很多其他的降維方法,Scikit-Learn 支持其中的好幾種。這裏是其中最流行的:

  • 多維縮放(MDS)在嘗試保持實例之間距離的同時降低了維度(參見圖 8-13)
  • Isomap 通過將每個實例連接到最近的鄰居來創建圖形,然後在嘗試保持實例之間的測地距離時降低維度。
  • t-分佈隨機鄰域嵌入(t-Distributed Stochastic Neighbor Embedding,t-SNE)可以用於降低維​​度,同時試圖保持相似的實例臨近並將不相似的實例分開。它主要用於可視化,尤其是用於可視化高維空間中的實例(例如,可以將MNIST圖像降維到 2D 可視化)。
  • 線性判別分析(Linear Discriminant Analysis,LDA)實際上是一種分類算法,但在訓練過程中,它會學習類之間最有區別的軸,然後使用這些軸來定義用於投影數據的超平面。LDA 的好處是投影會儘可能地保持各個類之間距離,所以在運行另一種分類算法(如 SVM 分類器)之前,LDA 是很好的降維技術。

圖 8-13 使用不同的技術將瑞士捲降維至 2D

練習

  1. 減少數據集維度的主要動機是什麼?主要缺點是什麼?
  2. 什麼是維度爆炸?
  3. 一旦對某數據集降維,我們可能恢復它嗎?如果可以,怎樣做才能恢復?如果不可以,爲什麼?
  4. PCA 可以用於降低一個高度非線性對數據集嗎?
  5. 假設你對一個 1000 維的數據集應用 PCA,同時設置方差解釋率爲 95%,你的最終數據集將會有多少維?
  6. 在什麼情況下你會使用普通的 PCA,增量 PCA,隨機 PCA 和核 PCA?
  7. 你該如何評價你的降維算法在你數據集上的表現?
  8. 將兩個不同的降維算法串聯使用有意義嗎?
  9. 加載 MNIST 數據集(在第 3 章中介紹),並將其分成一個訓練集和一個測試集(將前 60,000 個實例用於訓練,其餘 10,000 個用於測試)。在數據集上訓練一個隨機森林分類器,並記錄了花費多長時間,然後在測試集上評估模型。接下來,使用 PCA 降低數據集的維度,設置方差解釋率爲 95%。在降維後的數據集上訓練一個新的隨機森林分類器,並查看需要多長時間。訓練速度更快?接下來評估測試集上的分類器:它與以前的分類器比較起來如何?
  10. 使用 t-SNE 將 MNIST 數據集縮減到二維,並使用 Matplotlib 繪製結果圖。您可以使用 10 種不同顏色的散點圖來表示每個圖像的目標類別。或者,您可以在每個實例的位置寫入彩色數字,甚至可以繪製數字圖像本身的降維版本(如果繪製所有數字,則可視化可能會過於混亂,因此您應該繪製隨機樣本或只在周圍沒有其他實例被繪製的情況下繪製)。你將會得到一個分隔良好的的可視化數字集羣。嘗試使用其他降維算法,如 PCA,LLE 或 MDS,並比較可視化結果。

練習答案請見附錄 A。

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