一、算法简介
K-means 算法是一种聚类算法,所谓聚类,即根据相似性原则,将具有较高相似度的数据对象划分至同一类簇,将具有较高相异度的数据对象划分至不同类簇。聚类与分类最大的区别在于,聚类过程为无监督过程,即待处理数据对象没有任何先验知识,而分类过程为有监督过程,即存在有先验知识的训练数据集。 经典的聚类算法 K-means 是通过指定聚类中心,再通过迭代的方式更新聚类中心的方 式,由于每个点都被指派到距离最近的聚类中心,所以导致其不能分析出非球面类别的数据分布。虽然有 DBSCAN(density-based spatial clustering of applications with noise)对于任意形状分布的进行聚类,但是必须指定一个密度阈值,从而去除低于此密度阈值的噪音点。 基于以上分析,在 CFDP 算法是基于这样的假设:聚类中心周围都是密度比其低的点,同时这些点距离该聚类中心的距离相比于其他聚类中心来说是最近的。新算法就是基于这两个假设来识别和查找聚类中心。对于每一个数据点,要计算两个量:**点的局部密度**和**该点到具有更高局部密度的点的距离**,而这两个值都取决于数据点间的距离。二、实现内容
1. 采用 Matlab、Python 或者其他的编程语言,实现 CFDP 算法; 2. 随机生成 500 个数,并对这 500 个数进行 CFDP 聚类,验证算法的正确性,并用matplot/plot 画图,进行数据可视化操作,展示算法的过程; 3. 针对以下数据集:consumption_data;bankloan;iris 数据集或者其他,进行聚类分析实验。三、实验代码
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.datasets as ds
#字体设置
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def distEclud(x,y):
return np.sqrt(np.sum(pow((x-y),2))) # 计算欧氏距离
#计算各点间距离、各点点密度大小
def get_point_distanceanddensity(datas,dc,number):
data = datas.tolist()
distance = np.random.rand(number,number)#距离初始化
point_density = np.random.rand(number)#密度初始化
#计算得到各点间距离
for i in range(number):
for j in range(number):
distance[i][j] = distEclud(np.array(data[i]),np.array(data[j]))
#计算得到各点的点密度
for i in range(number):
x = 0
for j in range(number):
if distance[i][j]< dc and i!=j:
x = x+1
point_density[i] = x
return distance, point_density
#计算得到各点的聚类中心距离
def get_each_distance(distance,point_density,data,dc):
nn = []
for i in range(len(point_density)):
aa = []
for j in range(len(point_density)):
if point_density[i] <= point_density[j] and i!=j:
aa.append(j)
ll = get_min_distance(aa,i,distance, point_density,data,dc)
nn.append(ll)
return nn
#到点密度大于自身的最近点的距离
def get_min_distance(aa,i,distance, point_density,data,dc):
min_distance = []
if aa != []:#如果传入的aa为空,说明该点是点密度最大的点
for k in aa:
min_distance.append(distance[i][k])
return min(min_distance)
else:
max_distance = get_max_distance(distance, point_density)
#max_distance=dc
return max_distance
#计算点密度最大的点的聚类中心距离
def get_max_distance(distance,point_density):
point_density = point_density.tolist()
a = max(point_density)#最大点密度
b = point_density.index(a)#最大点密度对应的下标
c = max(distance[b])#最大点密度对应的聚类中心的距离
return c
#选出质心
def get_group(point_density):
a=[]
for i in range(len(point_density)):
if nn[i]>0.2*max(nn) and point_density[i]>0.3*max(point_density):#密度和聚类中心距离大于最大值的20%
a.append(i)
return a
#分类
def get_cluster(a,distance,data):
cluster=[]
for i in range(len(data)):
min=float('inf')
for j in a:
if distance[i][j]<min:#将每个点分到距离最近的质心
min=distance[i][j]
min_id=j
cluster.append(min_id)#每个点的标签设为质心下标
return cluster
#画图
def get_picture(data,dc,point_density,nn,cluster,p,q,a):
plt.figure(1)
plt.subplot(1,2,1)
l = []
for i in a:
l.append(data[i])
l = np.array(l)
plt.scatter(data[:, p], data[:, q], c=cluster, s=50)#画质心
plt.scatter(l[:, p], l[:, q], s=20, color='red', marker='x')#画点
'''
for i in range(len(data)):
plt.text(data[:,p][i],data[:,q][i],i)
'''
plt.subplot(1,2,2)
plt.scatter(point_density,nn,c=cluster,s=50,alpha=0.5)
plt.xlabel('ρ')
plt.ylabel('δ')
'''
for i in range(len(data)):
plt.text(point_density[i],nn[i],i)
'''
plt.show()
def get_picture2(data,dc,point_density,nn,cluster,p,q,group,a):
plt.figure(1)
plt.subplot(2,2,1)
l=[]
for i in a:
l.append(data[i])
l = np.array(l)
plt.scatter(data[:,p],data[:,q],c=cluster,s=50)
plt.scatter(l[:,p],l[:,q], s=20, color='red', marker='x')
'''
for i in range(len(data)):
plt.text(data[:,p][i],data[:,q][i],i)
'''
plt.subplot(2,2,2)
plt.scatter(point_density,nn,c=cluster,s=50,alpha=0.5)
plt.xlabel('ρ')
plt.ylabel('δ')
'''
for i in range(len(data)):
plt.text(point_density[i],nn[i],i)
'''
plt.subplot(2,2,3)
plt.title('真实')
plt.scatter(data[:,p],data[:,q],c=group,s=50)
'''
for i in range(len(data)):
plt.text(data[:,p][i],data[:,q][i],i)
'''
plt.show()
#随机数
N=500
dc =2# 截断距离
data, laber = ds.make_blobs(n_samples=N, n_features=2,centers=4, random_state=1)
distance, point_density = get_point_distanceanddensity(data, dc, N)
nn = get_each_distance(distance, point_density, data,dc)
a=get_group(point_density)
cluster=get_cluster(a,distance,data)
get_picture2(data,dc,point_density,nn,cluster,0,1,laber,a)
#iris
dc=0.5
data = pd.DataFrame(np.genfromtxt("iris.txt",dtype=[float,float,float,float,float]))
group=data.values[:,-1]
data=data.drop(data.columns[-1],axis=1)
data=np.array(data)
distance, point_density = get_point_distanceanddensity(data, dc,len(data))
nn = get_each_distance(distance, point_density, data,dc)
a=get_group(point_density)
cluster=get_cluster(a,distance,data)
get_picture2(data,dc,point_density,nn,cluster,2,3,group,a)
#consumption_data
dc=80
data=pd.DataFrame(pd.read_excel('consumption_data.xls',header=0))
data=data.drop(["Id"],axis=1)
data=np.array(data)
distance, point_density = get_point_distanceanddensity(data, dc,len(data))
nn = get_each_distance(distance, point_density, data,dc)
a=get_group(point_density)
cluster=get_cluster(a,distance,data)
get_picture(data,dc,point_density,nn,cluster,1,2,a)
#bankloan.xls
dc=10
data=pd.DataFrame(pd.read_excel('bankloan.xls',header=0))
group=data.values[:,-1]
data=data.drop(['违约'],axis=1)
data=np.array(data)
distance, point_density = get_point_distanceanddensity(data, dc, len(data))
nn = get_each_distance(distance, point_density, data,dc)
a=get_group(point_density)
cluster=get_cluster(a,distance,data)
get_picture2(data,dc,point_density,nn,cluster,6,7,group,a)
四、实验结果与分析
500个随机数:
iris.txt:
consumption_data:
bankloan.xls:
总结
根据上面这些运行结果我们可以发现,CFDP聚类算法可以得到非球形的聚类结果,可以很好地描述数据分布,同时在算法复杂度上也比一般的K-means算法的复杂度低,并且可以在很大程度上排除噪点带来的影响。但是需要事先计算好所有点与点之间的距离及其局部密度,还要事先设置截断距离,截断距离仍需按照聚类情况进行调整。如果样本太大则整个距离矩阵的空间复杂多特别大。