模糊C均值聚类(Fuzzy C-means)算法(FCM)

这篇具有很好参考价值的文章主要介绍了模糊C均值聚类(Fuzzy C-means)算法(FCM)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文的代码与数据地址已上传至github:https://github.com/helloWorldchn/MachineLearning

一、FCM算法简介

1、模糊集理论

L.A.Zadeh在1965年最早提出模糊集理论,在该理论中,针对传统的硬聚类算法其隶属度值非0即1的严格隶属关系,使用模糊集合理论,将原隶属度扩展为 0 到 1 之间的任意值,一个样本可以以不同的隶属度属于不同的簇集,从而极大提高了聚类算法对现实数据集的处理能力,由此模糊聚类出现在人们的视野。FCM算法广泛应用在数据挖掘、机器学习和计算机视觉与图像处理等方向。

2、FCM算法

模糊C均值聚类(Fuzzy C-means)算法简称FCM算法,是软聚类方法的一种。FCM算法最早由Dunn在1974年提出然后经 Bezdek推广。

硬聚类算法在分类时有一个硬性标准,根据该标准进行划分,分类结果非此即彼。
软聚类算法更看重隶属度,隶属度在[0,1]之间,每个对象都有属于每个类的隶属度,并且所有隶属度之和为 1,即更接近于哪一方,隶属度越高,其相似度越高。

3、算法思想

模糊 C-均值聚类(FCM)算法一种软聚类的聚类方法,该方法的思想使用
隶属度来表示每个数据之间的关系,从而确定每个数据点属于的聚类簇的聚类方法。同时 FCM 算法也是一种基于目标函数的算法,给定含有n个数据的数据集: X = { x 1 , x 2 , … x i , … , x n } X=\left\{\right.x_1,x_2,…x_i,…,x_n\left\}\right. X={x1,x2,xi,,xn} X i X_i Xi是第 i i i个特征向量; X i j X_{ij} Xij X i Xi Xi的第 j j j个属性。每个样本包含 d d d个属性。FCM算法可以将该数据集划分为 K K K类, K K K为大于1的正整数,其中 K K K个类的聚类中心分别为 [ v 1 , v 2 , … , v n ] [v_1,v _2,…,v_n] [v1,v2,,vn]
FCM的目标函数和约束条件如下:

J ( U , V ) = ∑ i = 1 n ∑ j = 1 k u i j m d i j 2 J(U,V)=\displaystyle\sum_{i=1}^{n} \displaystyle\sum_{j=1}^{k} u_{ij}^md_{ij}^2 J(U,V)=i=1nj=1kuijmdij2

∑ j = 1 k u i j = 1 , u i j ∈ [ 0 , 1 ] \displaystyle\sum_{j=1}^{k} u_{ij}=1, u_{ij}∈[0,1] j=1kuij=1,uij[0,1]

其中, u i j u_{ij} uij是样本点 x i x_i xi与聚类中心 v j v_j vj的隶属度,m是模糊指数(m>1), d i j d_{ij} dij是样本点 x i x_i xi与聚类中心 v j v_j vj的距离,一般采用欧氏距离。聚类即是求目标函数在约束条件的最小值。FCM 算法通过对目标函数的迭代优化来取得对样本集的模糊分类。

为使目标函数 J 取得最小值,在满足约束条件的情况下对目标函数使用拉格朗日(Lagrange)乘数法,得到隶属度矩阵U和聚类中心 v j v_j vj

u i j = 1 ∑ c = 1 k ( d i j d i k ) 2 m − 1 u_{ij}=\frac{1}{\displaystyle\sum_{c=1}^{k} (\frac{d_{ij}}{d_{ik}}) ^\frac{2}{m-1}} uij=c=1k(dikdij)m121

v j = ∑ i = 1 n u i j m x i ∑ i = 1 n u i j m v_j=\frac{\displaystyle\sum_{i=1}^{n} u_{ij}^m x_i }{\displaystyle\sum_{i=1}^{n} u_{ij}^m } vj=i=1nuijmi=1nuijmxi

