Spectral Clustering 谱聚类

七月在线机器学习笔记

#谱和谱聚类


'''
方阵的谱:方阵作为线性算子,它的所有特征值的全体
谱半径:方阵最大的特征值
矩阵A的谱半径:A^{T}A的最大特征值,T即转置
谱聚类:一般的说,是一种基于图论的聚类方法,通过对样本数据的拉普拉斯矩阵的特征向量进行聚类,从而达到对样本数据聚类的目的。
'''
#谱分析的整体过程
'''
    给定一组数据x1,x2,...xn,记任意两个点之间的相似度(“距离”的减函数)为Sij=<xi,xj>,形成相似度图(similarity graph):G=(V,E) 。如果xi和xj之间
的相似度Sij大于一定的阈值,那么,两个点是连接的,权值记做Sij。[往往大于阈值的放到矩阵里,小于的直接置0]
    接下来,可以用相似度图来解决样本数据的聚类问题:找到图的一个划分,形成若干个组(Group),使得不同组之间有较低的权值,组内有较高的权值。

    W:邻接矩阵(wij) ,i,j=1,...,n    相似度矩阵
    顶点的度di-->度矩阵D(对角阵)
        di=\sum_{j}w_{ij},j=1,...,n
    A和B是图G的不相交子图,则定义子图的连接权:

         W(A,B)=\sum_{i\in A,j\in B}w_{ij}

即两个图之间所有点连接权之间的加和,越小表明应该断开    
相似度图G的建立方法:
    全连接图:高斯相似度函数---距离越大,相似度越小

   s(x_i,x_j)=e^{\frac{-||x_i-x_j||^2}{2\sigma ^2}}
    使用高斯相似度函数可以很好的建立权值矩阵。但缺点是建立的矩阵不是稀疏的
    
    ε近邻图:(当数据有不同的“密度”时,往往发生部分连接不紧密问题)
        给定参数ε,如何确定?---- 图G的权值的均值;图G的最小生成树的最大边
    k近邻图:(可以解决数据存在不同密度时有些无法连接的问题)--优先尝试
        若vi的k最近邻包含vj,vj的k最近邻不一定包含vi:有向图
        忽略方向的图,往往简称“k近邻图”
        两者都满足才连接的图,称作“互k近邻图(mutual)”
'''
#拉普拉斯矩阵及其性质:
'''
L=D - W


L_{sym}=D^{-1/2}LD^{-1/2}=I-D^{-1/2}WD^{-1/2}

L_{rw}=D^{-1}L=I-D^{-1}W      (因为前面W的定义,wii=0,则W矩阵第i行的加和即为该顶点i的度),因此D-1W的每行加和为1,因此可以表示顶点i跳到j的转移概率,pij值较大的表明i向j转移的概率较大
按照这个点的转移概率,依次转移到别的点上去,然后最终得到的那个图的过程就是它的聚类的过程------随机游走的思路

子图A的指示向量:

定理:令G是权值非负的无向图,正则拉普拉斯矩阵Lsym和Lrw的特征值0的重数k等于图 G的连通分量数。记G的连通分量为 A1,A2...Ak,则特征值0的特征向量由下列指示向量确定

性质:

     1)  L是对称半正定矩阵;

     2)  L的最小特征值是0

      3) L有n个非负实特征值0=\lambda_1\leq \lambda_2\leq ...\leq \lambda_n

      4) (λ,u)是Lrw的特征值和特征向量,当且仅当\left ( \lambda ,D^{1/2}u\right )是Lsym的特征值和特征向量;

      5) (0,E)是Lrw的特征值和特征向量,\left ( 0,D^{1/2}E \right )是Lsym的特征值和特征向量;


########马尔可夫链
'''
#谱聚类算法:------可以作为一个参考,如果某个聚类效果比它好,说明该聚类方法还不错-----实践中首选随机游走拉普拉斯矩阵
'''
输入:n个点{Pi},簇的数目k
    计算n*n的相似度矩阵W和度矩阵D;
    计算拉普拉斯矩阵L=D - W    Lsym=D^-1/2 L D-1/2   ///  Lrw=D-1L=I - D-1W
    计算L的前k个特征向量u1,u2,...,uk[特征值(降维)从小到大排的前k个]
    将k个列向量组成矩阵U,U为n*k的实数阵
    对于i=1,2,...,n ,令yi(k维列向量)为U的第 i 行的向量
    ###对于i=1,2,...,n ,将yi(k维列向量)依次单位化,使得|yi|=1###【对称拉普拉斯聚类 ,步骤】
    使用k-means算法将点(yi)聚类成簇C1,C2,...,Ck
输出:簇A1,A2,...,Ak, 其中,Ai={j | yj∈Ci}#U的第j行属于第i个簇,那么原来的第j个点就属于第i个簇
#流式聚类

'''

RatioCut

聚类问题的本质:

      对于定值k和图G,选择一组划分: A1,A2,...,Ak,最小化下面的式子:

      cut(A_1,...,A_k)=\frac{1}{2}\sum_{i=1}W(A_i,\bar{A_i})

修正目标函数

      上述的目标函数存在问题:在很多情况下, minCut的解,将图分成了一个点和其余的n- 1个点。为了避免这个问题,目标函数应该显示的要求A1,A2,...,Ak足够大。

     RatioCut(A_1,...,A_k)=\frac{1}{2}\sum_{i=1}\frac{W(A_i,\bar{A_i})}{|A_i|}=\sum_{i=1}^{k}\frac{cut(A_i,\bar{A_i})}{|A_i|}

当k=2时的RatioCut

目标函数:min_{A\subset V} RatioCut(A,\bar_A)

定义向量f=(f1,f2,...,fn)^T,

