OPTICS (Ordering points to identify the clustering structure)演算法實現
阿新 • • 發佈:2019-01-06
本文依照《資料探勘概念與技術》第三版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