4、算法步骤

算法的具体描述如下:

输入:聚类数c,初始聚类中心 X = { x 1 , x 2 , … x i , … , x n } X=\left\{\right.x_1,x_2,…x_i,…,x_n\left\}\right. X={x1,x2,xi,,xn},模糊指标m,终止误差
输出:聚类中心 V = [ v 1 , v 2 , … , v c ] V=[v_1,v _2,…,v_c] V=[v1,v2,,vc],隶属度矩阵 u i j u_{ij} uij
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(t1) ;若 ∣ ∣ J t − J ( t − 1 ) ∣ ∣ ≤ ε || J{t} - J{(t-1)} || ≤ ε ∣∣JtJ(t1)∣∣ε,则满足迭代停止条件,迭代停止。否则置 t = t + 1 t=t+1 t=t+1,返回Step3,继续迭代。

伪代码如下:

输入:聚类数目c,数据集$X=\left\{\right.x_1,x_2,…x_i,…,x_n\left\}\right.$,停止阈值*ε*,模糊因子*m*,最大迭代次数*T*;
输出:聚类中心$V=[v_1,v _2,…,v_c]$, 隶属度矩阵*U*;
begin
1. V ← Ø, U ← Ø, t ← 0 // 初始化聚类中心V、隶属度矩阵U和迭代次数t
2. while t < T do 
3.    for i ← 1 to n do
4.       for j ← 1 to c do
5.          calculate uij  //根据公式(2-3)计算隶属度
6.          U[i][j]= uij  //更新隶属度矩阵
7.       end for
8.    end for
9.    for j ← 1 to c do 
10.       calculate vj  //根据隶属度和公式(2-4)计算聚类中心点
11.   end for
12.   calculate J  //根据公式(2-1)重新计算目标函数J
13.   t += 1
14.   if ||J(t) - J(t-1)|| ≤ ε then
15.      return V,U
16.   end if
17.end while
18.return V,U
end

FCM流程图如下:
模糊C均值聚类(Fuzzy C-means)算法(FCM)

5、时间复杂度分析

在有n个样本的d维数据集X中,数据集被划分成c个簇,如果本次聚类经过了t次迭代,每次迭代需要计算一次目标函数,计算过程中需要分别求出d维数据中c个簇的聚类中心与n个数据的距离,算法在此过程的时间复杂度为O(ncd)。隶属度矩阵需要计算c次距离,所以每轮迭代需要的时间复杂度为O(nc2d)。综上所述模糊C均值算法的时间复杂度为O(nc2td)。但是由于在一般情况下类簇数目c、数据维度d以及算法的迭代次数t均可认为是常量,所以模糊C均值算法的时间复杂度可以简化为O(n)。由此可见,模糊C均值算法的时间复杂度随着数据点的数量增加呈线性增长,同时也受迭代次数、聚类簇数目以及数据维度的影响。

二、代码实现(Python3)

本文使用的数据集为UCI数据集,分别使用鸢尾花数据集Iris、葡萄酒数据集Wine、小麦种子数据集seeds进行测试,本文从UCI官网上将这三个数据集下载下来,并放入和python文件同一个文件夹内即可。同时由于程序需要,将数据集的列的位置做出了略微改动。数据集具体信息如下表:

数据集 样本数 属性维度 类别个数
Iris 150 4 3
Wine 178 3 3
Seeds 210 7 3

数据集在我主页资源里有,免积分下载,如果无法下载,可以私信我。

1、Python3代码实现

from pylab import *
import pandas as pd
import numpy as np
import operator
import math
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import random
from sklearn.decomposition import PCA
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import normalized_mutual_info_score  # NMI
from sklearn.metrics import rand_score  # RI
from sklearn.metrics import accuracy_score  # ACC
from sklearn.metrics import f1_score  # F-measure
from sklearn.metrics import adjusted_rand_score  # ARI

