本人在此就不搬运书上关于密度聚类的理论知识了,仅仅实现密度聚类的模板代码和调用skelarn的密度聚类算法。
有人好奇,为什么有sklearn库了还要自己去实现呢?其实,库的代码是比自己写的高效且容易,但自己实现代码会对自己对算法的理解更上一层楼。

#调用科学计算包与绘图包
import numpy as np
import random
import matplotlib.pyplot as plt
# 获取数据
def loadDataSet(filename):
  dataSet=np.loadtxt(filename,dtype=np.float32,delimiter=',')
  return dataSet
#计算两个向量之间的欧式距离
def calDist(X1 , X2 ):
  sum = 0
  for x1 , x2 in zip(X1 , X2):
    sum += (x1 - x2) ** 2
  return sum ** 0.5
#获取一个点的ε-邻域(记录的是索引)
def getNeibor(data , dataSet , e):
  res = []
  for i in range(dataSet.shape[0]):
    if calDist(data , dataSet[i])<e:
      res.append(i)
  return res
#密度聚类算法
def DBSCAN(dataSet , e , minPts):
  coreObjs = {}#初始化核心对象集合
  C = {}
  n = dataSet.shape[0]
  #找出所有核心对象,key是核心对象的index,value是ε-邻域中对象的index
  for i in range(n):
    neibor = getNeibor(dataSet[i] , dataSet , e)
    if len(neibor)>=minPts:
      coreObjs[i] = neibor
  oldCoreObjs = coreObjs.copy()
  k = 0#初始化聚类簇数
  notAccess = list(range(n))#初始化未访问样本集合(索引)
  while len(coreObjs)>0:
    OldNotAccess = []
    OldNotAccess.extend(notAccess)
    cores = coreObjs.keys()
    #随机选取一个核心对象
    randNum = random.randint(0,len(cores)-1)
    cores=list(cores)
    core = cores[randNum]
    queue = []
    queue.append(core)
    notAccess.remove(core)
    while len(queue)>0:
      q = queue[0]
      del queue[0]
      if q in oldCoreObjs.keys() :
        delte = [val for val in oldCoreObjs[q] if val in notAccess]#Δ = N(q)∩Γ
        queue.extend(delte)#将Δ中的样本加入队列Q
        notAccess = [val for val in notAccess if val not in delte]#Γ = Γ\Δ
    k += 1
    C[k] = [val for val in OldNotAccess if val not in notAccess]
    for x in C[k]:
      if x in coreObjs.keys():
        del coreObjs[x]
  return C
# 代码入口
dataSet = loadDataSet(r"E:\jupyter\sklearn学习\sklearn聚类\DataSet.txt")
print(dataSet)
print(dataSet.shape)
C = DBSCAN(dataSet, 0.11, 5)
draw(C, dataSet)

结果图:

python实现密度聚类(模板代码+sklearn代码)

下面是调用sklearn库的实现

db = skc.DBSCAN(eps=1.5, min_samples=3).fit(dataSet) #DBSCAN聚类方法 还有参数,matric = ""距离计算方法
labels = db.labels_ #和X同一个维度,labels对应索引序号的值 为她所在簇的序号。若簇编号为-1,表示为噪声
print('每个样本的簇标号:')
print(labels)
raito = len(labels[labels[:] == -1]) / len(labels) #计算噪声点个数占总数的比例
print('噪声比:', format(raito, '.2%'))
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0) # 获取分簇的数目
print('分簇的数目: %d' % n_clusters_)
print("轮廓系数: %0.3f" % metrics.silhouette_score(X, labels)) #轮廓系数评价聚类的好坏
for i in range(n_clusters_):
  print('簇 ', i, '的所有样本:')
  one_cluster = X[labels == i]
  print(one_cluster)
  plt.plot(one_cluster[:,0],one_cluster[:,1],'o')
plt.show()
标签:
python,密度聚类

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
白云城资源网 Copyright www.dyhadc.com