模糊Kmeans

模糊Kmeans


基本思想:首先设定一些类及每个样本对各类的隶属度; 然后通过迭代,不断调整聚类中心和隶属度至收敛。收敛条件是隶属度的变化量小于规定的阈值。

 

算法实现步骤:

 

1.给定样本个数X(个数N),类数K,迭代收敛常数e

2.给定或随机生成隶属度UU[i][j]表示第j个元素对第i类的隶属度。

3.计算各类的聚类中心Zj

 

   i=1,2........Kj=1,2......Nm>=2

 

 

4.计算新的隶属度矩阵U

 

     i=1,2........Kj=1,2......Nm>=2     

 

 

5.判断是否满足收敛条件

 

  收敛条件:

当算法收敛时聚类结束,否则返回第三步

 

6根据最终迭代的隶属度结果进行分类。

 

   j=1,2......N  

 

 

时间复杂度:O(tK2mn)

空间复杂度:O((m+K)n+Km)

 

 

 

程序运行结果图:



Python实现

注:此程序需要引入一些外部开源库,详细内容请参照网上教程,此处省略;sample.txt和membership.txt中的数据由MATLAB随机生成一定格式数据。


import math   #导入math模块
import matplotlib.pyplot as plt       #导入画图库

W=2;          #样本坐标维度(本程序只考虑二维坐标中的数据点)
N=180;         #样本数量
K=3;          #类数
M=2;          #控制模糊程度的参数
E=0.0001      #达到收敛时最小误差

#从sample.txt中读入样本坐标
X = []
for i in open("sample.txt"):
    row = [float(x) for x in i.split()]
    if len(row):
        X.append(row)

#聚类中心
Z=[ [0 for i in range(W) ] for j in range(K) ]      

#计算乘方
def pow(a,b):
    return a**b

#计算距离
def dis(x1,y1,x2,y2):
    return math.sqrt((x1-x2)**2+(y1-y2)**2)

#更新聚类中心和隶属度
def membership(U):
    #生成二维列表,K行N列
    UL=[ [ 0.0 for i in range(N)] for j in range(K)]
    #求聚类中心Z
    for i in range(0,K,1):
        s1=s2=s3=0.0 
        for j in range(0,N,1):
            s1+=pow(U[i][j],M)*X[j][0]
            s2+=pow(U[i][j],M)*X[j][1]
            s3+=pow(U[i][j],M)
        Z[i][0]=s1/s3
        Z[i][1]=s2/s3

    #求新的隶属度
    for i in range(0,K,1):
        for j in range(0,N,1):
            s=0.0
            d=dis(Z[i][0],Z[i][1],X[j][0],X[j][1])  
            if d==0:
                UL[i][j]=1
            else:
                for k in  range(0,K,1):
                    d1=dis(Z[k][0],Z[k][1],X[j][0],X[j][1])
                    s+=pow(d/d1,2/(M-1))
                UL[i][j]=1/s
    return UL

#计算新旧隶属度最大差值
def MAX_error(U,UL):
    max=0.0
    for i in range(0,K,1):
        for j in range(0,N,1):
            t=abs(UL[i][j]-U[i][j])
            if max<t:
                max=t
    return max

#画图函数,显示结果
def showMap(UL):
    #定义点的颜色,这里只定义四种,即最大为四类
    mark1 = ['or', 'ob', 'og', 'ok']
    mark2 = ['Dr', 'Db', 'Dg', 'Dk']
    #定义横纵坐标的范围
    for i in range(0,N,1):
        max=0.0
        index=0
        #找出每个点对K个类的隶属度中最高的那个,并归为那一类
        for j in range(0,K,1):
            if UL[j][i]>max:
                max=UL[j][i]
                index=j
        plt.plot(X[i][0],X[i][1],mark1[index])
    #显示聚类中心
    for i in range(0,K,1):
        plt.plot(Z[i][0],Z[i][1],mark2[i])
    plt.xlim(-5.0,20.0)
    plt.ylim(-6.0,14.0)
    plt.show()
    
            
#主函数
def main():
    #从membership.txt文件中导入初始化的隶属度
    U = []
    for i in open("membership.txt"):
        row = [float(x) for x in i.split()]
        if len(row):
            U.append(row)
            
    #归一化
    s=[0.0 for i in range(N)]  #初始化每列的和
    for i in range(0,K,1):
        for j in range(0,N,1):
            s[j]+=U[i][j]
    for i in range(0,K,1):
        for j in range(0,N,1):
            U[i][j]=U[i][j]/s[j]
            
    UL=membership(U)
    err=MAX_error(U,UL)
    
    #进行迭代,直到隶属度的最大差值小于常数E
    while(err>E):
        U=UL
        UL=membership(U)
        err=MAX_error(U,UL)

    #绘图
    showMap(UL)

#__name__作为模块的内置属性,就是.py文件的调用方式。.py文件有两种使用方式:作为模块被调用和
#直接使用。如果它等于"__main__"就表示是直接执行。  在if __name__ == "__main__":之后的
#语句作为模块被调用的时候,语句之后的代码不执行;直接使用的时候,语句之后的代码执行。
if __name__ == '__main__':
     main()


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值