Kmeans和FCM算法性能比较

  1. 查阅无监督聚类的评价标准有哪些,选择其中一个标准作为后续试验的验证指标:CP
  2. 在已有数据上分别验证两种聚类算法。同时,也可以先利用kmeans算法选择初始聚类中心,然后再使用FCM聚类,观察其结果。

1、无监督聚类评价标准:
一、内部指标
内部指标主要依赖于聚类结果本身的数据来计算,用于衡量聚类结果的紧凑性和可分性。
1、紧密性(Compactness,CP):定义:计算每一个类各点到聚类中心的平均距离。
解读:CP越低,意味着类内聚类距离越近,聚类结果越紧凑。

2、间隔性(Separation,SP):定义:计算各聚类中心两两之间平均距离。
解读:SP越高,意味类间聚类距离越远,聚类结果的可分性越好。

3、轮廓系数(Silhouette Coefficient):定义:结合聚类的凝聚度和分离度来评价聚类效果。具体计算方式为,对于每个数据点,计算其到同簇内其他点的平均距离(a),以及到最近的不同簇内点的平均距离(b),然后根据公式s=(b-a)/max(a,b)计算轮廓系数。
解读:轮廓系数的值域为[-1,1],值越大表示聚类效果越好。但需要注意的是,轮廓系数不适合评价紧凑的环形数据聚类,且在DBSCAN等某些聚类算法中可能不适用。

4、Calinski-Harabasz指数(CH指标):定义:也称为方差比准则,是类别内部数据的距离平方和与类别之间的距离平方和之比。
解读:CH分数越高,聚类效果越好。它衡量了聚类结果的紧密性和可分性的综合效果。

5、Davies-Bouldin Index(DBI,戴维森堡丁指数):定义:计算任意两类别的类内距离平均距离之和除以两聚类中心距离的最大值。
解读:DBI越小,意味着类内距离越小,同时类间距离越大,聚类效果越好。但需要注意,由于使用欧式距离,对于环状分布的聚类评测效果可能较差。

6、Dunn Validity Index(DVI,邓恩指数):定义:计算任意两个簇元素的最短距离(类间)除以任意簇中的最大距离(类内)。
解读:DVI越大,意味着类间距离越大,同时类内距离越小,聚类效果越好。但对离散点的聚类测评很高,对环状分布测评效果差。

二、外部指标
外部指标需要预先知道数据的真实标签,用于比较聚类结果与真实标签的一致性。
1、准确率(Accuracy):定义:正确聚类的文档数占总文档数的比例。
解读:准确率越高,表示聚类结果与真实标签越一致。

2、兰德指数(Rand Index,RI):定义:通过排列组合原理对聚类进行评价,衡量聚类结果与真实标签的一致性。
解读:RI值越高,表示聚类结果与真实标签的一致性越好。

3、调整兰德系数(Adjusted Rand Index,ARI):定义:ARI是RI的改进版,通过调整RI的惩罚力度来更准确地评价聚类结果。
解读:ARI值越高,表示聚类结果与真实标签的一致性越好,且比RI更具鲁棒性。

三、相对指标
相对指标通过对比不同的聚类结果,来评估哪一个聚类结构在某种意义上更好。这类指标通常用于比较不同聚类算法或不同参数设置下的聚类效果。

四、可视化方法
除了上述定量指标外,还可以使用可视化方法来评估聚类结果。例如,通过散点图、热力图等可视化工具,可以直观地观察聚类结果的分布和紧凑性,从而评估聚类算法的性能。
综上所述,无监督聚类的评价标准包括内部指标、外部指标、相对指标以及可视化方法。在实际应用中,可以根据具体需求和数据集特点选择合适的评价标准来评估聚类算法的性能。

2、算法比较
Kmeans算法:
kmeans算法又名k均值算法,K-means算法中的k表示的是聚类为k个簇,means代表取每一个聚类中数据值的均值作为该簇的中心,或者称为质心,即用每一个的类的质心对该簇进行描述。
其算法思想大致为:先从样本集中随机选取 k个样本作为簇中心,并计算所有样本与这 k个“簇中心”的距离,对于每一个样本,将其划分到与其距离最近的“簇中心”所在的簇中,对于新的簇计算各个簇的新的“簇中心”。
根据以上描述,我们大致可以猜测到实现kmeans算法的主要四点:
   (1)簇个数 k 的选择
   (2)各个样本点到“簇中心”的距离
   (3)根据新划分的簇,更新“簇中心”
   (4)重复上述2、3过程,直至"簇中心"没有移动