f_i=\begin{Bmatrix} \sqrt{|\bar_A|/|A|} &if, v_i\in A \\ -\sqrt{|A|/|\bar_A|} & if,v_i\in \bar_A \end{Bmatrix}

RatioCut与拉普拉斯矩阵的关系

f的约束条件

目标函数约束条件的放松relaxation

若划分为k个子集

考察指示向量组成的矩阵

目标函数

Rayleigh-Ritz理论

 

下面只是每一步的代码实现,但是我并没有得到理想的结果,并且在用np.linalg.eig()求拉普拉斯矩阵特征值和特征向量时,出现了无限接近于0但小于0的特征值,以及复数,所以还不能不能直接运行,我也找了很多办法,但可能当局者迷,我就先搁置这里了。。。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pylab
from pandas import DataFrame, Series
from keras import models, layers, optimizers, losses, metrics
from keras.utils.np_utils import to_categorical
plt.rcParams['font.sans-serif'] = ['SimHei'] #指定默认字体
plt.rcParams['axes.unicode_minus'] = False #解决保存图像是负号'-'显示为方块的问题
from sklearn.cluster import KMeans


import matplotlib.colors as colors
import matplotlib.cm as cmx


class Spectral_Cluster(object):
    def __init__(self,data,k):
        self.data=data
        self.k=k#k近邻的k值
        self.w=np.zeros((data.shape[0],data.shape[0]))#保存knn图相似度矩阵w
    def similar_matric(self,is_sqrt=True):#得到欧氏距离矩阵
        n = self.data.shape[0]
        w = np.zeros((n, n))
        for i in range(n):
            for j in range(i+1,n):
                if is_sqrt:
                    distance=np.sqrt(np.sum(np.square(self.data[i]-self.data[j])))
                else:
                    distance=1.0*np.sum(np.square(self.data[i]-self.data[j]))
                w[i,j]=distance
                w[j,i]=distance

        return w

    #knn相似度矩阵
    def get_knn_sm(self,sigma=1):#sigma,高斯核函数,带宽
        w=self.similar_matric()
        # print(w[0])
        order_w=np.argsort(w,axis=1)#得到升序后的列索引
        idx=order_w[:,1:self.k+1]#取除自身的k个

        # print(idx.shape)#n*k+1包含自身
        w_sm=np.exp(-self.similar_matric(is_sqrt=False)/(2*sigma**2))#高斯核函数,相似度函数
        for i in range(idx.shape[0]):
            for j in idx[i]:
                # self.w[i,j]=w[i,j]
                self.w[i,j]=w_sm[i,j]#将对应列放入初始化定义的self.w中
            # self.w[i,i]=0
        # print(self.w[0])
        return
    def get_diag_degree_matric(self,w):#得到D顶点度矩阵(每行元素和)
        sum_w=np.sum(w,axis=1)
        return np.diag(sum_w)
    def get_laplacian(self,sigma):#拉普拉斯矩阵
        self.get_knn_sm(sigma)
        d = self.get_diag_degree_matric(self.w)
        la=np.dot(np.linalg.inv(d),d-self.w)
        # la=d-self.w
        return np.float64(la)
    def calculate_eigenvectors(self,laplacian):#计算特征值,特征向量
        return np.linalg.eig(laplacian)#返回eigen_val,eigen_vec

    def spectral_cluster(self,laplacian,c):#k-means聚类
        eigen_val, eigen_vec=self.calculate_eigenvectors(laplacian)

        # eigen_vec=np.float64(eigen_vec)
        print(np.sort(eigen_val))
        fig=plt.figure()
        ax1=fig.add_subplot(1,1,1)
        ax1.plot(np.sort(eigen_val)[:10])
        plt.show()
        # eigen_val_idx=np.argsort(eigen_val)
        # y=eigen_vec[:,eigen_val_idx[:c]]

        sp_kmeans=KMeans(c).fit(eigen_vec)
        results=sp_kmeans.labels_
        # print(y)
        # np.random.shuffle(y)
        # clusters=y[:c]
        # # print(clusters)
        # km=KMEANS(c,clusters,y)
        # results=km.start()
        # print(results)
        return results

    def color_list(self, color_nums):
        np.random.seed(101)
        curves = [np.random.random(20) for i in range(color_nums)]
        values = range(color_nums)
        jet = cm = plt.get_cmap('jet')
        cNorm = colors.Normalize(vmin=0, vmax=values[-1])
        scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
        print(scalarMap.get_clim())
        colorVals = [scalarMap.to_rgba(values[i]) for i in range(len(curves))]
        x = np.array(colorVals)
        color_rgb = x[:, :3]
        # print(color_rgb)
        return color_rgb

    def plot(self, data,c):
        fig = plt.figure()
        ax1 = fig.add_subplot(2, 1, 1)
        ax1.scatter(self.data[:, 0], self.data[:, 1])
        ax2 = fig.add_subplot(2, 1, 2)
        colors = self.color_list(c)
        for i in range(c):
            t = np.array(data.get(i))
            for j in t:
                ax2.scatter(self.data[j,0],self.data[j,1],color=colors[i])
        plt.show()

    def start(self,c,sigma):
        la=self.get_laplacian(sigma)
        results=self.spectral_cluster(la,c)
        # print(results)
        self.plot(results,c)


from sklearn import datasets
def genTwoCircles(n_samples=200):
    X,y = datasets.make_circles(n_samples, factor=0.5, noise=0.05)
    return X, y
x,y=genTwoCircles()

n=2
data=x

sc=Spectral_Cluster(data=data,k=10)
sc.start(c=2,sigma=1)#导致谱聚类效果不太好的原因可能包含三个方面:即k:k近邻参数大小;c:划分的类别数目;sigma:高斯核函数带宽大小
#




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值