# 数据保存在.csv文件中
iris = pd.read_csv("dataset/iris.csv", header=0)  # 鸢尾花数据集 Iris  class=3
wine = pd.read_csv("dataset/wine.csv")  # 葡萄酒数据集 Wine  class=3
seeds = pd.read_csv("dataset/seeds.csv")  # 小麦种子数据集 seeds  class=3
wdbc = pd.read_csv("dataset/wdbc.csv")  # 威斯康星州乳腺癌数据集 Breast Cancer Wisconsin (Diagnostic)  class=2
glass = pd.read_csv("dataset/glass.csv")  # 玻璃辨识数据集 Glass Identification  class=6

df = iris  # 设置要读取的数据集
# print(df)
columns = list(df.columns)  # 获取数据集的第一行,第一行通常为特征名,所以先取出
features = columns[:len(columns) - 1]  # 数据集的特征名(去除了最后一列,因为最后一列存放的是标签,不是数据)
dataset = df[features]  # 预处理之后的数据,去除掉了第一行的数据(因为其为特征名,如果数据第一行不是特征名,可跳过这一步)
original_labels = list(df[columns[-1]])  # 原始标签(最后一列)
attributes = len(df.columns) - 1  # 属性数量(数据集维度)


# 初始化模糊矩阵U
def initializeMembershipMatrix():
    num_samples = df.shape[0]
    membership_mat = np.random.rand(num_samples, c)
    membership_mat = membership_mat / np.sum(membership_mat, axis=1, keepdims=True)
    return membership_mat


# 计算类中心点
def calculateClusterCenter(membership_mat, c, m):
    cluster_mem_val = zip(*membership_mat)
    cluster_centers = list()
    cluster_mem_val_list = list(cluster_mem_val)
    for j in range(c):
        x = cluster_mem_val_list[j]
        x_raised = [e ** m for e in x]
        denominator = sum(x_raised)
        temp_num = list()
        for i in range(n):
            data_point = list(dataset.iloc[i])
            prod = [x_raised[i] * val for val in data_point]
            temp_num.append(prod)
        numerator = map(sum, zip(*temp_num))
        center = [z / denominator for z in numerator]  # 每一维都要计算。
        cluster_centers.append(center)
    return cluster_centers


# 更新隶属度
def updateMembershipValue(membership_mat, cluster_centers, c):
    #    p = float(2/(m-1))
    data = []
    for i in range(n):
        x = list(dataset.iloc[i])  # 取出文件中的每一行数据
        data.append(x)
        distances = [np.linalg.norm(list(map(operator.sub, x, cluster_centers[j]))) for j in range(c)]
        for j in range(c):
            den = sum([math.pow(float(distances[j] / distances[k]), 2) for k in range(c)])
            membership_mat[i][j] = float(1 / den)
    return membership_mat, data


# 得到聚类结果
def getClusters(membership_mat):
    cluster_labels = list()
    for i in range(n):
        max_val, idx = max((val, idx) for (idx, val) in enumerate(membership_mat[i]))
        cluster_labels.append(idx)
    return cluster_labels


# FCM算法
def fuzzyCMeansClustering(c, epsilon, m, T):
    start = time.time()  # 开始时间,计时
    membership_mat = initializeMembershipMatrix()  # 初始化隶属度矩阵
    t = 0
    while t <= T:  # 最大迭代次数
        cluster_centers = calculateClusterCenter(membership_mat, c, m)  # 根据隶属度矩阵计算聚类中心
        old_membership_mat = membership_mat.copy()  # 保留之前的隶属度矩阵,同于判断迭代条件
        membership_mat, data = updateMembershipValue(membership_mat, cluster_centers, c)  # 新一轮迭代的隶属度矩阵
        cluster_labels = getClusters(membership_mat)  # 获取标签
        if np.linalg.norm(membership_mat - old_membership_mat) < epsilon:
            break
        print("第", t, "次迭代")
        t += 1

    print("用时:{0}".format(time.time() - start))
    # print(membership_mat)
    return cluster_labels, cluster_centers, data, membership_mat


