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
49 lines (46 loc) • 1.89 kB
JavaScript
// Предполагаемый интерфейс: new DBSCAN(points, eps, minPts).run()
// Возвращает массив меток кластеров длины points.length, где -1 = шум
import DBSCAN from '../../../lib/analyze/dbscan/dbscan.js';
import { makeRng } from '../_rng.js';
function blobs(R, cfg) {
const { centers, nPer, sigma } = cfg;
const pts = {};
centers.forEach(([cx, cy],i) => {
const xs = R.normal(cx, sigma, nPer);
const ys = R.normal(cy, sigma, nPer);
for (let i=0;i<nPer;i++) pts[`v${i}`] = [xs[i], ys[i]];
});
return pts;
}
export const dbscanTool = {
id: 'dbscan',
cases: 5,
gen(seed, i) {
const R = makeRng(`${seed}/db/${i}`);
const cfg = {
centers: [[0,0],[6,0],[0,6]],
nPer: 40 + 5*(i%3),
sigma: 0.6 + 0.1*(i%2)
};
const pts = blobs(R, cfg);
// eps выбираем заметно меньше межкластерного расстояния
const eps = 1.2, minPts = 5;
return { pts, eps, minPts };
},
compute({pts, eps, minPts}) {
const {labels} = new DBSCAN(pts,{eps, minPts});
// метрики, устойчивые к переименованию кластеров:
const k = new Set(labels.filter(l => l>=0)).size;
const sizes = Object.values(labels.reduce((m,l)=>{
if (l>=0) m[l]=(m[l]||0)+1; return m;
},{})).sort((a,b)=>b-a);
const noise = labels.filter(l=>l<0).length / labels.length;
return { k, sizes, noise };
},
compare(exp, got, approx) {
if (got.k !== exp.k) throw new Error(`clusters k ${got.k} != ${exp.k}`);
if (got.sizes.length !== exp.sizes.length) throw new Error('sizes length mismatch');
for (let i=0;i<exp.sizes.length;i++) if (got.sizes[i]!==exp.sizes[i]) throw new Error(`size[${i}] mismatch`);
approx(got.noise, exp.noise);
},
};