FCM算法:
模糊C均值聚类(Fuzzy C-means)算法
Step1:设置聚类数目c;
Step2:初始化模糊因子m、迭代允许的误差ε、迭代次数t=0和隶属度矩阵U(0),从样本中随机选取c个样本作为初始聚类中心;
Step3:根据公计算或更新隶属度矩阵U,并更新聚类中心;
Step4:比较J ( t ) J(t)J(t)和 J ( t − 1 ) J{(t-1)}J(t−1) ;若∣ ∣ J t − J ( t − 1 ) ∣ ∣ ≤ ε || J{t} - J{(t-1)} || ≤ ε∣∣Jt−J(t−1)∣∣≤ε,则满足迭代停止条件,迭代停止。否则置t = t + 1 t=t+1t=t+1,返回Step3,继续迭代

3、具体实验过程及代码:

Kmeans:
import numpy as np
import numpy.linalg as lg
import math
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import random
import copy

---------------------------------读入文件---------------------------------------

path = r’C:\Users\asus\Desktop\iris\iris.data’

以只读模式打开指定路径的文件

f = open(path, ‘r’)

读取文件内容

data = f.read()

将文件内容按空白字符(空格、换行等)分割成字符串列表

data = data.split()

---------------------------------从str获取信息的函数-----------------------------

def get_data(datastr):
“”"
从输入的字符串中提取数据部分和标签部分
:param datastr: 包含鸢尾花数据的一行字符串,格式如 “特征1,特征2,特征3,特征4,类别”
:return: 返回数据部分的numpy数组和对应的类别标签(整数表示)
“”"
species = {‘Iris-setosa’: 0, ‘Iris-versicolor’: 1, ‘Iris-virginica’: 2}
# 按逗号分割字符串,得到包含各特征和类别的列表
datastr = datastr.split(‘,’)
# 将前4个元素(特征部分)转换为浮点数列表
data_part = list(map(float, datastr[:4]))
# 根据类别字符串获取对应的整数标签
label_part = species[datastr[4]]

# 将数据部分转换为numpy数组
data_part = np.array(data_part)
return data_part, label_part

---------------------------------创建样本空间向量集合----------------------------

Iris_data_list = []
Iris_label_list = []

遍历读取到的每一行数据(代表一个鸢尾花样本)

for iris in data:
# 调用get_data函数获取数据和标签,并分别添加到对应的列表中
iris_data, iris_label = get_data(iris)
Iris_data_list.append(iris_data)
Iris_label_list.append(iris_label)

----------------------------------初始化K个聚类中心-----------------------------

K = 3 # 聚类中心个数
z = [] # 存放K个聚类中心
while True:
# 随机从样本数据列表中选择一个作为新的聚类中心候选
newz = random.choice(Iris_data_list)
same_flag = False
# 检查新的候选聚类中心是否已存在于已选的聚类中心列表中
for i in z:
if (i == newz).all():
same_flag = True
if not same_flag:
z.append(newz)
if len(z) == K:
break

断言确保最终得到的聚类中心个数确实为K

assert len(z) == K
print(“初始聚类中心:”, z)

用于存储每次迭代的紧密性指标CP的值

cp_list = []

-----------------------------------迭代------------------------------------------

iterations_num = 0 # 迭代次数计数器
while True:
z_old = copy.copy(z)
clusters = [[] for i in range(K)] # K个聚类蔟中包含的点
for i in range(len(Iris_data_list)):
distance = [] # 该点到K个中心的距离表
for j in range(K):
# 计算样本点到每个聚类中心的距离(使用范数计算),并添加到距离列表中
distance.append(lg.norm(Iris_data_list[i] - z[j]))
# 找到距离当前样本点最近的聚类中心的索引
nearest_zpoint = distance.index(min(distance))
# 将样本点的索引添加到对应的最近聚类中心的簇列表中
clusters[nearest_zpoint].append(i)
same_flag = True
for i in range(K):
cluster_mean = np.zeros(len(z[i]))
for j in range(len(clusters[i])):
# 计算每个簇内样本点的均值,作为新的聚类中心
cluster_mean += Iris_data_list[clusters[i][j]] / len(clusters[i])
z[i] = cluster_mean
if (z[i]!= z_old[i]).all():
same_flag = False
iterations_num += 1
print(iterations_num, “次迭代后聚类中心:”, ‘\n’, z[0], ‘\n’, z[1], ‘\n’, z[2])

