绪论
刚刚完成了一个关于DBSCAN的作业,由于刚开始学习MATLAB的使用便用它完成了一个练手任务,有一点想法记录下来。以便于后来重新学习这个方法和记录一些函数,同时也希望能给同学着一点思路。有问题也请留言,会不断改正。
参考博客指路:看了不少,链接挺多,有些忘了,欢迎指出改正
推荐一个基础知识点整理的比较好的博主
万勇’s Blog
https://blog.csdn.net/qiu1440528444/article/details/80763420?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160601820019195264744375%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160601820019195264744375&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allbaidu_landing_v2~default-1-80763420.first_rank_ecpm_v3_pc_rank_v2&utm_term=matlab+%E5%AE%9E%E7%8E%B0DBSCAN&spm=1018.2118.3001.4449
任务目标
1.生成一个双月型数据集;
2.使用KNN求出E-PS,在本实验中预先设置了Min-point =4;
3,利用DBSCAN分类,展示分类结果
4,顺便赚点币下载别人资料(手动狗头)
实验思路
对于DBSCAN算法来说,我们需要关注以下几点:
数据集 Min-pot(阈值) Eps(半径)
有了这些才能开始算法,即使是调用封装好的函数,也是需要这些变量
这些概念可在文章开头推荐发博客中找到。
实验过程
1.生成双月型数据集
1.1思想
设计了一个半圆环,在matlab可以通过rand()函数在这个范围内生成随机数,
代码如下:
```function data=creat_point(N)
% Usage: data=dbmoon(N,d,r,w)
% 每个区域是一个半径r=10,宽度=6的半环,一个在上,另一个在下面
% d: 两个半圆的距离
% 将生成以(0,0)为中心的区域A,区域B是镜像区域A(w.r.t.x轴)的原点偏移(r,d)
% N: 每个类的样本数, default(初始值) = 1000
% d: 两类分离程度,负值表示重叠(默认值=1)
% r:半径 (default=10), w: 环的宽度 (default=6)
% clear all; close all;
% nargin(输入变量数)
w=8;
r=10;
d=1;
% 生成区域 A:
% 首先生成均匀随机分布的数据点 from (-r-w/2, 0)to (r+w/2, r+w/2)
N1=2*N; % 生成更多点并选择符合条件的点
w2=w/2;
done=0; data=[]; tmp1=[];
while ~done
%随机生成(m,1)的随机数
tmp=[2*(r+w2)*(rand(N1,1)-0.5) (r+w2)*rand(N1,1)];
tmp(:,3)=sqrt(tmp(:,1).*tmp(:,1)+tmp(:,2).*tmp(:,2)); %求到原点距离
idx=find((tmp(:,3)>r-w2) & (tmp(:,3)<r+w2));%返回非0数位置
tmp1=[tmp1;tmp(idx,1:2)];
%结束
if length(idx)>= N
done =1;
end
end
% 区域A数据和类标签0
% 区域B数据是区域A数据翻转y坐标-d,x坐标+r
data=[tmp1(1:N,:) ;[tmp1(1:N,1)+r -tmp1(1:N,2)-d ]];
plot(data(1:N,1),data(1:N,2),'.k',data(N+1:end,1),data(N+1:end,2),'.k');
title(['Double moon data set, d = ' num2str(d)]),
axis([-r-w2 2*r+w2 -r-w2-d r+w2])
save dbmoon data;
```bash
通过镜像和位移获得第二个半圆,N(生成点数量是可以自己定义)
完整代码资源指路:
你可以自己建个.m文件或者直接下载我的
https://download.csdn.net/download/Enjoy324/13137793
2求EPS
在本次实验中,由上文生成了一个200个点的双月型数据集
2.1如何求EPS
思想:求Eps的方法有很多,在这里只是提供了一种简单的思想。针对本实验是够用了。
这种方法是求出第K近邻距离,并且将其排序(注意,不是K近邻,是第K近邻,换句话说对于200个点的数据集来说,只是一个【200,1】矩阵)
通过调用k近邻函数将距离最近的前五个保存在一个数组中,
load('dbmoon');
A= data ();
%plot(data(:,1),data(:,2),'.b');
numData=size(A,1); %数据集中点个数=200
Kdist=zeros(numData,1);%生成一个【200,1】的0矩阵
%调用了K近邻函数 在A 找到距离a1的距离
[IDX,Dist]=knnsearch(A(1:numData,:),A(1,:),'k',5);
Kdist(1)=Dist(1,5);
for i=2:size(A,1)
[IDX,Dist] = knnsearch(A([1:i-1,i+1:numData],:),A(i,:),'k',5);
Kdist(i)=Dist(1,5);
end
[sortKdist,sortKdistIdx]=sort(Kdist);%距离排序,保留索引
distX=(1:numData);
plot(distX,sortKdist,'r-','LineWidth',1);
set(gcf,'position',[1000 340 350 350]);%位置
grid on;
因为Dist包含到自己本身的距离,所以想用第四近邻点是【1.5】
将该点
保存在新的数组中
Kdist(1)=Dist(1,5);`
重复这个过程得到一个200*1的数组
排序后,将其作为纵坐标,,将点的数量作为横坐标画图找转折点来确定Eps
画图如下:
该部分完整代码指路:
同样你可以自己建个.m文件或者直接下载我的
https://download.csdn.net/download/Enjoy324/13137793
如图,该转折点的纵坐标在(3,3.5),因此我们暂选3.2(随意挑选,对于本次实验来讲,其实可以选择的误差允许很多)
3.如何利用DBSCAN分类
3.1数据准备
由上文我们获得了( 数据集 Min-pot Eps)
如果你只是使用,直接找个人家封装好的调用呀(狗头)
3.2在这部分我想用伪代码解释应该更清楚并且记录一下我用到的函数。
function [IDX, isnoise]=DBSCAN(X,epsilon,MinPts)
C=0;
n=size(X,1);
IDX=zeros(n,1);
D=pdist2(X,X);%初始化距离矩阵
visited=false(n,1);
isnoise=false(n,1);
for i=1:n
%检查是否被遍历%已经遍历则直接将其属性保存在Neighbors中
if ~visited(i)
visited(i)=true;
Neighbors=RegionQuery(i);
%如果检查是不是噪音,如果近邻个数小于阈值是噪音
if numel(Neighbors)<MinPts
isnoise(i)=true;
else
%如果也不是噪音,则调用下面函数来找密度可达点
C=C+1;
ExpandCluster(i,Neighbors,C);
end
end
end
%扩展簇
function ExpandCluster(i,Neighbors,C)
IDX(i)=C;
% 从C开始
k = 1;
while true
%
j = Neighbors(k);
if ~visited(j)
visited(j)=true;%将其设为已经遍历
Neighbors2=RegionQuery(j);%调用函数找到(J)的近邻点
if numel(Neighbors2)>=MinPts
Neighbors=[Neighbors Neighbors2]; %#ok在迭代中更新簇
end
end
if IDX(j)==0
IDX(j)=C;%如果之前没有簇则形成新簇
end
k = k + 1;
if k > numel(Neighbors) %直到所有密度可达点都被遍历
break;
end
end
end
%确定是不是近邻点
function Neighbors=RegionQuery(i)
Neighbors=find(D(i,:)<=epsilon);
end
end
具体代码指路
最后贴一下我的主函数
clear all;
close all;
% creat_point (100);
% A = ans();
load('dbmoon');
A= data ();
%plot(data(:,1),data(:,2),'.b');
numData=size(A,1); %数据集中点个数=200
Kdist=zeros(numData,1);%生成一个【200,1】的0矩阵
%调用了K近邻函数 在A 找到距离a1的距离
[IDX,Dist]=knnsearch(A(1:numData,:),A(1,:),'k',5);
Kdist(1)=Dist(1,5);
for i=2:size(A,1)
[IDX,Dist] = knnsearch(A([1:i-1,i+1:numData],:),A(i,:),'k',5);
Kdist(i)=Dist(1,5);
end
[sortKdist,sortKdistIdx]=sort(Kdist);%距离排序,保留索引
distX=(1:numData);
plot(distX,sortKdist,'r-','LineWidth',1);
set(gcf,'position',[1000 340 350 350]);%位置
grid on;
%% Run DBSCAN Clustering Algorithm
epsilon= 3.2;%由图像观察【1-1.2】
MinPts= 4 ;
IDX1=DBSCAN(A,epsilon,MinPts);
%% Plot Results
figure;
PlotClusterinResult(A, IDX1);
title(['DBSCAN Clustering (\epsilon = ' num2str(epsilon) ', MinPts = ' num2str(MinPts) ')']);
set(gcf,'position',[30 -10 500 500]);
https://download.csdn.net/download/Enjoy324/13137793
(我将DBSCAN封装好了,调用就好,
找密度可达点函数封装在了DBSCAN函数中)
总结
DBSCAN其实网上有很多资料,优缺点也不赘述了,正如我推荐的博客一样。已经总结的很好。而我只是将我这次做的作业思路写了出来。如果对您的工作有帮助的话,还请给个赞呦
注:
仅供学习,欢迎交流,未经允许,请勿转载和他用