OPTICS (Ordering points to identify the clustering structure)算法实现

本文依照《数据挖掘概念与技术》第三版OPTICS算法描述,同时借鉴了博主皮果提对OPTICS算法的总结http://blog.csdn.net/itplus/article/details/10089323,以及本人之前缩写的DBSCAN算法http://blog.csdn.net/lengo/article/details/78700607综合而来。个人觉得OPTICS算法与DBSCAN算法基本相似,不同之处在于增加了对可达距离的排序,利用有序的可达距离来表达不同簇的结构。本文的实验数据量较大,请在网盘上下载:https://pan.baidu.com/s/1pLXFsJx。

以下是实现主程序:

clc;
clear;
%读取文件,前两列为x,y坐标数据
fileID = fopen('D:\matlabFile\OPTICS\optics.txt');
DS=textscan(fileID,'%f %f');
fclose(fileID);
%邻域阈值
eps=0.5;
%密度阈值
minPts=5;
%将cell数据转为矩阵形式
DB=cat(2,DS{1},DS{2});
% scatter(DB(:,1),DB(:,2),'filled');
%增加第三列,点的顺序编号
ind=1:size(DB,1);
DB=cat(2,DB,ind');
%增加最后一列访问标记,初始为未访问0
Col=zeros(size(DB,1),1);
DB=cat(2,DB,Col);
%结果队列,第一列为点的编号,第二列为该点的可达距离,第三列为类别序号
Outputs=zeros(1,3);
%离群队列,保存离群结果
Outliers=zeros(1,1);
DB_back=DB;
%簇编号
count=1;
while ~isempty(DB_back)
    Row=size(DB_back,1);
    %随机选择一个对象作为起始点
    index=randi(Row,1,1);
    p=DB_back(index,:);
    %确定目标是未被访问过的
    if p(1,4)==0
        %将原始数据集中的目标对象标记为访问过
        DB(p(1,3),4)=1;
        %将第index个元数据从备份数据集中删除
        DB_back(index,:)=[];
        %计算目标对象p与数据集所有元素的可达距离,结果保存在排序队列,第一列为
        OrderSeeds=ReachedDist(p,DB,eps);
        %如果排序列表中的数量满足密度阈值,则目标点为核心对象,加入输出队列
        if size(OrderSeeds,1)>=minPts-1
            %取得满足密度阈值的对象
            Obj=OrderSeeds(minPts-1,:);
            %确定目标对象的核心距离
            coreDist=Obj(1,2);
            %输出目标对象序号
            Outputs=cat(1,Outputs,[p(1,3),coreDist,count]);
            %遍历排序队列
            while ~isempty(OrderSeeds)               
                %依次取出排序队列
                for i=1:size(OrderSeeds)
                    q=DB(OrderSeeds(i,1),:);
                    %判断q是否被访问
                    if q(1,4)==0
                        DB(OrderSeeds(i,1),4)=1;
                        %计算目标对象q与数据集所有元素的可达距离
                        subOrderSeeds=ReachedDist(q,DB,eps);
                        if size(subOrderSeeds,1)>minPts-1
                            %查看结果队列中是否有对象q,没有则加入
                            r1=find(Outputs(:,1)==q(1,3));
                            if isempty(r1)
                                Outputs=cat(1,Outputs,[OrderSeeds(i,:),count]);
                            end
                            %判断子排队序列是否存在于排队序列
                            for j=1:size(subOrderSeeds,1)                                
                                r2=find(Outputs(:,1)==subOrderSeeds(j,1)); 
                                %若不存在,则加入
                                if isempty(r2)
                                    %查看是否在结果队列中
                                    r3=find(OrderSeeds(:,1)==subOrderSeeds(j,1));
                                    if isempty(r3)
                                        OrderSeeds=cat(1,OrderSeeds,subOrderSeeds(j,:));
                                    end                                    
                                end
                            end
                            %从排序队列中删除
                            OrderSeeds(i,:)=[];
                            %对排序队列按照可达距离重新排序
                            OrderSeeds=sortrows(OrderSeeds,2);
                            %删除备份数据集中的对象q
                            r4=find(DB_back(:,3)==q(1,3));
                            if ~isempty(r4)
                                DB_back(r4,:)=[];
                            end
                            %结束for循环
                            break;
                        end
                    end 
                end
            end
            %簇编号加1
            count=count+1;
        else
            %将目标对象保存到离群队列
            Outliers=cat(1,Outliers,p(1,3));
        end
    end
end
%删除第一行的零值
Outliers(1,:)=[];
Outputs(1,:)=[];
%显示结果
x0=0;
%检索分类序号
CID=unique(Outputs(:,3));
for i=1:length(CID)
    r5=find(Outputs(:,3)==CID(i));
    y=Outputs(r5,:);
    x=1+x0:size(y,1)+x0;
    c=[i*0.2 1-i*0.1 1-i*0.1];
    stem(x,y(:,2),'Marker','none','Color',c);
    x0=x0+size(y,1);
    hold on
end
hold off
xlabel('序号');
ylabel('可达距离');
ylim([0 0.7]);

ReachedDist函数实现如下:

function OrderSeeds=ReachedDist(point,Dataset,eps)
    OrderSeeds=zeros(1,2);
    for i=1:size(Dataset,1)
        %计算两点之间的距离
        dist=sqrt((Dataset(i,1)-point(1))^2+(Dataset(i,2)-point(2))^2);
        %如在邻域范围内,加入排序队列
        if dist==0
            continue;
        end
        if dist<=eps
            temp=[Dataset(i,3),dist];
            OrderSeeds=cat(1,OrderSeeds,temp);
        end
    end
    %删除第一行零值
    OrderSeeds(1,:)=[];
    %如果是非空,则进行排序
    if ~isempty(OrderSeeds)
        %按照第三列距离值降序排列
        OrderSeeds=sortrows(OrderSeeds,2);
    end
end

版权声明:本文为博主原创文章,未经博主允许不得转载。
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值