# 计算聚类指标
def clustering_indicators(labels_true, labels_pred):
    if type(labels_true[0]) != int:
        labels_true = LabelEncoder().fit_transform(df[columns[len(columns) - 1]])  # 如果标签为文本类型,把文本标签转换为数字标签
    f_measure = f1_score(labels_true, labels_pred, average='macro')  # F值
    accuracy = accuracy_score(labels_true, labels_pred)  # ACC
    normalized_mutual_information = normalized_mutual_info_score(labels_true, labels_pred)  # NMI
    rand_index = rand_score(labels_true, labels_pred)  # RI
    ARI = adjusted_rand_score(labels_true, labels_pred)
    return f_measure, accuracy, normalized_mutual_information, rand_index, ARI


# 绘制聚类结果散点图
def draw_cluster(dataset, centers, labels):
    center_array = array(centers)
    if attributes > 2:
        dataset = PCA(n_components=2).fit_transform(dataset)  # 如果属性数量大于2,降维
        center_array = PCA(n_components=2).fit_transform(center_array)  # 如果属性数量大于2,降维
    else:
        dataset = array(dataset)
    # 做散点图
    label = array(labels)
    plt.scatter(dataset[:, 0], dataset[:, 1], marker='o', c='black', s=7)  # 原图
    # plt.show()
    colors = np.array(
        ["#FF0000", "#0000FF", "#00FF00", "#FFFF00", "#00FFFF", "#FF00FF", "#800000", "#008000", "#000080", "#808000",
         "#800080", "#008080", "#444444", "#FFD700", "#008080"])
    # 循换打印k个簇,每个簇使用不同的颜色
    for i in range(c):
        plt.scatter(dataset[nonzero(label == i), 0], dataset[nonzero(label == i), 1], c=colors[i], s=7, marker='o')
    # plt.scatter(center_array[:, 0], center_array[:, 1], marker='x', color='m', s=30)  # 聚类中心
    plt.show()


if __name__ == "__main__":
    c = 3  # 聚类簇数
    T = 100  # 最大迭代数
    n = len(dataset)  # 样本数
    m = 2.00  # 模糊参数
    epsilon = 1e-5
    labels, centers, data, membership = fuzzyCMeansClustering(c, epsilon, m, T)  # 运行FCM算法
    F_measure, ACC, NMI, RI, ARI = clustering_indicators(original_labels, labels)  # 计算聚类指标
    print("F_measure:", F_measure, "ACC:", ACC, "NMI", NMI, "RI", RI, "ARI", ARI)
    # print(membership)
    # print(centers)
    # print(dataset)
    draw_cluster(dataset, centers, labels)



2、聚类结果分析

本文选择了F值(F-measure,FM)、准确率(Accuracy,ACC)、标准互信息(Normalized Mutual Information,NMI)和兰德指数(Rand Index,RI)作为评估指标,其值域为[0,1],取值越大说明聚类结果越符合预期。

F值结合了精度(Precision)与召回率(Recall)两种指标,它的值为精度与召回率的调和平均,其计算公式见公式:

P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP

R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP

F − m e a s u r e = 2 R e c a l l × P r e c i s i o n R e c a l l + P r e c i s i o n F-measure=\frac{2Recall \times Precision}{Recall+Precision} Fmeasure=Recall+Precision2Recall×Precision

ACC是被正确分类的样本数与数据集总样本数的比值,计算公式如下:

A C C = T P + T N T P + T N + F P + F N ACC=\frac{TP+TN}{TP+TN+FP+FN} ACC=TP+TN+FP+FNTP+TN

其中,TP(True Positive)表示将正类预测为正类数的样本个数,TN (True Negative)表示将负类预测为负类数的样本个数,FP(False Positive)表示将负类预测为正类数误报的样本个数,FN(False Negative)表示将正类预测为负类数的样本个数。

NMI用于量化聚类结果和已知类别标签的匹配程度,相比于ACC,NMI的值不会受到族类标签排列的影响。计算公式如下:

