聚类分析之基于密度的聚类算法(DBSCAN)

一  什么是基于密度的聚类算法

由于层次聚类算法和划分式聚类算往往只能发现凸形的聚类簇。为了弥补这一缺陷,发现各种任意形状的聚类簇,开发出基于密度的聚类算法。这类算法认为,在整个样本空间点中,各目标类簇是由一群的稠密样本点组成的,而这些稠密样本点被低密度区域(噪声)分割,而算法的目的就是要过滤低密度区域,发现稠密样本点。

二  DBSCAN(Density-based Spatial Clustering of Applications with Noise)

是一种基于高密度联通区域的聚类算法,它将类簇定义为高密度相连点的最大集合。它本身对噪声不敏感,并且能发现任意形状的类簇。

DBSCAN中的的几个定义:

Ε领域:给定对象半径为Ε内的区域称为该对象的Ε领域

核心对象:如果给定对象Ε领域内的样本点数大于等于MinPts,则称该对象为核心对象

直接密度可达:对于样本集合D,如果样本点q在p的Ε领域内,并且p为核心对象,那么对象q从对象p直接密度可达

密度可达:对于样本集合D,给定一串样本点p1,p2….pn,p=
p1,q= pn,假如对象pi从pi-1直接密度可达,那么对象q从对象p密度可达

密度相连:对于样本集合D中的任意一点O,如果存在对象p到对象o密度可达,并且对象q到对象o密度可达,那么对象q到对象p密度相连

可以发现,密度可达是直接密度可达的传递闭包,并且这种关系是非对称的。密度相连是对称关系。DBSCAN目的是找到密度相连对象的最大集合。

Eg: 假设半径Ε=3,MinPts=3,点p的E领域中有点{m,p,p1,p2,o}, 点m的E领域中有点{m,q,p,m1,m2},点q的E领域中有点{q,m},点o的E领域中有点{o,p,s},点s的E领域中有点{o,s,s1}.

那么核心对象有p,m,o,s(q不是核心对象,因为它对应的E领域中点数量等于2,小于MinPts=3);

点m从点p直接密度可达,因为m在p的E领域内,并且p为核心对象;

点q从点p密度可达,因为点q从点m直接密度可达,并且点m从点p直接密度可达;

点q到点s密度相连,因为点q从点p密度可达,并且s从点p密度可达。

三  算法描述

算法:DBSCAN

输入:E — 半径

MinPts — 给定点在E领域内成为核心对象的最小领域点数

D — 集合

输出:目标类簇集合

方法:repeat

1)       判断输入点是否为核心对象

2)       找出核心对象的E领域中的所有直接密度可达点

util 所有输入点都判断完毕

repeat

针对所有核心对象的E领域所有直接密度可达点找到最大密度相连对象集合,

中间涉及到一些密度可达对象的合并。

Util 所有核心对象的E领域都遍历完毕

算法:DBSCAN

输入:E — 半径

MinPts — 给定点在E领域内成为核心对象的最小领域点数

D — 集合

输出:目标类簇集合

方法:repeat

1)       判断输入点是否为核心对象

2)       找出核心对象的E领域中的所有直接密度可达点

util 所有输入点都判断完毕

repeat

针对所有核心对象的E领域所有直接密度可达点找到最大密度相连对象集合,

中间涉及到一些密度可达对象的合并。

Util 所有核心对象的E领域都遍历完毕

四  算法实现

package com.dbscan;

public class DataPoint {

private String dataPointName; // 样本点名

private double dimensioin[]; // 样本点的维度

private boolean isKey; //是否是核心对象

public DataPoint(){

}

public DataPoint(double[] dimensioin,String dataPointName,boolean isKey){

this.dataPointName=dataPointName;

this.dimensioin=dimensioin;

this.isKey=isKey;

}

}

------------

package com.dbscan;

import java.util.ArrayList;

import java.util.List;

public class Cluster {

private List<DataPoint> dataPoints = new ArrayList<DataPoint>(); // 类簇中的样本点

private String clusterName; //簇名

public List<DataPoint> getDataPoints() {

return dataPoints;

}

public void setDataPoints(List<DataPoint> dataPoints) {

this.dataPoints = dataPoints;

}

public String getClusterName() {

return clusterName;

}

public void setClusterName(String clusterName) {

this.clusterName = clusterName;

}

}

------------

package com.dbscan;

import java.util.ArrayList;

import java.util.List;

