用scikit-learn研究局部線性嵌入(LLE)

局部線性嵌入(LLE)原理總結中,咱們對流形學習中的局部線性嵌入(LLE)算法作了原理總結。這裏咱們就對scikit-learn中流形學習的一些算法作一個介紹,並着重對其中LLE算法的使用方法作一個實踐上的總結。html

1、1. scikit-learn流形學習庫概述

    在scikit-learn中,流形學習庫在sklearn.manifold包中。裏面實現的流形學習算法有:python

    1)多維尺度變換MDS算法:這個對應的類是MDS。MDS算法但願在降維時在高維裏樣本之間的歐式距離關係在低維能夠獲得保留。因爲降維時它須要考慮了樣本的全局歐式距離關係,所以降維計算量很大,如今通常較少使用了。git

    2)等距映射ISOMAP算法:這個對應的類是Isomap。 ISOMAP算法使用了樣本間的測地距離來代替歐式距離,此外基本和MDS算法相同。因爲降維時它仍然須要考慮了樣本的全局測地距離關係,所以降維計算量很大。github

    3)局部線性嵌入LLE算法:這個對應的類是LocallyLinearEmbedding。這個就是咱們LLE原理篇裏面的算法、除了包含咱們原理篇裏講到的標準的LLE實現之外,它還支持改進版的LLE算法,包括MLLE,HLLE和LTSA。這三個算法咱們在原理篇的第五節有介紹。後面咱們會詳細講這個類的參數使用。算法

    4)拉普拉斯特徵映射LE算法:這個對應的類是SpectralEmbedding。這個算法使用了圖論的方法,用樣本構成的無向圖對應的拉普拉斯矩陣做特徵分解來降維。具體方法和咱們在譜聚類(spectral clustering)原理總結裏面講到的基本相同。微信

    5)t-distributed Stochastic Neighbor Embedding(t-SNE)算法:這個對應的類是TSNE。這個是一個比較新的降維方法。t-SNE但願樣本間的在高維對應的高斯核函數類似度在低維能夠獲得保留,即低維和高維有儘可能同樣的類似度矩陣。dom

    這些算法基本原理很相似,都基於流形降維後保持樣本之間的某一個特定的關係而產生。下面咱們重點講述LLE算法的使用,即LocallyLinearEmbedding的使用。函數

2、LLE算法類庫使用介紹

    LLE算法類LocallyLinearEmbedding使用起來並不複雜,通常來講,須要調參的參數只有樣本近鄰的個數。下面咱們對LocallyLinearEmbedding的主要參數作一個介紹。post

    1)n_neighbors:即咱們搜索樣本的近鄰的個數,默認是5。 n_neighbors個數越大,則創建樣本局部關係的時間會越大,也就意味着算法的複雜度會增長。固然n_neighbors個數越大,則降維後樣本的局部關係會保持的更好。在下一節咱們能夠經過具體的例子看出這一點。通常來講,若是算法運行時間能夠接受,咱們能夠儘可能選擇一個比較大一些的n_neighbors。學習

    2)n_components:即咱們降維到的維數。若是咱們降維的目的是可視化,則通常能夠選擇2-5維。

    3) reg :正則化係數,在n_neighbors大於n_components時,即近鄰數大於降維的維數時,因爲咱們的樣本權重矩陣不是滿秩的,LLE經過正則化來解決這個問題。默認是0.001。通常不用管這個參數。當近鄰數遠遠的大於降維到的維數時能夠考慮適當增大這個參數。

    4)eigen_solver:特徵分解的方法。有‘arpack’和‘dense’二者算法選擇。固然也能夠選擇'auto'讓scikit-learn本身選擇一個合適的算法。‘arpack’和‘dense’的主要區別是‘dense’通常適合於非稀疏的矩陣分解。而‘arpack’雖然能夠適應稀疏和非稀疏的矩陣分解,但在稀疏矩陣分解時會有更好算法速度。固然因爲它使用一些隨機思想,因此它的解可能不穩定,通常須要多選幾組隨機種子來嘗試。

    5)method: 即LLE的具體算法。LocallyLinearEmbedding支持4種LLE算法,分別是'standard'對應咱們標準的LLE算法,'hessian'對應原理篇講到的HLLE算法,'modified'對應原理篇講到的MLLE算法,‘ltsa’對應原理篇講到的LTSA算法。默認是'standard'。通常來講HLLE/MLLE/LTSA算法在一樣的近鄰數n_neighbors狀況下,運行時間會比標準的LLE長,固然降維的效果會稍微好一些。若是你對降維後的數據局部效果很在乎,那麼能夠考慮使用HLLE/MLLE/LTSA或者增大n_neighbors,不然標準的LLE就能夠了。須要注意的是使用MLLE要求n_neighbors >; n_components,而使用HLLE要求n_neighbors >; n_components * (n_components + 3) / 2

    6)neighbors_algorithm:這個是k近鄰的搜索方法,和KNN算法的使用的搜索方法同樣。算法一共有三種,第一種是蠻力實現,第二種是KD樹實現,第三種是球樹實現。這三種方法在K近鄰法(KNN)原理小結中都有講述,若是不熟悉能夠去複習下。對於這個參數,一共有4種可選輸入,‘brute’對應第一種蠻力實現,‘kd_tree’對應第二種KD樹實現,‘ball_tree’對應第三種的球樹實現, ‘auto’則會在上面三種算法中作權衡,選擇一個擬合最好的最優算法。須要注意的是,若是輸入樣本特徵是稀疏的時候,不管咱們選擇哪一種算法,最後scikit-learn都會去用蠻力實現‘brute’。我的的經驗,若是樣本少特徵也少,使用默認的 ‘auto’就夠了。 若是數據量很大或者特徵也不少,用"auto"建樹時間會很長,效率不高,建議選擇KD樹實現‘kd_tree’,此時若是發現‘kd_tree’速度比較慢或者已經知道樣本分佈不是很均勻時,能夠嘗試用‘ball_tree’。而若是輸入樣本是稀疏的,不管你選擇哪一個算法最後實際運行的都是‘brute’。

