matlab编程实现基于密度的聚类(DBSCAN)
1. DBSCAN聚類的基本原理
詳細(xì)原理可以參考鏈接:
https://www.cnblogs.com/pinard/p/6208966.html
這是找到的相對很詳細(xì)的介紹了,此鏈接基本仍是周志華《機器學(xué)習(xí)》中的內(nèi)容,不過這個鏈接更通俗一點,且算法流程感覺比《機器學(xué)習(xí)》書中的偽代碼形式算法流程更清晰。
2. matlab實現(xiàn)DBSCAN聚類
參考《機器學(xué)習(xí)》中的偽代碼編寫的算法,具體代碼如下:
function [clusterIndex, dataType] = DBSCAN(data, r, minPts)
% 本函數(shù)用于基于密度的聚類(DBSCAN)
% 輸入data為聚類數(shù)據(jù),每行一個數(shù)據(jù)點
% 輸入r為密度聚類的滑動窗口半徑參數(shù)
% 輸入minPts為滑動窗口內(nèi)數(shù)據(jù)量閾值參數(shù)
% 輸出clusterIndex為數(shù)據(jù)對應(yīng)的類別號組成的序列
% 輸出objType為數(shù)據(jù)樣本類型,0表示噪聲樣本,1表示邊緣對象,2表示核心對象% 數(shù)據(jù)量大小
dataSize = length(data(:, 1));
% 預(yù)分配輸出的內(nèi)存
clusterIndex = zeros(dataSize, 1);
dataType = zeros(dataSize, 1);
% 獲得距離方陣
distanceMatrix = squareform(pdist(data));% 標(biāo)記核心對象集合
% 這里直接用距離矩陣判斷,相當(dāng)于把自己到自己的距離0也算進(jìn)去
for i = 1 : dataSizeif sum(distanceMatrix(:, i) < r) >= minPtsdataType(i) = 2;end
end
% 保存核心對象
coreObj = data(dataType == 2, :);% 初始化聚類簇的標(biāo)記
k = 0;
% 初始化未被訪問的樣本集合
noData = data;% 進(jìn)入迭代,如果核心對象集合非空,則進(jìn)入迭代過程
while ~isempty(coreObj)% 記錄當(dāng)前未被訪問樣本集合,noData數(shù)據(jù)每次迭代會更新noDataOld = noData;% 隨機選擇一個核心對象作為初始迭代對象randCoreIndex = randperm(length(coreObj(:, 1)), 1);initCoreObj = coreObj(randCoreIndex, :);% 初始化隊列,最初Q只有一個初始核心對象Q = initCoreObj;% 注:集合運算后默認(rèn)是將集合排序過的,需要加stable參數(shù)來保持原來的順序% 從未訪問樣本中刪去隨機選擇的這個核心對象,只刪除這一個,不刪除它密度直達(dá)的對象noData = setdiff(noData, initCoreObj, 'stable', 'rows');% 進(jìn)入循環(huán),找到Q的所有密度可達(dá)對象,并放入隊列Q中while ~isempty(Q)% 取出Q中的第一個元素q = Q(1, :);Q(1, :) = [];% 再次距離計算,找到點q鄰域內(nèi)的數(shù)據(jù)個數(shù)qSizeqIndex = ismember(data, q, 'rows') == 1;qSize = sum(distanceMatrix(qIndex, :) <= r);% q鄰域內(nèi)的數(shù)據(jù)qAeraData = data(distanceMatrix(qIndex, :) <= r, :);% 如果數(shù)量超過閾值,則將鄰域內(nèi)的的未訪問的數(shù)據(jù)賦給隊列Q if qSize >= minPts% 求交集D = qAereData∩noDataD = intersect(qAeraData, noData, 'stable', 'rows');% 將D中的元素加入隊列QQ = union(Q, D, 'stable', 'rows');% 再將這些數(shù)據(jù)從未訪問數(shù)據(jù)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% 函數(shù)結(jié)束
end
主函數(shù)調(diào)用:
clear all; close all;
model_class = 3;
dim = 2;
% 期望值
m = [0, 0;2, 2;-2, -2];
% 協(xié)方差陣
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;
聚類結(jié)果如下:
注:主函數(shù)給了兩個例子,一個是基于高斯分布數(shù)據(jù),一個是基于《機器學(xué)習(xí)》書籍上的西瓜數(shù)據(jù)集4.0。這里高斯分布數(shù)據(jù)用到了筆者自編寫的generate_data_GMM函數(shù),這個函數(shù)詳細(xì)說明及代碼請查看:
https://blog.csdn.net/sangnanpo/article/details/104222339
3. 其他說明
DBSCAN的主要優(yōu)點有:
- 不需要輸入簇的數(shù)量
- 可以對任意形狀的稠密數(shù)據(jù)集進(jìn)行聚類,相對的,K-Means之類的聚類算法一般只適用于凸數(shù)據(jù)集。
- 可以在聚類的同時發(fā)現(xiàn)噪聲點,對數(shù)據(jù)集中的噪聲點不敏感。
- 聚類結(jié)果沒有偏倚,相對的,K-Means之類的聚類算法初始值對聚類結(jié)果有很大影響。
DBSCAN的主要缺點有:
- 如果樣本集的密度不均勻、聚類間距差相差很大時,聚類質(zhì)量較差,這時用DBSCAN聚類一般不適合。
- 如果樣本集較大時,聚類收斂時間較長,此時可以對搜索最近鄰時建立的KD樹或者球樹進(jìn)行規(guī)模限制來改進(jìn)。
- 需要調(diào)參數(shù),調(diào)參相對于傳統(tǒng)的K-Means之類的聚類算法稍復(fù)雜,主要需要對距離閾值?,鄰域樣本數(shù)閾值MinPts聯(lián)合調(diào)參,不同的參數(shù)組合對最后的聚類效果有較大影響。這一點在具體實現(xiàn)時即可發(fā)現(xiàn)。
附:西瓜數(shù)據(jù)集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
總結(jié)
以上是生活随笔為你收集整理的matlab编程实现基于密度的聚类(DBSCAN)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab编程实现k_means聚类(
- 下一篇: 基于三维点云数据的主成分分析方法(PCA