DBSCAN密度聚类,matlab 练手项目,2700字带你手撕课设作业!

绪论

刚刚完成了一个关于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()函数在这个范围内生成随机数,
R是半径 W是圆环厚度,R+W是大圆环半径  R-W为小圆环半径
代码如下:

```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其实网上有很多资料,优缺点也不赘述了,正如我推荐的博客一样。已经总结的很好。而我只是将我这次做的作业思路写了出来。如果对您的工作有帮助的话,还请给个赞呦

注:
仅供学习,欢迎交流,未经允许,请勿转载和他用

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值