简单易学的机器学习算法——基于密度的聚类算法DBSCAN
一、基于密度的聚类算法的概述
最近在Science上的一篇基于密度的聚类算法《Clustering by fast search and find of density peaks》引起了大家的关注(在我的博文“论文中的机器学习算法——基于密度峰值的聚类算法”中也进行了中文的描述)。于是我就想了解下基于密度的聚类算法,熟悉下基于密度的聚类算法与基于距离的聚类算法,如K-Means算法之间的区别。
基于密度的聚类算法主要的目标是寻找被低密度区域分离的高密度区域。与基于距离的聚类算法不同的是,基于距离的聚类算法的聚类结果是球状的簇,而基于密度的聚类算法可以发现任意形状的聚类,这对于带有噪音点的数据起着重要的作用。
二、DBSCAN算法的原理
1、基本概念
2、算法流程
(流程)
三、实验仿真
在实验中使用了两个测试数据集,数据集的原始图像如下:
(数据集1)
(数据集2)
数据集1相对比较简单。显然我们可以发现数据集1共有两个类,数据集2有四个类,下面我们通过DBSCAN算法实现数据点的聚类:
MATLAB代码
主程序
%% DBSCAN
clear all;
clc;
%% 导入数据集
% data = load('testData.txt');
data = load('testData_2.txt');
% 定义参数Eps和MinPts
MinPts = 5;
Eps = epsilon(data, MinPts);
[m,n] = size(data);%得到数据的大小
x = [(1:m)' data];
[m,n] = size(x);%重新计算数据集的大小
types = zeros(1,m);%用于区分核心点1,边界点0和噪音点-1
dealed = zeros(m,1);%用于判断该点是否处理过,0表示未处理过
dis = calDistance(x(:,2:n));
number = 1;%用于标记类
%% 对每一个点进行处理
for i = 1:m
%找到未处理的点
if dealed(i) == 0
xTemp = x(i,:);
D = dis(i,:);%取得第i个点到其他所有点的距离
ind = find(D<=Eps);%找到半径Eps内的所有点
%% 区分点的类型
%边界点
if length(ind) > 1 && length(ind) < MinPts+1
types(i) = 0;
class(i) = 0;
end
%噪音点
if length(ind) == 1
types(i) = -1;
class(i) = -1;
dealed(i) = 1;
end
%核心点(此处是关键步骤)
if length(ind) >= MinPts+1
types(xTemp(1,1)) = 1;
class(ind) = number;
% 判断核心点是否密度可达
while ~isempty(ind)
yTemp = x(ind(1),:);
dealed(ind(1)) = 1;
ind(1) = [];
D = dis(yTemp(1,1),:);%找到与ind(1)之间的距离
ind_1 = find(D<=Eps);
if length(ind_1)>1%处理非噪音点
class(ind_1) = number;
if length(ind_1) >= MinPts+1
types(yTemp(1,1)) = 1;
else
types(yTemp(1,1)) = 0;
end
for j=1:length(ind_1)
if dealed(ind_1(j)) == 0
dealed(ind_1(j)) = 1;
ind=[ind ind_1(j)];
class(ind_1(j))=number;
end
end
end
end
number = number + 1;
end
end
end
% 最后处理所有未分类的点为噪音点
ind_2 = find(class==0);
class(ind_2) = -1;
types(ind_2) = -1;
%% 画出最终的聚类图
hold on
for i = 1:m
if class(i) == -1
plot(data(i,1),data(i,2),'.r');
elseif class(i) == 1
if types(i) == 1
plot(data(i,1),data(i,2),'+b');
else
plot(data(i,1),data(i,2),'.b');
end
elseif class(i) == 2
if types(i) == 1
plot(data(i,1),data(i,2),'+g');
else
plot(data(i,1),data(i,2),'.g');
end
elseif class(i) == 3
if types(i) == 1
plot(data(i,1),data(i,2),'+c');
else
plot(data(i,1),data(i,2),'.c');
end
else
if types(i) == 1
plot(data(i,1),data(i,2),'+k');
else
plot(data(i,1),data(i,2),'.k');
end
end
end
hold off
距离计算函数
%% 计算矩阵中点与点之间的距离
function [ dis ] = calDistance( x )
[m,n] = size(x);
dis = zeros(m,m);
for i = 1:m
for j = i:m
%计算点i和点j之间的欧式距离
tmp =0;
for k = 1:n
tmp = tmp+(x(i,k)-x(j,k)).^2;
end
dis(i,j) = sqrt(tmp);
dis(j,i) = dis(i,j);
end
end
end
epsilon函数
function [Eps]=epsilon(x,k)
% Function: [Eps]=epsilon(x,k)
%
% Aim:
% Analytical way of estimating neighborhood radius for DBSCAN
%
% Input:
% x - data matrix (m,n); m-objects, n-variables
% k - number of objects in a neighborhood of an object
% (minimal number of objects considered as a cluster)
[m,n]=size(x);
Eps=((prod(max(x)-min(x))*k*gamma(.5*n+1))/(m*sqrt(pi.^n))).^(1/n);
最终的结果
(数据集1的聚类结果)
(数据集2的聚类结果)
在上面的结果中,红色的点代表的是噪音点,点代表的是边界点,十字代表的是核心点。不同的颜色代表着不同的类。
参考文献
[1] M. Ester, H. Kriegel, J. Sander, X. Xu, A density-based algorithm for discovering clusters in large spatial databases with noise, www.dbs.informatik.uni-muenchen.de/cgi-bin/papers?query=--CO [2] M. Daszykowski, B. Walczak, D. L. Massart, Looking for Natural Patterns in Data. Part 1: Density Based Approach
- 在R中使用支持向量机(SVM)进行数据挖掘
- 【你问我答】你与Java大牛的距离,只差这24个问题
- Android漏洞扫描工具Code Arbiter
- Huawei HG532 系列路由器远程命令执行漏洞分析
- postMessage与postMessage跨域
- 【手把手教你做项目】自然语言处理:单词抽取/统计
- D-Link系列路由器漏洞挖掘入门
- 大家一直在谈的领域驱动设计(DDD),我们在互联网业务系统是这么实践的
- 在Atom中设置Python开发环境
- Kaggle赛题解析:逻辑回归预测模型实现
- Shield:支撑美团点评品类最丰富业务的移动端模块化框架开源了
- 点击块,让小块动起来 - 函数封装
- 玩玩文本挖掘-wordcloud、主题模型与文本分类
- Typecho 前台 getshell 漏洞分析
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 填坑-回溯-预习 之 二分-尺取大总结
- 深入浅出理解动态规划(一) | 交叠子问题
- 深入浅出理解动态规划(二) | 最优子结构
- 用x种方式求第n项斐波那契数,99%的人只会第一种
- 面试官:手撕十大排序算法,你会几种?
- 如何在Integer类型的ArrayList中同时添加String、Character、Boolean等类型的数据?
- Java开发岗面试题--基础篇(一)
- leetcode链表之找出倒数第k个节点
- MAC下安装nginx的正确姿势 实践笔记
- 关于 ThreadLocal 你需要知道的几点
- 关于Guava ForwardingMap
- http post Request header is too large 开发环境和线上版本解决方案
- 像java一样使用js contains 数组包含方法 实践笔记
- 服务治理之重试篇
- 一次排查线上接口偶发异常耗时引起的思考!