3、LLE用於降維可視化實踐

    下面咱們用一個具體的例子來使用scikit-learn進行LLE降維並可視化。

    完整代碼參見個人github: https://github.com/nickchen121/machinelearning/blob/master/classic-machine-learning/lle.ipynb

    首先咱們載入須要的類庫:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline
from sklearn import manifold, datasets
from sklearn.utils import check_random_state

    咱們接着生成隨機數據,因爲LLE必需要基於流形不能閉合,所以咱們生成了一個缺一個口的三維球體。生成數據並可視化的代碼以下:

n_samples = 500
random_state = check_random_state(0)
p = random_state.rand(n_samples) * (2 * np.pi - 0.55)
t = random_state.rand(n_samples) * np.pi

# 讓球體不閉合,符合流形定義
indices = ((t <; (np.pi - (np.pi / 8))) &amp; (t >; ((np.pi / 8))))
colors = p[indices]
x, y, z = np.sin(t[indices]) * np.cos(p[indices]), \
    np.sin(t[indices]) * np.sin(p[indices]), \
    np.cos(t[indices])

fig = plt.figure()
ax = Axes3D(fig, elev=30, azim=-20)
ax.scatter(x, y, z, c=p[indices], marker='o', cmap=plt.cm.rainbow)

    咱們能夠看到原始的數據是這樣的:

    如今咱們簡單的嘗試用LLE將其從三維降爲2維並可視化,近鄰數設爲30,用標準的LLE算法。

train_data = np.array([x, y, z]).T
trans_data = manifold.LocallyLinearEmbedding(n_neighbors =30, n_components = 2,
                                method='standard').fit_transform(train_data)
plt.scatter(trans_data[:, 0], trans_data[:, 1], marker='o', c=colors)

    降維到2維後的效果圖以下:

    能夠看出從三維降到了2維後,咱們大概仍是能夠看出這是一個球體。

    如今咱們看看用不一樣的近鄰數時,LLE算法降維的效果圖,代碼以下:

for index, k in enumerate((10,20,30,40)):
    plt.subplot(2,2,index+1)
    trans_data = manifold.LocallyLinearEmbedding(n_neighbors = k, n_components = 2,
                                method='standard').fit_transform(train_data)
    plt.scatter(trans_data[:, 0], trans_data[:, 1], marker='o', c=colors)
    plt.text(.99, .01, ('LLE: k=%d' % (k)),
                 transform=plt.gca().transAxes, size=10,
                 horizontalalignment='right')
plt.show()

    效果圖以下:

    如今咱們看看仍是這些k近鄰數,用HLLE的效果。

for index, k in enumerate((10,20,30,40)):
    plt.subplot(2,2,index+1)
    trans_data = manifold.LocallyLinearEmbedding(n_neighbors = k, n_components = 2,
                                method='hessian').fit_transform(train_data)
    plt.scatter(trans_data[:, 0], trans_data[:, 1], marker='o', c=colors)
    plt.text(.99, .01, ('HLLE: k=%d' % (k)),
                 transform=plt.gca().transAxes, size=10,
                 horizontalalignment='right')
plt.show()

    輸出以下:

    可見在一樣的近鄰數的時候,HLLE降維後的數據分佈特徵效果要比LLE更好。

    咱們接着看看MLLE和LTSA的效果。因爲代碼相似,這裏就只給出效果圖。

    首先是MLLE的效果圖:

    接着是LTSA的效果圖:

    從上面的一系列圖也能夠看出,一樣的k-近鄰數狀況下, MLLE,HLLE和LTSA降維的可視化效果更好。一樣的算法,k-近鄰數越大則降維可視化效果越好。固然,沒有免費的午飯,較好的降維可視化效果意味着更多的算法運行時間。

 

(歡迎轉載,轉載請註明出處。歡迎溝通交流: 微信:nickchen121)

相關文章
相關標籤/搜索