DBSCAN算法是一种基于密度的聚类算法:
DBSCAN是基于一组邻域来描述样本集的紧密程度的,参数 (ϵ, MinPts) 用来描述邻域的样本分布紧密程度。其中,ϵ 描述了某一样本的邻域距离阈值,MinPts 描述了某一样本的距离为ϵ的邻域中样本个数的阈值。
1.聚类的时候不需要预先指定簇的个数;
2.最终的簇的个数不定。
DBSCAN算法将数据点分为三类:
核心点:在半径Eps内含有超过MinPts数目的点。
边界点:在半径Eps内点的数量小于MinPts,但是落在核心点的领域内。
噪音点:既不是核心点也不是边界点的点。
密度可达和密度相连直观解释:
从上图可以很容易看出理解上述定义,图中MinPts=5,红色的点都是核心对象,因为其ϵ-邻域至少有5个样本。黑色的样本是非核心对象。所有核心对象密度直达的样本在以红色核心对象为中心的超球体内,如果不在超球体内,则不能密度直达。图中用绿色箭头连起来的核心对象组成了密度可达的样本序列。在这些密度可达的样本序列的ϵ-邻域内所有的样本相互都是密度相连的。
由密度可达关系导出的最大密度相连的样本集合,即为我们最终聚类的一个类别,或者说一个簇。这个DBSCAN的簇里面可以有一个或者多个核心对象。如果只有一个核心对象,则簇里其他的非核心对象样本都在这个核心对象的ϵ-邻域里;如果有多个核心对象,则簇里的任意一个核心对象的ϵ-邻域中一定有一个其他的核心对象,否则这两个核心对象无法密度可达。这些核心对象的ϵϵ-邻域里所有的样本的集合组成的一个DBSCAN聚类簇。
DBSCAN算法流程:
1.将所有点标记为核心点、边界点或噪声点;
2.删除噪声点;
3.为距离在Eps之内的所有核心点之间赋予一条边;
4.每组连通的核心点形成一个簇;
5.将每个边界点指派到一个与之关联的核心点的簇中(哪一个核心点的半径范围之内)。
取Eps=3,MinPts=3,依据DBSCAN对所有点进行聚类(曼哈顿距离):
1.对每个点计算其邻域Eps=3内的点的集合。
2.集合内点的个数超过MinPts=3的点为核心点。
3.查看剩余点是否在核心点的邻域内,若在,则为边界点,否则为噪声点。
4.将距离不超过Eps=3的点相互连接,构成一个簇,核心点邻域内的点也会被加入到这个簇中。则右侧形成3个簇。
DBSCAN主要参数:
eps:两个样本被看作邻居节点的最大距离。
min_samples:簇的样本数。
metric:距离计算方式。
例:sklearn.cluster.DBSCAN(eps=0.5,min_samples=5,metric='euclidean')
学生上网分析--DBSCAN密度聚类:
数据样式:
'''
学生上网分析--DBSCAN密度聚类
'''
#导入相关包:
import numpy as np
import sklearn.cluster as skc
from sklearn import metrics
import matplotlib.pyplot as plt
f=open(r'd:\Users\zhanggl21\Desktop\Python机器学习应用\课程数据\聚类\学生月上网时间分布-TestData.txt',encoding='utf-8')
#读取每条数据中的mac地址、开始上网时间、上网时长:
mac2id=dict()
onlinetimes=[]
for line in f:
mac=line.split(',')[2]
onlinetime=int(line.split(',')[6])
starttime=int(line.split(',')[4].split(' ')[1].split(':')[0])#取第一条上网记录的上网时间(小时)
if mac not in mac2id:
mac2id[mac]=len(onlinetimes)
onlinetimes.append((starttime,onlinetime))
else:
onlinetimes[mac2id[mac]]=[(starttime,onlinetime)]
real_X=np.array(onlinetimes).reshape((-1,2))
X=real_X[:,0:1] #提取出上网时间(小时)
#调用DBSCAN方法进行训练,labels为每个数据的簇标签:
db=skc.DBSCAN(eps=0.01,min_samples=20).fit(X)
labels=db.labels_
#打印数据被记上的标签,计算标签为-1即噪声数据的比例:
print('labels:\n',labels)
raito=len(labels[labels[:]==-1])/len(labels)
print('Noise raito(噪声数据的比例):',format(raito,'.2%'))
#计算簇的个数并打印,评价聚类效果
n_clusters_=len(set(labels))-(1 if -1 in labels else 0)
print('估计簇的个数为:%d' %(n_clusters_))
print('Silhouette Coefficient: %0.3f' %(metrics.silhouette_score(X,labels)))
#打印各簇标号以及各簇内数据
for i in range(n_clusters_):
print('Cluster ',i,':\n',list(X[labels==i].flatten()),'\n')
打印的结果如下: