对给定的数据,聚类分析是许多分类和系统建模问题的基础。聚类的目的是从大量的数据中抽取固有的特征,从而获得系统行为的简洁表示。常见的聚类方法有均值聚类、分层聚类和模糊聚类方法等。

一、MATLAB 实现:

在MATLAB模糊逻辑工具箱中提供了对两种聚类方法的支持,一种是模糊C-均值聚类方法,另一种是减聚类方法。

fcm( )模糊C-均值聚类函数

subclust( )减法聚类函数

genfis2( )基于减法聚类的模糊推理系统建模函数

模糊C-均值聚类函数:在模糊C-均值聚类方法中,每一个数据点按照一定的模糊隶属度隶属于某一聚类中心。这一聚类技术作为对传统聚类技术的改进,Jim Bezdek于1981年提出。该方法首先随机选取若干聚类中心,所有数据点都被赋予对聚类中心一定的模糊隶属度,然后通过迭代方法不断修正聚类中心,迭代过程以极小化所有数据点到各个聚类中心的距离与隶属度值的加权和为优化目标。模糊C-均值聚类的输出不是一个模糊推理系统,而是聚类中心的列表以及每个数据点对各个聚类中心的隶属度值。该输出能够被进一步用来建立模糊推理系统。对应模糊C-均值聚类方法的函数为fcm( ),该函数的调用格式为[center,U,obj_fcn]=fcm(data,cluster_n)或[center,U,obj_fcn]=fcm(data,cluster_n,options)

减法聚类函数:减法聚类方法将每个数据点作为可能的聚类中心,并根据各个数据点周围的数据点密度来计算该点作为聚类中心的可能性。被选为聚类中心的数据点周围具有最高的数据点密度,同时该数据点附近的数据点被排除作为聚类中心的可能性;在选除第一个聚类中心后,从剩余的可能作为聚类中心的数据点中,继续采用类似的方法选择下一个聚类中心。这一过程一直持续到所有剩余的数据点作为聚类中心的可能性低于某一阀值时。在MATLAB模糊逻辑工具箱中,提供了函数subclust( )来完成减法聚类的功能。该函数的调用格式为[C,S]=subclust(X,radii,XBounds,options)

基于减法聚类的模糊推理系统建模函数:在减法聚类的基础上可以进行模糊推理系统的建模,模糊逻辑工具箱提供的函数genfis2( )能够实现这一功能。函数genfis2( )是一种快速的单次算法,不同于那些基于叠代过程的算法,它并不进行那些反复的优化过程。该函数的调用格式为:fisMat=genfis2(Xin,Xout,radii,Xbounds,options)

MATLAB的模糊工具箱也提供了聚类的图形用户界面工具来实现函数subclust( ) 和fcm( )以及它们的所有参数选项。在MATLAB命令窗口中输入命令:findcluster,便可打开模糊聚类图形窗口界面。

二、PYTHON 实现

模糊C均值聚类(Fuzzy C-means)算法简称FCM算法,是软聚类方法的一种。FCM算法来自《A Fuzzy Relative of the ISODATA Process and Its Use in Detecting Compact Well-Separated Clusters》和《FCM: The fuzzy c-means clustering algorithm》。

Step1:设置聚类数目c;
Step2:初始化模糊因子m、迭代允许的误差ε、迭代次数t=0和隶属度矩阵U(0),从样本中随机选取c个样本作为初始聚类中心;
Step3:根据公计算或更新隶属度矩阵U,并更新聚类中心;
Step4:比较J(t)和 J ( t − 1 );若|| J t − J ( t − 1 ) || ≤ ε,则满足迭代停止条件,迭代停止。否则置t = t + 1 ,返回Step3,继续迭代

其python代码如下:

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"])

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)

来源: 网络资料