基于密度峰值的聚类(DPCA)

天天见闻 天天见闻 2022-02-21 科技 阅读: 2077
摘要: 密度峰值算法由Alex Rodriguez和Alessandro Laio于2014年提出,并将论文发表在Science上。Science上的这篇文章《Clustering by fast search and find of density peaks》主要讲的是一种基于密度的聚类方法,基于密度的聚类方法的主要思想是寻找被低密度区域分离的高密度区域。密度峰值算法基于这样的假设:类簇中心点的密度大于周围邻居点的密度;类簇中心点与更高密度点之间的距离相对较大。因此水的密度,DPCA主要有两个需要计算的量:第一,局部密度;第二,与高密度点之间的距离。

1、背景介绍

密度峰值算法(Clustering by fast search and find of density peaks)由Alex Rodriguez和Alessandro Laio于2014年提出,并将论文发表在Science上。Science上的这篇文章《Clustering by fast search and find of density peaks》主要讲的是一种基于密度的聚类方法,基于密度的聚类方法的主要思想是寻找被低密度区域分离的高密度区域。 密度峰值算法(DPCA)基于这样的假设:(1)类簇中心点的密度大于周围邻居点的密度;(2)类簇中心点与更高密度点之间的距离相对较大。因此水的密度,DPCA主要有两个需要计算的量:第一,局部密度;第二,与高密度点之间的距离。

2、局部密度

数据对象

的局部密度

石油密度 水_水 酒精 水银的密度_水的密度

定义为:

其中,

表示截断距离

石油密度 水_水的密度_水 酒精 水银的密度

,这个公式的含义是说找到与第

个数据点之间的距离小于截断距离

的数据点的个数,并将其作为第i个数据点真的密度。

水的密度_水 酒精 水银的密度_石油密度 水

3、定义聚类中心距离

密度峰聚类算法的巧妙之处:就是在于聚类中心距离 δi的选定。根据局部密度的定义,我们可以计算出上图中每个点的密度,依照密度确定聚类中心距离 δi。

1.首先将每个点的密度从大到小排列: ρi > ρj > ρk > ….;密度最大的点的聚类中心距离与其他点的聚类中心距离的确定方法是不一样的;

2.先确定密度最大的点的聚类中心距离–i点是密度最大的点,它的聚类中心距离δiδi等于与i点最远的那个点n到点i的直线距离 d(i,n);

3. 再确定其他点的聚类中心距离——其他点的聚类中心距离是等于在密度大于该点的点集合中,与该点距离最小的的那个距离。例如i、j、k的密度都比n点的密度大,且j点离n点最近,则n点的聚类中心距离等于d(j,n);

水的密度_水 酒精 水银的密度_石油密度 水

4. 依次确定所有的聚类中心距离δ

4、聚类效果

将所有点的聚类中心密度都统计出来后,将其值按δi和pi作为坐标轴作图可以得到如图所示结果。可以看到图中1,10两个聚类中心同时远离坐标轴。普通点则是靠近p轴,异常点靠近δ轴。

5、基于python的实现:

python代码如下水的密度,其中要引入numpy等一些包,pycharm中引入包还是比较简单的。

# -*- coding:utf-8 -*-
# -*- python3.5
import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as ds
import matplotlib.colors
min_distance = 4.6           # 邻域半径
points_number = 40          # 随机点个数
# 计算各点间距离、各点点密度(局部密度)大小
def get_point_density(datas,labers,min_distance,points_number):
    # 将numpy.ndarray格式转为list格式,并定义元组大小
    data = datas.tolist()
    laber = labers.tolist()
    distance_all = np.random.rand(points_number,points_number)
    point_density = np.random.rand(points_number)
    # 计算得到各点间距离
    for i in range(points_number):
        for n in range(points_number):
            distance_all[i][n] = np.sqrt(np.square(data[i][0]-data[n][0])+np.square(data[i][1]-data[n][1]))
    print('距离数组:\n',distance_all,'\n')
    # 计算得到各点的点密度
    for i in range(points_number):
        x = 0
        for n in range(points_number):
            if distance_all[i][n] > 0 and distance_all[i][n]< min_distance:
                x = x+1
            point_density[i] = x
    print('点密度数组:', point_density, '\n')
    return distance_all, point_density
# 计算点密度最大的点的聚类中心距离
def get_max_distance(distance_all,point_density,laber):
    point_density = point_density.tolist()
    a = int(max(point_density))
    # print('最大点密度',a,type(a))
    b = laber[point_density.index(a)]
    # print("最大点密度对应的索引:",b,type(b))
    c = max(distance_all[b])
    # print("最大点密度对应的聚类中心距离",c,type(c))
    return c
# 计算得到各点的聚类中心距离
def get_each_distance(distance_all,point_density,data,laber):
    nn = []
    for i in range(len(point_density)):
        aa = []
        for n in range(len(point_density)):
            if point_density[i] < point_density[n]:
                aa.append(n)
        # print("大于自身点密度的索引",aa,type(aa))
        ll = get_min_distance(aa,i,distance_all, point_density,data,laber)
        nn.append(ll)
    return nn
# 获得:到点密度大于自身的最近点的距离
def get_min_distance(aa,i,distance_all, point_density,data,laber):
    min_distance = []
    """
    如果传入的aa为空,说明该点是点密度最大的点,该点的聚类中心距离计算方法与其他不同
    """
    if aa != []:
        for k in aa:
            min_distance.append(distance_all[i][k])
        # print('与上各点距离',min_distance,type(nn))
        # print("最小距离:",min(min_distance),type(min(min_distance)),'\n')
        return min(min_distance)
    else:
        max_distance = get_max_distance(distance_all, point_density, laber)
        return max_distance
