网摘文苑 / python / Python 谱聚类算法从零开始

分享

   

Python 谱聚类算法从零开始

2019-08-31  网摘文苑

谱聚类算法是一种常用的无监督机器学习算法,其性能优于其他聚类方法。 此外,谱聚类实现起来非常简单,并且可以通过标准线性代数方法有效地求解。 在谱聚类算法中,根据数据点之间的相似性而不是k-均值中的绝对位置来确定数据点属于哪个类别下。具体区别可通过下图直观看出:

Python 谱聚类算法从零开始

谱聚类算法实现

谱聚类算法的基本思想是先根据样本点计算相似度矩阵,然后计算度矩阵和拉普拉斯矩阵,接着计算拉普拉斯矩阵前k个特征值对应的特征向量,最后将这k个特征值对应的特征向量组成

Python 谱聚类算法从零开始

的矩阵U,U的每一行成为一个新生成的样本点,对这些新生成的样本点进行k-means聚类,聚成k类,最后输出聚类的结果。即该算法可分为4个基本步骤:

  • 构造相似性图
  • 确定邻接矩阵W,度矩阵D和拉普拉斯矩阵L
  • 计算矩阵L的特征向量
  • 训练k均值模型并使用它来对数据进行分类

Python实现

下面就开始通过代码实现谱聚类算法。首先加载必要的库:

import numpy as npfloat_formatter = lambda x: '%.3f' % xnp.set_printoptions(formatter={'float_kind':float_formatter})from sklearn.datasets.samples_generator import make_circlesfrom sklearn.cluster import SpectralClustering, KMeansfrom sklearn.metrics import pairwise_distancesfrom matplotlib import pyplot as pltimport networkx as nximport seaborn as snssns.set()

通常我们的数据集是由样本(行)及其特征(列)组成的, 但是谱聚类算法只能应用于下图所示的节点连接的图形。

Python 谱聚类算法从零开始

因此,我们必须对数据进行转换,以便从行和列转换为图形。 假设我们有以下数据集。 我们可以清楚地看到数据可以分为三个集群。

X = np.array([ [1, 3], [2, 1], [1, 1], [3, 2], [7, 8], [9, 8], [9, 9], [8, 7], [13, 14], [14, 14], [15, 16], [14, 15]])plt.scatter(X[:,0], X[:,1], alpha=0.7, edgecolors='b')plt.xlabel('Weight')plt.ylabel('Height')

Python 谱聚类算法从零开始

首先,我们构造NxN的相似性矩阵,其中N是样本数。 矩阵的每一个点为每对点之间的欧氏距离。然后我们通过相似性矩阵来创建邻接矩阵,通过设置一个阈值,比较相似性矩阵与阈值的大小关系,如果距离大于阈值就设置为0,否则为1。然后可以使用邻接矩阵来构建图。 如果邻接矩阵的单元格中有1,那么我们在列和行的节点之间绘制一条边。创建的邻接矩阵如下:

W = pairwise_distances(X, metric='euclidean')vectorizer = np.vectorize(lambda x: 1 if x < 5 else 0)W = np.vectorize(vectorizer)(W)print(W)

Python 谱聚类算法从零开始

接下来我们通过networkx来可视化节点图形。定义绘图函数draw_graph():

def draw_graph(G): pos = nx.spring_layout(G) nx.draw_networkx_nodes(G, pos) nx.draw_networkx_labels(G, pos) nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5)

下面我们随机创建一个图并输出其邻接矩阵。

G = nx.random_graphs.erdos_renyi_graph(10, 0.5)draw_graph(G)W = nx.adjacency_matrix(G)print(W.todense())

Python 谱聚类算法从零开始

Python 谱聚类算法从零开始

当我们构建好邻接矩阵,我们就可以开始构造度矩阵。对于度矩阵的每一行,我们通过对邻接矩阵中相应行的所有元素求和来表示度矩阵的对角线。然后,我们通过从度矩阵中减去邻接矩阵来计算拉普拉斯矩阵。计算代码和计算结果如下:

# degree matrixD = np.diag(np.sum(np.array(W.todense()), axis=1))print('degree matrix:')print(D)# laplacian matrixL = D - Wprint('laplacian matrix:')print(L)

Python 谱聚类算法从零开始

根据得到拉普拉斯矩阵,我们就可以利用它的一个特殊属性来分类我们的数据。即如果图(W)具有K个连通分量,则L具有特征值为0的K个特征向量。因此,因为在我们当前的例子中我们只有一个分量,所以只有一个特征值等于0。计算特征值与特征向量代码如下:

e, v = np.linalg.eig(L)# eigenvaluesprint('eigenvalues:')print(e)# eigenvectorsprint('eigenvectors:')print(v)

Python 谱聚类算法从零开始

可以看到,计算的特征值中只有一个为0。与我们的结论完全吻合。下边我们再来验证一个有两个连通分量的示例。

G = nx.Graph()G.add_edges_from([[1, 2],[1, 3], [1, 4], [2, 3], [2, 7],[3, 4],[4, 7], [1, 7], [6, 5], [5, 8],[6, 8], [9, 8], [9, 6]])draw_graph(G)W = nx.adjacency_matrix(G)print(W.todense())

Python 谱聚类算法从零开始

计算得到的特征值和特征向量如下,可以看到特征值中有两个0.

Python 谱聚类算法从零开始

接下来我们就根据特征向量对数据进行聚类分析。

U = np.array(v[:, i[1]])km = KMeans(init='k-means++', n_clusters=3)km.fit(U)km.labels_

得到聚类标签如下:

Python 谱聚类算法从零开始

到此,我们已经基本实现了谱聚类算法,总的来说,谱聚类算法的原理并不复杂,实现起来也比较容易,文中代码比较散乱,大家可以根据文中的思路将代码组合起来,这将更有助于学习理解谱聚类算法原理。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多
    喜欢该文的人也喜欢 更多

    ×
    ×

    ¥.00

    微信或支付宝扫码支付:

    开通即同意《个图VIP服务协议》

    全部>>