pascalabcnet/InstallerSamples/MachineLearning/04_Models/09_ClusteringDensityVsKMeans.pas

76 lines
2.5 KiB
ObjectPascal
Raw Permalink Normal View History

2026-03-25 14:07:27 +03:00
// Сравнение KMeans и DBSCAN на данных с шумом и разной плотностью.
//
2026-03-25 14:07:27 +03:00
// Оба алгоритма находят одинаковое число кластеров (k = 5),
// поэтому сравнение по ARI является корректным.
//
2026-03-25 14:07:27 +03:00
// KMeans предполагает компактные и одинаковые по форме кластеры,
// а также чувствителен к шуму, что снижает качество разбиения.
//
2026-03-25 14:07:27 +03:00
// DBSCAN выделяет кластеры как области высокой плотности
// и автоматически игнорирует шумовые точки (label = -1),
// благодаря чему лучше восстанавливает структуру данных.
//
2026-03-25 14:07:27 +03:00
// В результате DBSCAN показывает более высокий ARI,
// так как точнее отражает реальную геометрию кластеров.
2026-03-25 14:07:27 +03:00
// KMeans ARI: 0.8973
// 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);
kmeans.Fit(X);
var yKM := kmeans.Predict(X);
2026-03-25 14:07:27 +03:00
kmeans.ClustersCount.Println;
var db := new DBSCAN(0.7, 5);
var yDB := db.FitPredict(X);
2026-03-25 14:07:27 +03:00
db.ClustersCount.Println;
// --- метрики
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})';
end.