Python实现模糊C均值聚类算法(FCM)

目录

一、模糊C均值聚类的原理 

二、不使用skfuzzy的python代码

三、 使用skfuzzy的python代码


一、模糊C均值聚类的原理 

 

二、不使用skfuzzy的python代码

import numpy as np
import random
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False


'''初始化隶属矩阵'''
def initial_u0(n,K):
    '''
    :param n:样本数量
    :param K:簇的数量
    :return: 初始化的隶属矩阵
    '''
    u0=np.zeros((K,n))
    for i in range(K):
        for j in range(n):
            if i==0:
                u0[i][j]=random.uniform(0,1)
            elif i<K-1:
                s=0
                for k in range(i):
                    s=s+u0[k][j]
                u0[i][j]=random.uniform(0,1-s)
            else:
                s=0
                for k in range(i):
                    s=s+u0[k][j]
                u0[i][j]=1-s
    return u0


'''聚类函数'''
def Cluster(U,n):
    '''
    :param U:隶属度矩阵
    :param n: 样本数量
    :return: 聚类结果
    '''
    cluster=[]
    for i in range(n):
        A=U.T[i].tolist()
        a=A.index(max(A))
        cluster.append(int(a))
    return cluster


'''计算隶属中心矩阵'''
def center(data,U,m,n,K,dim):
    '''
    :param data:样本数据
    :param U: 隶属度矩阵
    :param m: 模糊加权参数,一般取2
    :param n: 样本数量
    :param K: 聚类数目
    :param dim: 维度
    :return: 隶属中心矩阵
    '''

    '''进行初始聚类'''
    cluster=Cluster(U,n)

    '''初始化隶属中心矩阵'''
    Z=np.zeros((K,dim))

    '''计算隶属中心矩阵'''
    #初始化
    u_x=[np.zeros((1,dim)) for i in range(K)]
    u=[0 for i in range(K)]
    #计算
    for i in range(n):
        c=cluster[i]  #类别
        u[c]=u[c]+(U[c][i])**m
        u_x[c]=u_x[c]+((U[c][i])**m)*data[i]
    for i in range(K):
        Z[i]=u_x[i]/u[i]

    '''返回隶属中心矩阵'''
    return Z


'''基于欧氏距离计算各点到聚类中心的距离矩阵'''
def distinct(data,n,dim,Z,K):
    '''
    :param data:样本数据
    :param n: 样本数量
    :param dim: 数据维度
    :param Z: 隶属中心矩阵
    :param K: 聚类数目
    :return: 基于欧氏距离的距离矩阵
    '''

    '''初始化距离矩阵'''
    D=np.zeros((K,n))

    '''计算欧式距离'''
    for i in range(K):
        for j in range(n):
            z=Z[i]   #隶属中心
            df=data[j]  #数据点
            df_z=df-z
            d=0
            for k in range(dim):
                d=d+(df_z[k])**2
            d=np.sqrt(d)
            D[i][j]=d

    '''返回距离矩阵'''
    return D


'''定义目标函数并返回目标函数值'''
def function(data,Z,n,dim,K,U,m,D):
    '''
    :param data:样本数据
    :param Z: 隶属中心矩阵
    :param n: 样本数量
    :param dim: 数据维度
    :param K: 聚类数目
    :param U: 隶属度矩阵
    :param m: 模糊加权参数
    :param D: 距离矩阵
    :return: 目标函数值
    '''

    '''初始化聚类'''
    cluster=Cluster(U,n)

    '''计算目标函数值'''
    J=0    #目标函数值
    W=[0 for i in range(K)]
    for i in range(n):
        c=cluster[i]  #聚类类别
        df=data[i]    #数据点
        z=Z[c]        #聚类中心
        d=D[c][i]     #数据点到聚类中心的距离
        u=U[c][i]     #隶属度
        W[c]=W[c]+(u**m)*(d**2)
    J=sum(W)

    '''返回目标函数值'''
    return J


'''更新隶属度矩阵'''
def update_U(data,Z,n,dim,K,D,m):
    '''
    :param data:样本数据
    :param Z: 隶属中心矩阵
    :param n: 样本数量
    :param dim: 数据维度
    :param K: 聚类数目
    :param D: 距离矩阵
    :param m: 模糊加权参数
    :return: 更新后的隶属度矩阵
    '''

    '''初始化隶属度矩阵'''
    U=np.zeros((K,n))

    '''更新隶属度矩阵'''
    for i in range(K):
        for j in range(n):
            r=0
            for k in range(K):
                r=r+(D[i][j]/D[k][j])**(2/(m-1))
            U[i][j]=1/r

    '''返回更新后的隶属度矩阵'''
    return U


'''模糊C均值聚类函数'''
def FCM(data,K,Tmax,m,error):
    '''
    :param data:样本数据
    :param K: 聚类数目
    :param Tmax: 最大迭代步数
    :param m: 模糊加权参数
    :param error: 迭代停止阈值,一般取0.001至0.01
    :return: 聚类结果
    '''

    '''样本数量'''
    n=data.shape[0]

    '''数据维度'''
    dim=data.shape[1]

    '''初始化隶属度矩阵'''
    U0=initial_u0(n,K)
    U=U0.copy()

    '''存储目标函数值'''
    J=[]

    '''循环'''
    for i in range(Tmax):
        #计算隶属中心矩阵
        Z=center(data,U,m,n,K,dim)
        #基于欧氏距离计算各点到聚类中心的距离矩阵
        D=distinct(data,n,dim,Z,K)
        #计算目标函数的值
        J.append(function(data,Z,n,dim,K,U,m,D))
        #更新隶属度矩阵
        U=update_U(data,Z,n,dim,K,D,m)
        #判断阈值
        if i!=0 and abs(J[i-1]-J[i])<=error:
            break

    '''得到聚类结果'''
    cluster=Cluster(U,n)

    '''返回聚类结果(聚类类别,聚类中心,目标函数值)'''
    return cluster,Z,J[-1]


