matlab编程实现基于密度的聚类(DBSCAN)
1. DBSCAN聚類的基本原理
詳細原理可以參考鏈接:
https://www.cnblogs.com/pinard/p/6208966.html
這是找到的相對很詳細的介紹了,此鏈接基本仍是周志華《機器學習》中的內容,不過這個鏈接更通俗一點,且算法流程感覺比《機器學習》書中的偽代碼形式算法流程更清晰。
2. matlab實現DBSCAN聚類
參考《機器學習》中的偽代碼編寫的算法,具體代碼如下:
function [clusterIndex, dataType] = DBSCAN(data, r, minPts)
% 本函數用于基于密度的聚類(DBSCAN)
% 輸入data為聚類數據,每行一個數據點
% 輸入r為密度聚類的滑動窗口半徑參數
% 輸入minPts為滑動窗口內數據量閾值參數
% 輸出clusterIndex為數據對應的類別號組成的序列
% 輸出objType為數據樣本類型,0表示噪聲樣本,1表示邊緣對象,2表示核心對象% 數據量大小
dataSize = length(data(:, 1));
% 預分配輸出的內存
clusterIndex = zeros(dataSize, 1);
dataType = zeros(dataSize, 1);
% 獲得距離方陣
distanceMatrix = squareform(pdist(data));% 標記核心對象集合
% 這里直接用距離矩陣判斷,相當于把自己到自己的距離0也算進去
for i = 1 : dataSizeif sum(distanceMatrix(:, i) < r) >= minPtsdataType(i) = 2;end
end
% 保存核心對象
coreObj = data(dataType == 2, :);% 初始化聚類簇的標記
k = 0;
% 初始化未被訪問的樣本集合
noData = data;% 進入迭代,如果核心對象集合非空,則進入迭代過程
while ~isempty(coreObj)% 記錄當前未被訪問樣本集合,noData數據每次迭代會更新noDataOld = noData;% 隨機選擇一個核心對象作為初始迭代對象randCoreIndex = randperm(length(coreObj(:, 1)), 1);initCoreObj = coreObj(randCoreIndex, :);% 初始化隊列,最初Q只有一個初始核心對象Q = initCoreObj;% 注:集合運算后默認是將集合排序過的,需要加stable參數來保持原來的順序% 從未訪問樣本中刪去隨機選擇的這個核心對象,只刪除這一個,不刪除它密度直達的對象noData = setdiff(noData, initCoreObj, 'stable', 'rows');% 進入循環,找到Q的所有密度可達對象,并放入隊列Q中while ~isempty(Q)% 取出Q中的第一個元素q = Q(1, :);Q(1, :) = [];% 再次距離計算,找到點q鄰域內的數據個數qSizeqIndex = ismember(data, q, 'rows') == 1;qSize = sum(distanceMatrix(qIndex, :) <= r);% q鄰域內的數據qAeraData = data(distanceMatrix(qIndex, :) <= r, :);% 如果數量超過閾值,則將鄰域內的的未訪問的數據賦給隊列Q if qSize >= minPts% 求交集D = qAereData∩noDataD = intersect(qAeraData, noData, 'stable', 'rows');% 將D中的元素加入隊列QQ = union(Q, D, 'stable', 'rows');% 再將這些數據從未訪問數據noData中刪除掉noData = setdiff(noData, D, 'stable', 'rows'); endendk = k + 1;% 生成聚類簇kCluster = setdiff(noDataOld, noData, 'stable', 'rows');coreObj = setdiff(coreObj, kCluster, 'stable', 'rows');% 記錄類編號clusterIndex(ismember(data, kCluster, 'rows')) = k;
end% 遍歷得到邊緣對象(非核心對象,但在類中)
for i = 1 : dataSizeif (dataType(i) ~= 2) && (clusterIndex(i) ~= 0)dataType(i) = 1;end
end% 函數結束
end
主函數調用:
clear all; close all;
model_class = 3;
dim = 2;
% 期望值
m = [0, 0;2, 2;-2, -2];
% 協方差陣
s(:, :, 1) = [0.1, 0;0, 0.1];
s(:, :, 2) = [0.5, 0.3;0.3, 0.5];
s(:, :, 3) = [1, -0.5;-0.5, 1];num = [500, 500, 500];
data = generate_data_GMM(dim, model_class, m, s, num);
data = data(:, (1:2));[T, N] = DBSCAN(data, 0.27, 9);figure(1)
for i = 1 : length(T)if N(i) == 0plot(data(i, 1), data(i, 2), '*k');hold on;% 邊緣對象elseif N(i) == 1if T(i) == 1plot(data(i, 1), data(i, 2), 'or');hold on;elseif T(i) == 2plot(data(i, 1), data(i, 2), 'og');hold on;elseif T(i) == 3plot(data(i, 1), data(i, 2), 'ob');hold on;else plot(data(i, 1), data(i, 2), 'oy');hold on;endelse % 核心對象if T(i) == 1plot(data(i, 1), data(i, 2), '.r');hold on;elseif T(i) == 2plot(data(i, 1), data(i, 2), '.g');hold on;elseif T(i) == 3plot(data(i, 1), data(i, 2), '.b');hold on;else plot(data(i, 1), data(i, 2), '.y');hold on;endendgrid on;
end% watermelon4_0 = load('watermelon4.0.txt');
% data = watermelon4_0;
聚類結果如下:
注:主函數給了兩個例子,一個是基于高斯分布數據,一個是基于《機器學習》書籍上的西瓜數據集4.0。這里高斯分布數據用到了筆者自編寫的generate_data_GMM函數,這個函數詳細說明及代碼請查看:
https://blog.csdn.net/sangnanpo/article/details/104222339
3. 其他說明
DBSCAN的主要優點有:
- 不需要輸入簇的數量
- 可以對任意形狀的稠密數據集進行聚類,相對的,K-Means之類的聚類算法一般只適用于凸數據集。
- 可以在聚類的同時發現噪聲點,對數據集中的噪聲點不敏感。
- 聚類結果沒有偏倚,相對的,K-Means之類的聚類算法初始值對聚類結果有很大影響。
DBSCAN的主要缺點有:
- 如果樣本集的密度不均勻、聚類間距差相差很大時,聚類質量較差,這時用DBSCAN聚類一般不適合。
- 如果樣本集較大時,聚類收斂時間較長,此時可以對搜索最近鄰時建立的KD樹或者球樹進行規模限制來改進。
- 需要調參數,調參相對于傳統的K-Means之類的聚類算法稍復雜,主要需要對距離閾值?,鄰域樣本數閾值MinPts聯合調參,不同的參數組合對最后的聚類效果有較大影響。這一點在具體實現時即可發現。
附:西瓜數據集4.0
0.697 0.460
0.774 0.376
0.634 0.264
0.608 0.318
0.556 0.215
0.403 0.237
0.481 0.149
0.437 0.211
0.666 0.091
0.243 0.267
0.245 0.057
0.343 0.099
0.639 0.161
0.657 0.198
0.360 0.370
0.593 0.042
0.719 0.103
0.359 0.188
0.339 0.241
0.282 0.257
0.748 0.232
0.714 0.346
0.483 0.312
0.478 0.437
0.525 0.369
0.751 0.489
0.532 0.472
0.473 0.376
0.725 0.445
0.446 0.459
總結
以上是生活随笔為你收集整理的matlab编程实现基于密度的聚类(DBSCAN)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab编程实现k_means聚类(
- 下一篇: 基于三维点云数据的主成分分析方法(PCA