英文全称:Density-Based Spatial Clustering of Applications with Noise
基本思想:
算法的思想大致是把所有的样本分成三类,一个是核心点(周围的样本点足够多),边缘点(周围的样本点不够多,但是在核心点的邻域内),孤立点(周围没有太多点,也不在核心点的邻域内)。
算法流程:
取出一个没有被分类的孤立点,如果它是核心点或者边缘点,就把他可以连接到的点们和他聚成一个簇,如果是孤立点,就把他单独作为一簇(或者当作噪声去掉)。
算法需要确定两个参数,一个是邻域大小,一个是邻域内点的个数,改变邻域大小会影响到邻域内点的个数。
优点是可以处理不同的形状簇,可以去除噪声。
缺点是有两个超参数,需要人工设定这两个参数。
代码1,命名为datahelper.py,被代码2引用:
import matplotlib.pyplot as plt
import numpy as np
import random
#随机生成大致是K个类别的点,用均匀分布生成中心点的位置,用高斯分布生成中心点周围的点
def generatorN(K):
#np.random.seed()
center=[[np.random.rand(1)*20,np.random.rand(1)*20] for _ in range(K)]
_data=[]
for _x, _y in center:
_data.append([np.random.randn(100)+_x ,np.random.randn(100)+_y])
_data = np.transpose(_data, (0, 2, 1)).reshape((-1, 2))
np.random.shuffle(_data)
return _data
#画图
def draw_data(_groups):
#fig=plt.figure(dpi=180)
plt.title("画图")
for xys in _groups.values():
xs=[xy[0] for xy in xys]
ys=[xy[1] for xy in xys]
plt.scatter(xs,ys)
plt.show()
代码2,直接运行:
#DBSCAN
import data_helper
#判断是不是已经分好簇了
def in_groups(_x,_y):
for xys in groups.values():
for p_x,p_y in xys:
if p_x==_x and p_y==_y:
return True
return False
#获取一个点所有的邻居
def get_neighbors(_x,_y):
_neighbors=[]
for p_x,p_y in data:
if p_x==_x and p_y==_y:#自己不是自己的邻居
continue
if (p_x-_x)**2+(p_y-_y)**2<=distance_thresh:
_neighbors.append([p_x,p_y])
return _neighbors
def get_grouped_pts():
_count=0
for xys in groups.values():
_count+=len(xys)
return _count
def get_ungrouped_p():
for p_x,p_y in data:
if not in_groups(p_x,p_y):
return p_x,p_y
return None
#groups
min_pts = 13
distance_thresh =2.35
groups={}
#存放聚类信息,格式(x,y):[[x1,y1],[x2,y2]...],xy是这个簇中最先被选中的点
data=data_helper.generatorN(5)#生成原始数据
judged=[]#判断某个点有没有被判断过
count=0
while len(data)!=get_grouped_pts():
x,y=get_ungrouped_p()
stack=[[x,y]]
groups[(x, y)] = [[x,y]]
#把这个点可以连接到的点加入整个簇
while len(stack)!=0:
x_,y_=stack.pop()
neighbors = get_neighbors(x_, y_)
if len(neighbors)>=min_pts:
for neighbor in neighbors:
if neighbor not in judged:
stack.append(neighbor)
judged.append(neighbor)
for neighbor in neighbors:
if not in_groups(*neighbor):
groups[(x, y)].append(neighbor)
data_helper.draw_data(groups)