# 计算紧密性CP指标
cp = 0
for i in range(K):
    for j in range(len(clusters[i])):
        # 计算簇内每个样本点到其所属聚类中心的距离,并累加
        cp += lg.norm(Iris_data_list[clusters[i][j]] - z[i])
# 计算平均距离(紧密性CP),除以样本总数
cp /= len(Iris_data_list)
cp_list.append(cp)
print("紧密性CP为:", cp)

# 计算分类准确率
clusters_labels = []
accuracy = 0
for i in range(K):
    label_list = []
    for j in range(len(clusters[i])):
        label_list.append(Iris_label_list[clusters[i][j]])
    true_label = []
    for j in range(K):
        true_label.append(label_list.count(j))
    accuracy += max(true_label)  # 选取数量最大的标签作为其标签
    print(true_label.index(max(true_label)), end=' ')
    clusters_labels.append(true_label.index(max(true_label)))
accuracy = accuracy / len(Iris_label_list)
print("分类准确率为:", accuracy)
if same_flag:
    if len(set(clusters_labels)) == K:
        print('已找到聚类结果')
    else:
        print('聚类结果错误!')
    break

绘制紧密性CP变化图(可选,用于可视化观察CP随迭代次数的变化趋势)

plt.plot(range(1, iterations_num + 1), cp_list)
plt.xlabel(‘Iteration Number’)
plt.ylabel(‘Compactness (CP)’)
plt.title(‘Compactness (CP) vs Iteration’)
plt.show()

聚类结果:
9 次迭代后聚类中心:
[6.85 3.07368421 5.74210526 2.07105263]
[5.006 3.418 1.464 0.244]
[5.9016129 2.7483871 4.39354839 1.43387097]
紧密性CP为: 0.6488394948953341
2 0 1 分类准确率为: 0.8933333333333333
已找到聚类结果在这里插入图片描述

FCM:
import numpy as np
import numpy.linalg as lg
import math
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import random
import copy

---------------------------------读入文件---------------------------------------

path = r’C:\Users\asus\Desktop\iris\iris.data’
f = open(path, ‘r’)
data = f.read()
data = data.split()

---------------------------------从str获取信息的函数-----------------------------

def get_data(datastr):
“”"
从输入的字符串中提取数据部分和标签部分。
该函数接收一个表示鸢尾花数据的字符串,格式为 “特征1,特征2,特征3,特征4,类别”,
返回特征数据的numpy数组和对应的类别标签(以整数表示)。
:param datastr: 包含鸢尾花数据的一行字符串
:return: 数据部分的numpy数组和对应的类别标签(整数表示)
“”"
species = {‘Iris-setosa’: 0, ‘Iris-versicolor’: 1, ‘Iris-virginica’: 2}
datastr = datastr.split(‘,’)
data_part = list(map(float, datastr[:4]))
label_part = species[datastr[4]]

data_part = np.array(data_part)
return data_part, label_part

---------------------------------创建样本空间向量集合----------------------------

Iris_data_list = []
Iris_label_list = []
for iris in data:
“”"
遍历读取到的每一行数据(代表一个鸢尾花样本),
通过调用get_data函数获取每个样本的特征数据和标签,
并分别添加到对应的列表中。
“”"
iris_data, iris_label = get_data(iris)
Iris_data_list.append(iris_data)
Iris_label_list.append(iris_label)

----------------------------------初始化K个聚类中心-----------------------------

K = 3 # 聚类中心个数
z = [0, 0, 0] # 存放K个聚类中心

----------------------------------初始化隶属矩阵U-------------------------------

U = np.random.rand(len(Iris_data_list), K)
“”"
初始化隶属矩阵U,使其元素为随机值,范围在0到1之间。
然后对每一行进行归一化处理,确保每行元素之和为1,
表示每个样本对于各个聚类的隶属程度总和为1。
“”"
for i in range(len(Iris_data_list)):
U[i] = U[i] / sum(U[i])