N M I = I ( U , V ) H ( U ) H ( V ) NMI=\frac{I\left(U,V\right)}{\sqrt{H\left(U\right)H\left(V\right)}} NMI=H(U)H(V) I(U,V)

其中H(U)代表正确分类的熵,H(V)分别代表通过算法得到的结果的熵。

其具体实现代吗如下:
由于数据集中给定的正确标签可能为文本类型而不是数字标签,所以在计算前先判断数据集的标签是否为数字类型,如果不是,则转化为数字类型

def clustering_indicators(labels_true, labels_pred):
    if type(labels_true[0]) != int:
        labels_true = LabelEncoder().fit_transform(df[columns[len(columns) - 1]])  # 如果标签为文本类型,把文本标签转换为数字标签
    f_measure = f1_score(labels_true, labels_pred, average='macro')  # F值
    accuracy = accuracy_score(labels_true, labels_pred)  # ACC
    normalized_mutual_information = normalized_mutual_info_score(labels_true, labels_pred)  # NMI
    rand_index = rand_score(labels_true, labels_pred)  # RI
    return f_measure, accuracy, normalized_mutual_information, rand_index


F_measure, ACC, NMI, RI = clustering_indicators(labels_number, labels)
print("F_measure:", F_measure, "ACC:", ACC, "NMI", NMI, "RI", RI)

如果需要计算出聚类分析指标,只要将以上代码插入实现代码中即可。

3、聚类结果

  1. 鸢尾花数据集Iris
    模糊C均值聚类(Fuzzy C-means)算法(FCM)
Iris鸢尾花数据集原图

模糊C均值聚类(Fuzzy C-means)算法(FCM)

Iris鸢尾花数据集FCM聚类效果图
  1. 葡萄酒数据集Wine

模糊C均值聚类(Fuzzy C-means)算法(FCM)

Wine葡萄酒数据集原图

模糊C均值聚类(Fuzzy C-means)算法(FCM)

Wine葡萄酒数据集FCM聚类效果图
  1. 小麦种子数据集Seeds

模糊C均值聚类(Fuzzy C-means)算法(FCM)

Seeds小麦种子数据集原图

模糊C均值聚类(Fuzzy C-means)算法(FCM)

Seeds小麦种子数据集FCM聚类效果图

4、FCM算法的不足

FCM算法的核心步骤就是通过不断地迭代,更新聚类簇中心,达到簇内距离最小。算法的时间复杂度很低,因此该算法得到了广泛应用,但是该算法存在着许多不足,主要不足如下:文章来源地址https://www.toymoban.com/news/detail-485312.html

  1. FCM聚类的簇数目需要用户指定。FCM算法首先需要用户指定簇的数目C值,C值的确定直接影响聚类的结果,通常情况下,C值需要用户依据自己的经验和对数据集的理解指定,因此指定的数值未必理想,聚类的结果也就无从保证。
  2. FCM算法的初始中心点选取上采用的是随机的方法。FCM算法极为依赖初始中心点的选取:一旦错误地选取了初始中心点,对于后续的聚类过程影响极大,很可能得不到最理想的聚类结果,同时聚类迭代的次数也可能会增加。而随机选取的初始中心点具有很大的不确定性,也直接影响着聚类的效果。
  3. FCM采用欧氏距离进行相似性度量,在非凸形数据集中难以达到良好的聚类效果。

