Python实现DBSCAN聚类算法,可视化

英文全称: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)

 

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页