UNPKG

als-statistics

Version:

Modular JS statistics toolkit for Node.js and the browser: descriptive stats, correlations (Pearson/Spearman/Kendall), t-tests & ANOVA (Student/Welch), reliability (Cronbach’s alpha), regression (linear/logistic), clustering (DBSCAN/HDBSCAN), and table/co

61 lines (54 loc) 2.16 kB
import computeDistances from './compute-dist.js'; import { buildClusters } from './build-clusters.js' import { TestBase } from '../test-base/index.js' export default class Dbscan extends TestBase { constructor(samples, options = {}) { super(samples, 'Dbscan',[], { min: 2 }) const { eps = 0.4, minPts = 3, metric = 'mad' } = options this.metric = metric; this.eps = eps; this.minPts = minPts; this.labels = new Array(this.k).fill(0); // 0: не обработан, -1: шум, 1+: кластер this.clusters = []; this.distances = computeDistances(this.samples,this.metric) this.run(); buildClusters(this); } findNeighbors(pointIdx) { const neighbors = []; for (let i = 0; i < this.k; i++) { const d = this.distances[pointIdx][i]; if (Number.isFinite(d) && d <= this.eps) neighbors.push(i); } return neighbors; } expandCluster(pointIdx, clusterId) { this.labels[pointIdx] = clusterId; const seeds = this.findNeighbors(pointIdx).filter(idx => idx !== pointIdx); while (seeds.length > 0) { const current = seeds.pop(); if (this.labels[current] === -1) this.labels[current] = clusterId; // шум -> кластер if (this.labels[current] !== 0) continue; // уже помечен this.labels[current] = clusterId; const currentNeighbors = this.findNeighbors(current); if (currentNeighbors.length >= this.minPts) { for (const nb of currentNeighbors) { if (this.labels[nb] === 0) seeds.push(nb); } } } } run() { // Основной алгоритм DBSCAN let clusterId = 0; for (let i = 0; i < this.k; i++) { if (this.labels[i] !== 0) continue; // уже обработан const neighbors = this.findNeighbors(i); if (neighbors.length < this.minPts) { this.labels[i] = -1; // шум continue; } clusterId++; this.expandCluster(i, clusterId); } } }