import { ClusterBase } from '../base/cluster'; import { Params } from '../base/estimator'; import { Distance } from '../metrics'; /** * AgglomerativeClustering: bottom-up hierarchical clustering, following * sklearn.cluster.AgglomerativeClustering. * * - 'ward', 'complete' and 'average' linkage use the nearest-neighbor chain * algorithm (Müllner 2011, the same algorithm scipy's `linkage` and * sklearn use) with Lance-Williams distance updates. NN-chain finds * reciprocal nearest neighbors by walking a chain of nearest neighbors; * every merge is provably identical to the naive O(n^3) greedy * agglomeration for reducible linkages, but runs in O(n^2) time. * - 'single' linkage is computed from the minimum spanning tree (Prim on the * dense distance matrix, then Kruskal-style processing of the sorted * edges), exactly like scipy's `mst_single_linkage`. * * The merge tree is exposed scipy/sklearn-style: `getChildren()` has shape * [n-1][2] where values < n are leaves and value n+i refers to the cluster * created at merge row i; `getDistances()` gives the merge distances * (non-decreasing, rows are sorted by distance like scipy's linkage output). * * Flat clusters are obtained either by requesting `nClusters` or by cutting * all merges with distance >= `distanceThreshold` (exactly one of the two * must be set, as in sklearn). Cluster labels are numbered by first sample * occurrence (sklearn numbers them in a different, heap-dependent order; the * partition itself is identical). */ export type AgglomerativeLinkage = 'ward' | 'complete' | 'average' | 'single'; export interface AgglomerativeClusteringProps { /** * number of flat clusters to extract; must be set to null when * `distanceThreshold` is used */ nClusters?: number | null; /** linkage criterion */ linkage?: AgglomerativeLinkage; /** distance metric name ('ward' requires 'euclidean') */ metric?: Distance.IDistanceType; /** * when set (with nClusters null), merges with distance >= this * threshold are not performed and the remaining components become the * flat clusters */ distanceThreshold?: number | null; } export declare class AgglomerativeClustering extends ClusterBase { private nClusters; private linkage; private metric; private distanceThreshold; private labels; /** merge tree, shape [n-1][2] (sklearn's children_) */ private children; /** merge distance per row of `children` (sklearn's distances_) */ private distances; /** number of flat clusters found by the last fit (sklearn's n_clusters_) */ private nClustersFitted; constructor(props?: AgglomerativeClusteringProps); getParams(): Params; /** resolved lazily from the metric name so instances stay JSON-serializable */ private get distance(); fitPredict(samplesX: number[][]): number[]; getLabels(): number[]; /** merge tree from the last fit, shape [n-1][2] (sklearn's children_) */ getChildren(): number[][]; /** merge distances from the last fit, one per row of getChildren() */ getDistances(): number[]; /** number of flat clusters found by the last fit */ getNClusters(): number; private pairwiseDistances; /** Lance-Williams distance update for the merged cluster (x ∪ y) vs i. */ private newDistance; /** * Nearest-neighbor chain agglomeration (scipy's `nn_chain`). `dist` is * mutated in place: row/column y holds the distances of the merged * cluster after each merge; dead clusters keep size 0. * * Returned merges reference *leaf representative* indices (as in scipy): * the sorted-relabel step afterwards converts them into cluster labels. */ private nnChain; /** * Single linkage from the minimum spanning tree (scipy's * `mst_single_linkage`): Prim's algorithm on the dense distance matrix. * The MST edges are exactly the single-linkage merges once sorted. */ private static mstSingleLinkage; /** * Flat clusters from the first n - nClusters merge rows (rows are sorted * by distance, so stopping early is exactly sklearn's `_hc_cut`, which * repeatedly re-splits the most recent merge). Labels are numbered by * first sample occurrence. */ private cutTree; }