社区发现之谱聚类算法的实现


#谱聚类算法实现
#1、计算距离矩阵(欧氏距离,作为相似度矩阵)
#2、利用KNN计算邻接矩阵A
#3、由邻接矩阵计算都矩阵D和拉普拉斯矩阵L
#4、标准化拉普拉斯矩阵
#5、对拉普拉斯矩阵进行特征值分解得到特征向量
#6、对特征向量进行K-means聚类
#7、得到分类结果

import numpy as np
#距离矩阵的计算

def euclidDistance(x1, x2, sqrt_flag=False):
    res = np.sum((x1-x2)**2)
    if sqrt_flag:
        res = np.sqrt(res)
    return res

def calEuclidDistanceMatrix(X):
    #X是(500,2)的数据维度
    X = np.array(X)
    #初始化一个相似度矩阵[len(x),len(x)]
    S = np.zeros((len(X), len(X)))
    #计算相似度矩阵
    for i in range(len(X)):
        for j in range(i+1, len(X)):
            S[i][j] = 1.0 * euclidDistance(X[i], X[j])
            S[j][i] = S[i][j]
    return S



#邻接矩阵
#传入的参数是相似度矩阵Similarity和K
def myKNN(S, k, sigma=1.0):
    N = len(S)
    A = np.zeros((N,N))
    # print(S[0,:15])
    for i in range(N):
        #S[i]为相似都矩阵中的第i行的所有数据  S[i]长度为500
        dist_with_index = zip(S[i], range(15))#每一个值赋予一个编号,然后打包,相当于给节点加上编号
        #由小到大排序,按照x[0],也就是zip中的第一个值,即相似度值(相似度值,编号)
        dist_with_index = sorted(dist_with_index, key=lambda x:x[0])
        #选出K个与节点i最相关的节点,相似度矩阵中值越小,表示两点之间距离越近,相似度越大
        #所以是由小到大排序,再选择
        #得到外循环节点i的邻居节点集合
        neighbours_id = [dist_with_index[m][1] for m in range(k+1)] # xi's k nearest neighbours
        # print(neighbours_id)
        # print(dist_with_index)
        # print(len(dist_with_index))
        # if i==0:
        #     break
        #用高斯核函数计算邻接矩阵的值
        for j in neighbours_id: # xj is xi's neighbour
            A[i][j] = np.exp(-S[i][j]/2/sigma/sigma)
            A[j][i] = A[i][j] # mutually

    return A

#数据加载

from sklearn import datasets

def genTwoCircles(n_samples=1000):
    #数据和标签  (500,2)和500的维度
    X, y = datasets.make_circles(n_samples, factor=0.5, noise=0.05)
    return X, y

#拉普拉斯矩阵标准化
def calLaplacianMatrix(adjacentMatrix):

    # 计算邻接矩阵的度
    degreeMatrix = np.sum(adjacentMatrix, axis=1)#axis=1逐行相加  axis=0逐列相加


    # 将邻接矩阵转化为对角矩阵,再减去邻接矩阵就是拉普拉斯矩阵  L=D-A
    laplacianMatrix = np.diag(degreeMatrix) - adjacentMatrix

    # normailze拉普拉斯矩阵归一化操作
    # D^(-1/2) L D^(-1/2)
    sqrtDegreeMatrix = np.diag(1.0 / (degreeMatrix ** (0.5)))
    #三部分做矩阵乘法得到归一化的拉普拉斯矩阵
    return np.dot(np.dot(sqrtDegreeMatrix, laplacianMatrix), sqrtDegreeMatrix)

#画图
from matplotlib import pyplot as plt
from itertools import cycle, islice

#参数data,y_sp为特征向量聚类的标签,y_km为原始数据聚类的标签
def plot(X, y_sp, y_km):
    colors = np.array(list(islice(cycle(['#377eb8', '#ff7f00', '#4daf4a',
                                                '#f781bf', '#a65628', '#984ea3',
                                                '#999999', '#e41a1c', '#dede00']),
                                        int(max(y_km) + 1))))
    plt.subplot(121)
    plt.scatter(X[:,0], X[:,1], s=10, color=colors[y_sp])
    plt.title("Spectral Clustering")
    plt.subplot(122)
    plt.scatter(X[:,0], X[:,1], s=10, color=colors[y_km])
    plt.title("Kmeans Clustering")
    plt.show()


def main():
    import sys

    sys.path.append("..")

    from sklearn.cluster import KMeans

    np.random.seed(1)
    #data维度是(500,2),500个样本,本个样本特征维度是2
    #label是(500),表示每一个样本的标签
    data, label = genTwoCircles(n_samples=500)
    #计算相似度矩阵  (500,500)的维度
    Similarity = calEuclidDistanceMatrix(data)
    #计算邻接矩阵 k=10为每个节点选择最相似的10个邻居
    Adjacent = myKNN(Similarity, k=10)#维度是(500,500)
    #计算归一化的拉普拉斯矩阵
    Laplacian = calLaplacianMatrix(Adjacent)
    #计算拉普拉斯矩阵的特征值和特征向量 x:500  V(500,500)500个节点,每个节点特征为500维
    x, V = np.linalg.eig(Laplacian)
    #将特征值由小到大排序  对应特征向量
    x = zip(x, range(len(x)))
    x = sorted(x, key=lambda x: x[0])
    #取出特征向量来,因为特征向量是按列排的,所以要转置,用vstack推叠起来
    H = np.vstack([V[:, i] for (v, i) in x[:500]]).T
    #送入kmeans中聚类 传入的是分解后的特征向量
    sp_kmeans = KMeans(n_clusters=2).fit(H)
    #原始数据进行kmeans聚类
    pure_kmeans = KMeans(n_clusters=2).fit(data)
    #传入plot函数作图,原始数据,两种聚类的标签结果
    plot(data, sp_kmeans.labels_, pure_kmeans.labels_)

if __name__ == '__main__':
    main()

 

你可能感兴趣的:(cluster,数据挖掘,神经网络,sklearn)