'''主函数'''
if __name__=="__main__":

    '''随机产生400组在区间[0,1]上的二维数据'''
    data=np.array([[random.uniform(0, 1) for i in range(2)] for j in range(400)])

    '''聚类'''
    cluster,cntr,J=FCM(data,K=4,Tmax=1000,m=2,error=0.0001)

    print("聚类结果:\n{}".format(cluster))
    print("目标函数值:\n{}".format(J))


    #将数据分类
    fdata=data.tolist()
    X1=[]
    Y1=[]
    X2=[]
    Y2=[]
    X3=[]
    Y3=[]
    X4=[]
    Y4=[]
    for i in range(400):
        if cluster[i]==0:
            X1.append(fdata[i][0])
            Y1.append(fdata[i][1])
        if cluster[i]==1:
            X2.append(fdata[i][0])
            Y2.append(fdata[i][1])
        if cluster[i]==2:
            X3.append(fdata[i][0])
            Y3.append(fdata[i][1])
        if cluster[i]==3:
            X4.append(fdata[i][0])
            Y4.append(fdata[i][1])

    # 聚类图
    plt.scatter(X1, Y1, c='red', marker='o')
    plt.scatter([cntr[0][0]], [cntr[0][1]], marker='>', c="black", label='聚类中心1')
    plt.scatter(X2, Y2, c='blue', marker="o")
    plt.scatter([cntr[1][0]], [cntr[1][1]], marker='<', c="black", label="聚类中心2")
    plt.scatter(X3, Y3, c='green', marker="o")
    plt.scatter([cntr[2][0]], [cntr[2][1]], marker='^', c="black", label="聚类中心3")
    plt.scatter(X4, Y4, c='orange', marker="o")
    plt.scatter([cntr[3][0]], [cntr[3][1]], marker="D", c="black", label="聚类中心4")
    plt.legend()
    plt.xlabel("x")
    plt.ylabel("y")
    plt.title("聚类图")
    plt.show()

三、 使用skfuzzy的python代码

import numpy as np
import random
import skfuzzy as fuzz
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False


'''随机产生400组在区间[0,1]上的二维数据'''
data = np.array([[random.uniform(0,1) for i in range(2)] for j in range(400)])


'''初始化隶属度矩阵(聚成4类)'''
'''
cntr:聚类中心
u:最后的隶属度矩阵
u0:初始化的隶属度矩阵
d:是一个矩阵,记录每一个点到聚类中心的欧式距离
jm:是目标函数的优化历史
p:p是迭代的次数
fpc:全称是fuzzy partition coefficient, 是一个评价分类好坏的指标,它的范围是0到1, 1表示效果最好,后面可以通过它来选择聚类的个数。
'''
cntr, u, u0, d, jm, p, fpc = fuzz.cluster.cmeans(data.T, 4, 2, error=0.0001, maxiter=1000)


'''迭代计算'''
cntr, u, u0, d, jm, p, fpc = fuzz.cluster.cmeans(data.T, 4,2, error=0.0001, maxiter=1000)


'''获得聚类结果'''
cluster_membership = np.argmax(u, axis=0)


'''绘制聚类结果'''
#将数据分类
fdata=data.tolist()
X1=[]
Y1=[]
X2=[]
Y2=[]
X3=[]
Y3=[]
X4=[]
Y4=[]
for i in range(400):
    if cluster_membership[i]==0:
        X1.append(fdata[i][0])
        Y1.append(fdata[i][1])
    if cluster_membership[i]==1:
        X2.append(fdata[i][0])
        Y2.append(fdata[i][1])
    if cluster_membership[i]==2:
        X3.append(fdata[i][0])
        Y3.append(fdata[i][1])
    if cluster_membership[i]==3:
        X4.append(fdata[i][0])
        Y4.append(fdata[i][1])

#聚类图
plt.scatter(X1,Y1,c='red',marker='o')
plt.scatter([cntr[0][0]],[cntr[0][1]],marker='>',c="black",label='聚类中心1')
plt.scatter(X2,Y2,c='blue',marker="o")
plt.scatter([cntr[1][0]],[cntr[1][1]],marker='<',c="black",label="聚类中心2")
plt.scatter(X3,Y3,c='green',marker="o")
plt.scatter([cntr[2][0]],[cntr[2][1]],marker='^',c="black",label="聚类中心3")
plt.scatter(X4,Y4,c='orange',marker="o")
plt.scatter([cntr[3][0]],[cntr[3][1]],marker="D",c="black",label="聚类中心4")
plt.legend()
plt.xlabel("x")
plt.ylabel("y")
plt.title("聚类图")
plt.show()

print(cluster_membership)
'''
print("cntr:\n{}".format(cntr))
print("u:\n{}".format(u))
print("u0:\n{}".format(u0))
print("d:\n{}".format(d))
print("jm:\n{}".format(jm))
print("p:\n{}".format(p))
print("fpc:\n{}".format(fpc))
'''

作者:天下弈星~

物联沃分享整理
物联沃-IOTWORD物联网 » Python实现模糊C均值聚类算法(FCM)

发表回复