2026-03-25 14:07:27 +03:00
|
|
|
|
// Сравнение KMeans и DBSCAN на данных с шумом и разной плотностью.
|
2026-03-24 14:26:08 +03:00
|
|
|
|
//
|
2026-03-25 14:07:27 +03:00
|
|
|
|
// Оба алгоритма находят одинаковое число кластеров (k = 5),
|
|
|
|
|
|
// поэтому сравнение по ARI является корректным.
|
2026-03-24 14:26:08 +03:00
|
|
|
|
//
|
2026-03-25 14:07:27 +03:00
|
|
|
|
// KMeans предполагает компактные и одинаковые по форме кластеры,
|
|
|
|
|
|
// а также чувствителен к шуму, что снижает качество разбиения.
|
2026-03-24 14:26:08 +03:00
|
|
|
|
//
|
2026-03-25 14:07:27 +03:00
|
|
|
|
// DBSCAN выделяет кластеры как области высокой плотности
|
|
|
|
|
|
// и автоматически игнорирует шумовые точки (label = -1),
|
|
|
|
|
|
// благодаря чему лучше восстанавливает структуру данных.
|
2026-03-24 14:26:08 +03:00
|
|
|
|
//
|
2026-03-25 14:07:27 +03:00
|
|
|
|
// В результате DBSCAN показывает более высокий ARI,
|
|
|
|
|
|
// так как точнее отражает реальную геометрию кластеров.
|
2026-03-24 14:26:08 +03:00
|
|
|
|
|
2026-03-25 14:07:27 +03:00
|
|
|
|
// KMeans ARI: 0.8973
|
2026-03-24 14:26:08 +03:00
|
|
|
|
// DBSCAN ARI: 0.9496
|
|
|
|
|
|
|
|
|
|
|
|
uses MLABC, PlotML;
|
|
|
|
|
|
|
|
|
|
|
|
begin
|
|
|
|
|
|
// --- данные (сложный случай: разная плотность + шум)
|
|
|
|
|
|
var (X, yTrue) := Datasets.MakeBlobs(
|
|
|
|
|
|
n := 400,
|
|
|
|
|
|
centers := 3,
|
|
|
|
|
|
nFeatures := 2,
|
|
|
|
|
|
clusterStd := 0.9,
|
|
|
|
|
|
clusterStdVar := 1.0,
|
|
|
|
|
|
centerBox := 6.0,
|
|
|
|
|
|
classBalance := 1.0,
|
|
|
|
|
|
noisePoints := 60,
|
|
|
|
|
|
shuffle := True,
|
|
|
|
|
|
seed := 1
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// --- модели
|
2026-03-25 14:07:27 +03:00
|
|
|
|
var kmeans := new KMeans(5);
|
2026-03-24 14:26:08 +03:00
|
|
|
|
kmeans.Fit(X);
|
2026-05-28 10:23:22 +03:00
|
|
|
|
var yKM := kmeans.Predict(X);
|
2026-03-25 14:07:27 +03:00
|
|
|
|
kmeans.ClustersCount.Println;
|
2026-03-24 14:26:08 +03:00
|
|
|
|
|
|
|
|
|
|
var db := new DBSCAN(0.7, 5);
|
2026-05-28 10:23:22 +03:00
|
|
|
|
var yDB := db.FitPredict(X);
|
2026-03-25 14:07:27 +03:00
|
|
|
|
db.ClustersCount.Println;
|
2026-03-24 14:26:08 +03:00
|
|
|
|
|
|
|
|
|
|
// --- метрики
|
|
|
|
|
|
var ariKM := Metrics.AdjustedRandIndex(yTrue, yKM);
|
|
|
|
|
|
var ariDB := Metrics.AdjustedRandIndex(yTrue, yDB);
|
|
|
|
|
|
|
|
|
|
|
|
Println('--- Clustering ---');
|
|
|
|
|
|
Println($'KMeans ARI: {ariKM,0:F4}');
|
|
|
|
|
|
Println($'DBSCAN ARI: {ariDB,0:F4}');
|
|
|
|
|
|
Println;
|
|
|
|
|
|
|
|
|
|
|
|
// --- координаты
|
|
|
|
|
|
var x1 := X.Col(0);
|
|
|
|
|
|
var x2 := X.Col(1);
|
|
|
|
|
|
|
|
|
|
|
|
// --- визуализация
|
|
|
|
|
|
var fig := Plot.Grid(1, 2);
|
|
|
|
|
|
|
|
|
|
|
|
// KMeans
|
|
|
|
|
|
//fig[0,0].SetPalette(Palettes.Bright);
|
|
|
|
|
|
fig[0,0].Points(x1, x2, yKM, size := 6);
|
|
|
|
|
|
fig[0,0].Title := $'KMeans (ARI={ariKM,0:F3})';
|
|
|
|
|
|
|
|
|
|
|
|
var yDB_plot := new integer[yDB.Length];
|
|
|
|
|
|
|
|
|
|
|
|
for var i := 0 to yDB.Length - 1 do
|
|
|
|
|
|
yDB_plot[i] := if yDB[i] = -1 then 0 else yDB[i] + 1;
|
|
|
|
|
|
// DBSCAN
|
|
|
|
|
|
//fig[0,1].SetPalette(Palettes.Bright);
|
|
|
|
|
|
fig[0,1].Points(x1, x2, yDB_plot, size := 6);
|
|
|
|
|
|
fig[0,1].Title := $'DBSCAN (ARI={ariDB,0:F3})';
|
2026-05-28 10:23:22 +03:00
|
|
|
|
end.
|