public class ClusterAnalysis {

public List<Cluster> doDbscanAnalysis(List<DataPoint> dataPoints,

double radius, int ObjectNum) {

List<Cluster> clusterList=new ArrayList<Cluster>();

for(int i=0; i<dataPoints.size();i++){

DataPoint dp=dataPoints.get(i);

List<DataPoint> arrivableObjects=isKeyAndReturnObjects(dp,dataPoints,radius,ObjectNum);

if(arrivableObjects!=null){

Cluster tempCluster=new Cluster();

tempCluster.setClusterName("Cluster "+i);

tempCluster.setDataPoints(arrivableObjects);

clusterList.add(tempCluster);

}

}

for(int i=0;i<clusterList.size();i++){

for(int j=0;j<clusterList.size();j++){

if(i!=j){

Cluster clusterA=clusterList.get(i);

Cluster clusterB=clusterList.get(j);

List<DataPoint> dpsA=clusterA.getDataPoints();

List<DataPoint> dpsB=clusterB.getDataPoints();

boolean flag=mergeList(dpsA,dpsB);

if(flag){

clusterList.set(j, new Cluster());

}

}

}

}

return clusterList;

}

public void displayCluster(List<Cluster> clusterList){

if(clusterList!=null){

for(Cluster tempCluster:clusterList){

if(tempCluster.getDataPoints()!=null&&tempCluster.getDataPoints().size()>0){

System.out.println("----------"+tempCluster.getClusterName()+"----------");

for(DataPoint dp:tempCluster.getDataPoints()){

System.out.println(dp.getDataPointName());

}

}

}

}

}

private double getDistance(DataPoint dp1,DataPoint dp2){

double distance=0.0;

double[] dim1=dp1.getDimensioin();

double[] dim2=dp2.getDimensioin();

if(dim1.length==dim2.length){

for(int i=0;i<dim1.length;i++){

double temp=Math.pow((dim1[i]-dim2[i]), 2);

distance=distance+temp;

}

distance=Math.pow(distance, 0.5);

return distance;

}

return distance;

}

private List<DataPoint> isKeyAndReturnObjects(DataPoint dataPoint,List<DataPoint> dataPoints,double radius,int ObjectNum){

List<DataPoint> arrivableObjects=new ArrayList<DataPoint>(); //用来存储所有直接密度可达对象

for(DataPoint dp:dataPoints){

double distance=getDistance(dataPoint,dp);

if(distance<=radius){

arrivableObjects.add(dp);

}

}

if(arrivableObjects.size()>=ObjectNum){

dataPoint.setKey(true);

return arrivableObjects;

}

return null;

}

private boolean isContain(DataPoint dp,List<DataPoint> dps){

boolean flag=false;

String name=dp.getDataPointName().trim();

for(DataPoint tempDp:dps){

String tempName=tempDp.getDataPointName().trim();

if(name.equals(tempName)){

flag=true;

break;

}

}

return flag;

}

private boolean mergeList(List<DataPoint> dps1,List<DataPoint> dps2){

boolean flag=false;

if(dps1==null||dps2==null||dps1.size()==0||dps2.size()==0){

return flag;

}

for(DataPoint dp:dps2){

if(dp.isKey()&&isContain(dp,dps1)){

flag=true;

break;

}

}

if(flag){

for(DataPoint dp:dps2){

if(!isContain(dp,dps1)){

DataPoint tempDp=new DataPoint(dp.getDimensioin(),dp.getDataPointName(),dp.isKey());

dps1.add(tempDp);

}

}

}

return flag;

}

public static void main(String[] args){

ArrayList<DataPoint> dpoints = new ArrayList<DataPoint>();

double[] a={2,3};

double[] b={2,4};

double[] c={1,4};

double[] d={1,3};

double[] e={2,2};

double[] f={3,2};

double[] g={8,7};

double[] h={8,6};

double[] i={7,7};

double[] j={7,6};

double[] k={8,5};

double[] l={100,2};//孤立点

double[] m={8,20};

double[] n={8,19};

double[] o={7,18};

double[] p={7,17};

double[] q={8,21};

dpoints.add(new DataPoint(a,"a",false));

dpoints.add(new DataPoint(b,"b",false));

dpoints.add(new DataPoint(c,"c",false));

dpoints.add(new DataPoint(d,"d",false));

dpoints.add(new DataPoint(e,"e",false));

dpoints.add(new DataPoint(f,"f",false));

dpoints.add(new DataPoint(g,"g",false));

dpoints.add(new DataPoint(h,"h",false));

dpoints.add(new DataPoint(i,"i",false));

dpoints.add(new DataPoint(j,"j",false));

dpoints.add(new DataPoint(k,"k",false));

dpoints.add(new DataPoint(l,"l",false));

dpoints.add(new DataPoint(m,"m",false));

dpoints.add(new DataPoint(n,"n",false));

dpoints.add(new DataPoint(o,"o",false));

dpoints.add(new DataPoint(p,"p",false));

dpoints.add(new DataPoint(q,"q",false));

ClusterAnalysis ca=new ClusterAnalysis();

List<Cluster> clusterList=ca.doDbscanAnalysis(dpoints, 2, 4);

ca.displayCluster(clusterList);

}

}

}

时间: 2024-10-10 15:33:08

聚类分析之基于密度的聚类算法(DBSCAN)的相关文章