到了这里,关于模糊C均值聚类(Fuzzy C-means)算法(FCM)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 机器学习实战:Python基于K均值K-means进行聚类(九)

    1.1 K-means的介绍 K均值( K-means )是一种基于距离度量的聚类算法,其主要思想是将数据集划分为k个不同的簇,每个簇代表一个相似度较高的数据组。该算法通过迭代优化来最小化所有数据点与其所属簇的欧氏距离之和,从而找到最佳的簇划分。 需要区分一下,K-means和KNN是两

    2024年02月16日
    浏览(26)
  • R语言APRIORI关联规则、K-MEANS均值聚类分析中药专利复方治疗用药规律网络可视化...

    应用关联规则、聚类方法等数据挖掘技术分析治疗的中药专利复方组方配伍规律 ( 点击文末“阅读原文”获取完整 代码数据 )。 方法检索治疗中药专利复方,排除外用中药及中西药物合用的复方。最近我们被要求撰写关于用药规律的研究报告,包括一些图形和统计输出。

    2024年02月11日
    浏览(26)
  • 多输入多输出 | Matlab实现k-means-LSTM(k均值聚类结合长短期记忆神经网络)多输入多输出组合预测

    预测效果 基本描述 Matlab实现k-means-LSTM(k均值聚类结合长短期记忆神经网络)多输入多输出组合预测 适合负荷预测、股票预测、价格预测等。 程序设计 完整程序私信博主回复 Matlab实现k-means-LSTM(k均值聚类结合长短期记忆神经网络)多输入多输出组合预测 。 参考资料 [1]

    2024年02月07日
    浏览(31)
  • 机器学习之K-Means(k均值)算法

    K-Means算法又称K均值算法,属于聚类(clustering)算法的一种,是应用最广泛的聚类算法之一。所谓聚类,即根据相似性原则,将具有较高相似度的数据对象划分至同一类簇,将具有较高相异度的数据对象划分至不同类簇。聚类与分类最大的区别在于,聚类过程为无监督过程,

    2024年02月03日
    浏览(34)
  • k-means聚类算法详解

    什么是特征向量? 用来描述样本点的一组数据,要和我们数学中的向量区别一下,本质来说就是个数组,数组中的每个元素代表从不同角度描述样本点的值。 K-means 是我们最常用的基于 欧式距离 的聚类算法,其认为两个目标的距离越近,相似度越大。 聚类就是对大量末知标

    2024年02月16日
    浏览(24)
  • 张伟伟-层次1 Mean_shift聚类算法和其他的聚类算法

    pycharm使用的简单教程 张伟伟,男,西安工程大学电子信息学院,2019级硕士研究生,张宏伟人工智能课题组。 研究方向:机器视觉与人工智能。 电子邮件:zhangweiweicpp@163.com 个人CSDN主页:欢迎关注和相互交流学习. 代码的百度网盘链接:https://pan.baidu.com/s/1neOlGt-3240B9tjhJVOy0A

    2024年02月04日
    浏览(33)
  • 【g】聚类算法之K-means算法

    聚类算法是一种无监督学习方法,它将相似的数据样本划分为一组,同时将不相似的数据样本划分为另一组。这个过程由计算机自动完成,不需要任何人为的干预。 K-means算法是一种经典的聚类算法,它的主要思想是把数据集分成k个簇,每个簇包括距离其它各簇最近的若干个

    2024年02月08日
    浏览(31)
  • 无涯教程-聚类算法 - K-Means

    K-均值聚类算法计算质心并进行迭代,直到找到最佳质心为止,它假定群集的数目是已知的,它也称为扁平聚类算法。通过算法从数据中识别出的簇数以K均值中的\\\" K\\\"表示。 在该算法中,将数据点分配给群集,以使数据点和质心之间的平方距离之和最小。应当理解,簇内的较

    2024年02月10日
    浏览(33)
  • K-means++聚类算法(matlab实现)

    K-means++算法:K-means++算法是K-means算法的改进版,其在选择初始质心时采用了一种更加聪明的方法,能够有效地避免局部最优解。具体来说,K-means++算法的初始质心是根据距离数据点最远的原则来选择的,这样可以保证初始质心的分布更加广泛,从而使得算法更容易找到全局最

    2024年02月07日
    浏览(84)
  • 机器学习之K-means聚类算法

    目录 K-means聚类算法 算法流程 优点 缺点 随机点聚类 人脸聚类 旋转物体聚类 K-means聚类算法是一种无监督的学习方法,通过对样本数据进行分组来发现数据内在的结构。K-means的基本思想是将n个实例分成k个簇,使得同一簇内数据相似度高而不同簇之间数据相似度低。 K-means的

    2024年02月11日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包