def get_picture(data,laber,points_number,point_density,nn):
    # 创建Figure
    fig = plt.figure()
    # 用来正常显示中文标签
    matplotlib.rcParams['font.sans-serif'] = [u'SimHei']
    # 用来正常显示负号
    matplotlib.rcParams['axes.unicode_minus'] = False
    # 原始点的分布
    ax1 = fig.add_subplot(211)
    plt.scatter(data[:,0],data[:,1],c=laber)
    plt.title(u'原始数据分布')
    plt.sca(ax1)
    for i in range(points_number):
        plt.text(data[:,0][i],data[:,1][i],laber[i])
    # 聚类后分布
    ax2 = fig.add_subplot(212)
    plt.scatter(point_density.tolist(),nn,c=laber)
    plt.title(u'聚类后数据分布')
    plt.sca(ax2)
    for i in range(points_number):
        plt.text(point_density[i],nn[i],laber[i])
    plt.show()
def main():
    # 随机生成点坐标
    data, laber = ds.make_blobs(points_number, centers=points_number, random_state=0)
    print('各点坐标:\n', data)
    print('各点索引:', laber, '\n')
    # 计算各点间距离、各点点密度(局部密度)大小
    distance_all, point_density = get_point_density(data, laber, min_distance, points_number)
    # 得到各点的聚类中心距离
    nn = get_each_distance(distance_all, point_density, data, laber)
    print('最后的各点点密度:', point_density.tolist())
    print('最后的各点中心距离:', nn)
    # 画图
    get_picture(data, laber, points_number, point_density, nn)
    """
    距离归一化:就把上面的nn改为:nn/max(nn)
    """

if __name__ == '__main__':
    main()

代码运行效果如下图:

其他相关

《圆的周长 》导学案

作者: 天天见闻 时间:2022-02-23 阅读: 1465
正方形的周长是边长的()倍。围成圆的( )的长叫做圆的周长 。讨论说出自己的方法:。圆周率是一个()小数圆周长公式,在实际应用中,一般取它的近似值,即()。答:它的周长是62.8米。半圆的周长是圆周长的一半。...

动漫游戏中常见的PV、OP、CV等是啥意思?其实很多人常常误用

作者: 天天见闻 时间:2022-02-24 阅读: 896
兄弟姐妹萌好,我是阿新。经常喜欢看动漫、玩游戏和听音乐的小伙伴可能经常会接触到一些英文简写词,比如“PV”、“OP”、“CV”等等,虽然这些词的含义并不复杂,不过我还是经常看到一些小伙伴会误用其中的一些词ost是什么意思,有时候可能有些同学也是没有去详细了解这些词的意思,只是知道它是在什么场合用,大概猜个意思。PV,这个词的全称叫做“Promotion Video”,直接翻译的话就是宣传视频的意思。...

11月,鸿运当头,诸事顺遂,走向上坡路,成为人生大赢家的星座

作者: 天天见闻 时间:2022-02-25 阅读: 605
了解星座性格,并改善性格,星座运势才能更好趋吉避凶。本期星座运势说,创优咖给大家带来的话题是十二星座中在11月,鸿运当头,诸事顺遂,走向上坡路,成为人生大赢家的3个星座,下面我们直接进入主题。处女座是一个求真务实的人,但他们特别聪明,不会走弯路,而且他们很少做无用功,所有努力都会见功效。水瓶座——阳性星座,大多是有进取心,积极主动的理想主义者。...

“甲乙丙丁”后面是什么﹖

作者: 天天见闻 时间:2022-02-26 阅读: 1106
以上两行合称天干地支。甲乙丙丁某后面是什么?甲乙丙丁后面是什么?- —— 甲乙丙丁戊己庚辛壬癸后面是"戊"有帮助请采纳 谢谢...甲乙丙丁后面是什么来着,还有那个念什么贵的 - —— 甲,乙,丙甲乙丙丁戊己庚辛壬癸怎么读,丁,戊,己,庚,辛,壬,癸...

IPHONE13是双卡双待吗,支持全网通5g双卡双待(除了mini版本是单卡)

作者: 天天见闻 时间:2022-03-01 阅读: 684
iPhone13全系列除了mini以外都是支持5G全网通双卡双待的手机,即使在国内也能进行非常流畅的通话和数据流量上网,不过也仅仅只有国行是这样,海外版则无法支持双卡双待,例如美版、日版等等,因此大家想用双卡双待的苹果手机的话就一定要购买国行版本。...

为什么美元符号“$”中间有时是一竖有时是两竖?

作者: 天天见闻 时间:2022-03-01 阅读: 3321
美元符号是一个大S加上两条竖线。另一个说法认为它是PS叠合写法的演变,PS是早期美国的一种圆形硬币比索(Pesos)的缩写,这种硬币在1974年美国正式建立造币厂以前一直在美国通用。后来美国政府认可了$这个符号作为新货币的一个单位,即一美元。在书写时,$要摆在数字前面。如1美元应写成$1,50美元写成$50。需要说明的是,看到$,不要以为一定就是美元。也就是说,美元既可加1竖也可加2竖。...
我来说两句

年度爆文