谱聚类 - 基于 Python 的实现

谱聚类(Spectral Clustering)是一种基于图论的聚类方法,通过对数据点的相似度矩阵进行特征值分解,从而识别出数据中的簇结构。相比于传统的聚类方法,如K-means,谱聚类在处理非线性、复杂结构的数据集时表现尤为出色。

在本文中,我们将详细介绍如何使用Python实现谱聚类,包括以下几个步骤:

  1. 构建相似度矩阵: 我们首先需要计算数据点之间的相似度,可以使用高斯核函数或其他合适的相似度度量方法来构建相似度矩阵。

  2. 构造图拉普拉斯矩阵: 根据相似度矩阵,构造标准图拉普拉斯矩阵或归一化图拉普拉斯矩阵。图拉普拉斯矩阵是谱聚类的核心,反映了数据点之间的连接关系。

  3. 特征值分解: 对图拉普拉斯矩阵进行特征值分解,提取前k个最小的特征值对应的特征向量。这些特征向量构成了新的特征空间,其中数据点可以更清晰地分离。

  4. 应用聚类算法: 在特征向量构成的新特征空间中,应用K-means或其他聚类算法对数据点进行聚类。由于特征向量保留了数据点的簇结构,聚类效果会显著提升。

  5. 结果可视化: 最后,将聚类结果进行可视化展示,以便直观地理解和验证聚类效果。

结合本专栏的Kmeans一起使用。

# 文件功能:实现Spectral谱聚类算法

import numpy as np
import scipy
import pylab
import random,math

import matplotlib.pyplot as plt
from matplotlib.patches import  Ellipse
from sklearn.neighbors import kneighbors_graph
import KMeans

class Spectral(object):
    def __init__(self,n_clusters,n_neighbors = 10):
        self.n_clusters_ = n_clusters # 数量
        self.n_neighbors_ = n_neighbors # 近邻数
        self.weight_ = None # 相似度矩阵
        self.degree_ = None # 度矩阵
        self.laplacians_ = None # 拉普拉斯矩阵
        self.eigen_vector_ = None # 拉普拉斯矩阵的特征向量

    def fit(self,data):

        # step1 构造每个点的权矩阵
        weight = kneighbors_graph(data,n_neighbors=self.n_neighbors_)
        weight = 0.5 * (weight + weight.T)
        self.weight_ = weight.toarray()
        self.degree_ = np.diag(np.sum(self.weight_,axis=0).ravel())

        # step2 对所有点构造拉普拉斯矩阵,并归一化
        self.laplacians_ = self.degree_ - self.weight_
        degree_nor=np.sqrt(np.linalg.inv(self.degree_))
        self.laplacians_ = np.dot(degree_nor,self.laplacians_)
        self.laplacians_ = np.dot(self.laplacians_,degree_nor) # 归一化

        # step3 计算对应于特征向量最小k个特征值并归一化
        eigen_values,eigen_vector = np.linalg.eigh(self.laplacians_)
        sort_index = eigen_values.argsort()
        eigen_vector = eigen_vector[:,sort_index]
        self.eigen_vector_ = np.asarray([eigen_vector[:,i] for i in range(self.n_clusters_)]).T
        self.eigen_vector_ /= np.linalg.norm(self.eigen_vector_,axis=1).reshape(data.shape[0],1)

        # step4 kmeans和特征向量
        spectral_kmeans = KMeans.K_Means(n_clusters=self.n_clusters_)
        spectral_kmeans.fit(self.eigen_vector_)
        spectral_label = spectral_kmeans.predict(self.eigen_vector_)
        self.label_ = spectral_label
        self.fitted = True

    def predict(self, data):
        result = []
        if not self.fitted:
            print('Unfitter. ')
            return result
        return np.copy(self.label_)


# 生成仿真数据
def generate_X(true_Mu,true_Var):
    # 第一簇的数据
    num1,mu1,var1 = 400,true_Mu[0],true_Var[0]
    x1 = np.random.multivariate_normal(mu1,np.diag(var1),num1)
    # 第二簇的数据
    num2, mu2, var2 = 400, true_Mu[1], true_Var[1]
    x2 = np.random.multivariate_normal(mu2, np.diag(var2), num2)
    # 第三簇的数据
    num3, mu3, var3 = 400, true_Mu[2], true_Var[2]
    x3 = np.random.multivariate_normal(mu3, np.diag(var3), num3)
    # 合并在一起
    x = np.vstack((x1,x2,x3))
    # 显示数据
    plt.figure(figsize=(10,8))
    plt.axis([-10,15,-5,15])
    plt.title(u"scatter cluster before spectral")
    plt.scatter(x1[:,0],x1[:,1],s=5,c='r')
    plt.scatter(x2[:, 0], x2[:, 1], s=5, c='g')
    plt.scatter(x3[:, 0], x3[:, 1], s=5, c='y')
    plt.show()
    return x

if __name__ == '__main__':
    # 生成数据
    true_Mu = [[0.5,0.5],[5.5,2.5],[1,7]]  #生成均值
    true_Var = [[1,3],[2,2],[6,2]]
    X = generate_X(true_Mu,true_Var)

    # 进行谱聚类
    spectral = Spectral(n_clusters=3)
    K = 3
    spectral.fit(X)
    cat = spectral.predict(X)
    print(cat)
    cluster = [[] for i in range(K)]
    for i in range(len(X)):
        if cat[i] == 0:
            cluster[0].append(X[i])
        elif cat[i] == 1:
            cluster[1].append(X[i])
        elif cat[i] == 2:
            cluster[2].append(X[i])
    clusters1 = np.asarray(cluster[0])
    clusters2 = np.asarray(cluster[1])
    clusters3 = np.asarray(cluster[2])
    plt.figure(figsize=(10,8))
    plt.title(u"scatter cluster after spectral")
    plt.scatter(clusters1[:,0],clusters1[:,1],s=5,c="r")
    plt.scatter(clusters2[:,0],clusters2[:,1],s=5,c="b")
    plt.scatter(clusters3[:,0],clusters3[:,1],s=5,c="y")
    plt.show()

对比一下,三个聚类的方法:

  • 12
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值