用于存储每次迭代的紧密性指标CP的值

cp_list = []

-----------------------------------迭代------------------------------------------

J = 0
a = 2 # 柔性参数
iterations_num = 0 # 迭代次数计数器
while True:
z_old = copy.copy(z)
U_old = copy.copy(U)
J_old = J

# 计算新聚类中心
for j in range(K):
    sum_ux = 0
    sum_u = 0
    for i in range(len(Iris_data_list)):
        """
        按照模糊C均值算法的规则,计算每个聚类中心的更新值。
        先分别累加 (隶属度的a次方 * 对应样本数据) 和 (隶属度的a次方),
        用于后续计算新的聚类中心坐标。
        """
        sum_ux += (U[i][j] ** a) * Iris_data_list[i]
        sum_u += U[i][j] ** a
    z[j] = sum_ux / sum_u
iterations_num += 1
print(iterations_num, "次迭代后聚类中心:", '\n', z[0], '\n', z[1], '\n', z[2])

# 计算代价函数
J = 0
for j in range(K):
    for i in range(len(Iris_data_list)):
        J += (U[i][j] ** a) * (lg.norm(z[j] - Iris_data_list[i]) ** 2)

# 计算紧密性CP指标
cp = 0
"""
按照紧密性(CP)的定义来计算,遍历每个聚类(由K表示聚类个数),
对于每个聚类中的每个样本(通过两层循环遍历),
计算样本到其所属聚类中心的距离(使用范数计算),并累加这些距离。
"""
for j in range(K):
    for i in range(len(Iris_data_list)):
        cp += lg.norm(z[j] - Iris_data_list[i])
"""
计算平均距离(紧密性CP),将累加的距离总和除以样本总数,
得到的cp值就表示当前聚类结果的紧密程度,值越小表示聚类越紧密。
"""
cp /= len(Iris_data_list)
cp_list.append(cp)
print("紧密性CP为:", cp)

# 终止条件
if abs(J - J_old) < 0.0001:
    break

# 计算新矩阵U
for i in range(len(Iris_data_list)):
    for j in range(K):
        sum_ud = 0
        for k in range(K):
            sum_ud += ((lg.norm(z[j] - Iris_data_list[i])) / (lg.norm(z[k] - Iris_data_list[i]))) ** (2 / (a - 1))
        U[i][j] = 1 / sum_ud

计算第几蔟的实际标签是什么

label_order = []
for i in range(K):
K_list = [0] * K
for j in range(len(Iris_data_list)):
if np.argmax(U[j]) == i:
K_list[Iris_label_list[j]] += 1
label_order.append(K_list.index(max(K_list)))
assert len(set(label_order)) == K, ‘出现了两类相同蔟!’

输出判断结果

for i in range(K):
print(‘第{}蔟的实际标签为:{}’.format(i + 1, label_order[i]), end=’ ')
print()

计算实际标签对应的是第几蔟

un_label_order = [0] * K
for i in range(K):
un_label_order[label_order[i]] = i

accuracy1 = 0
for i in range(len(Iris_data_list)):
if U[i][un_label_order[Iris_label_list[i]]] == max(U[i]):
accuracy1 += 1
accuracy1 /= len(Iris_data_list)
print(“归1分类准确率为:”, accuracy1)

accuracy2 = 0
for i in range(len(Iris_data_list)):
accuracy2 += U[i][un_label_order[Iris_label_list[i]]]
accuracy2 /= len(Iris_data_list)
print(“模糊分类准确率为:”, accuracy2)

绘制紧密性CP变化图

plt.plot(range(1, iterations_num + 1), cp_list)
plt.xlabel(‘Iteration Number’)
plt.ylabel(‘Compactness (CP)’)
plt.title(‘Compactness (CP) vs Iteration’)
plt.show()

19 次迭代后聚类中心:
[6.77457418 3.05227225 5.64623534 2.05334629]
[5.00356001 3.40305722 1.48496501 0.25152461]
[5.88874913 2.76107262 4.36359653 1.39710709]
紧密性CP为: 7.282550490441843
第1蔟的实际标签为:2 第2蔟的实际标签为:0 第3蔟的实际标签为:1
归1分类准确率为: 0.8933333333333333
模糊分类准确率为: 0.8249137478660143
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