简单易学的机器学习算法——基于密度的聚类算法DBSCAN

一.基于密度的聚类算法的概述 最近在Science上的一篇基于密度的聚类算法<Clustering by fast search and find of density peaks>引起了大家的关注(在我的博文"论文中的机器学习算法--基于密度峰值的聚类算法"中也进行了中文的描述).于是我就想了解下基于密度的聚类算法,熟悉下基于密度的聚类算法与基于距离的聚类算法,如K-Means算法之间的区别. 基于密度的聚类算法主要的目标是寻找被低密度区域分离的高密度区域.与基于距离的聚

【机器学习】DBSCAN Algorithms基于密度的聚类算法

一.算法思想: DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法.与划分和层次聚类方法不同,它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据库中发现任意形状的聚类. DBSCAN中的几个定义: Ε邻域:给定对象半径为Ε内的区域称为该对象的Ε邻域: 核心对象:如果给定对象Ε领域内的样本点数大于等于MinPts,则称该对象为核心对象:

基于密度的聚类之Dbscan算法

一.算法概述 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法.与划分和层次聚类方法不同,它将簇定义为密度相连的点的最大集合,能够把具有足够高密度的区域划分为簇,并可在噪声的空间数据库中发现任意形状的聚类(笔者认为是因为他不是基于距离的,基于距离的发现的是球状簇). 该算法利用基于密度的聚类的概念,即要求聚类空间中的一定区域内所包含对象(点或其他空间对象)的数目不小于某一给

聚类:层次聚类、基于划分的聚类(k-means)、基于密度的聚类、基于模型的聚类

一.层次聚类 1.层次聚类的原理及分类 1)层次法(Hierarchicalmethods)先计算样本之间的距离.每次将距离最近的点合并到同一个类.然后,再计算类与类之间的距离,将距离最近的类合并为一个大类.不停的合并,直到合成了一个类.其中类与类的距离的计算方法有:最短距离法,最长距离法,中间距离法,类平均法等.比如最短距离法,将类与类的距离定义为类与类之间样本的最短距离. 层次聚类算法根据层次分解的顺序分为:自下底向上和自上向下,即凝聚的层次聚类算法和分裂的层次聚类算法(agglomerat

为什么说K-Means是基于距离的聚类算法?

K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,两个对象的距离越近,其相似度就越大.K-means算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标.k-means聚类,需要用户设定一个聚类个数k作为输入数据.k个初始类聚类中心点的选取,对聚类结果具有较大的.为了用k-means达到高质量的聚类,需要估计k值.可根据需要的聚类个数,估计k值.比如一百万篇文章,如果平均500篇分为一类,k值可以取2000(1百万/500). 算法步骤1)随机选取

基于K-means Clustering聚类算法对电商商户进行级别划分(含Octave仿真)

在从事电商做频道运营时,每到关键时间节点,大促前,季度末等等,我们要做的一件事情就是品牌池打分,更新所有店铺的等级.例如,所以的商户分入SKA,KA,普通店铺,新店铺这4个级别,对于不同级别的商户,会给予不同程度的流量扶持或广告策略.通常来讲,在一定时间段内,评估的维度可以有:UV,收订金额,好评率,销退金额,广告位点击率,转化率,pc端流量.手机端流量.客单价......等n多个维度,那么如何在这n多个维度中找到一种算法,来将我们的品牌划分到4个级别中呢?今天所讨论的K-means聚类算法是其

数据挖掘聚类算法--DBSCAN

数据集如下所示: 1,1,1 2,1.5,1 3,0.5,1 3,5,-1 7,0.75,-1 7,4,2 8,5,2 8,5.5,2 数据集有三个属性,分别是二维坐标中的x和y,第三个属性是所属的类,-1代表为孤立点,坐标系如下图所示: 源代码如下: package neugle.dbscan; import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayList; import java.ut

基于密度聚类的DBSCAN算法

根据各行业特性,人们提出了多种聚类算法,简单分为:基于层次.划分.密度.图论.网格和模型的几大类. 其中,基于密度的聚类算法以DBSCAN最具有代表性. 假设有如下图的一组数据, 生成数据的R代码如下 x1 <- seq(0,pi,length.out=100) y1 <- sin(x1) + 0.1*rnorm(100) x2 <- 1.5+ seq(0,pi,length.out=100) y2 <- cos(x2) + 0.1*rnorm(100) data <- da

DBSCAN密度聚类算法

DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种很典型的密度聚类算法,和K-Means,BIRCH这些一般只适用于凸样本集的聚类相比,DBSCAN既可以适用于凸样本集,也可以适用于非凸样本集.下面我们就对DBSCAN算法的原理做一个总结. 1. 密度聚类原理 DBSCAN是一种基于密度的聚类算法,这类密度聚类算法一般假定类别可以通过样本分布的紧密程度决定.同一类别的样本,他们