在局部线性嵌入(LLE)原理总结中,咱们对流形学习中的局部线性嵌入(LLE)算法作了原理总结。这里咱们就对scikit-learn中流形学习的一些算法作一个介绍,并着重对其中LLE算法的使用方法作一个实践上的总结。html
在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的使用。函数
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’。
下面咱们用一个具体的例子来使用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))) & (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)