Estimators¶
EVoC runs the whole pipeline on the CPU. EVoCGpu moves the kNN stage onto
the GPU and is only present in a build carrying the gpu feature.
estimator
¶
The EVoC estimators.
EVoC runs the whole pipeline on the CPU. EVoCGpu moves the kNN stage onto
the GPU and leaves everything else where it was, which is the only part of EVoC
that is worth the transfer.
EVoC
¶
EVoC(
n_neighbours: int = 15,
*,
noise_level: float = 0.5,
n_epochs: int = 50,
embedding_dim: int | None = None,
neighbour_scale: float = 1.0,
symmetrise: bool = True,
min_samples: int = 5,
base_min_cluster_size: int = 5,
approx_n_clusters: int | None = None,
min_similarity_threshold: float = 0.2,
max_layers: int = 10,
ann_algorithm: str = "nndescent",
metric: str = "euclidean",
n_tree: int = 50,
search_budget: int | None = None,
m: int = 16,
ef_construction: int = 200,
ef_search: int = 100,
diversify_prob: float = 1.0,
delta: float = 0.001,
ef_budget: int | None = None,
extract_knn: bool = True,
bt_budget: float = 0.05,
n_list: int | None = None,
n_probes: int | None = None,
seed: int = 42,
verbose: int = 0,
)
Bases: BaseEstimator
Cluster high-dimensional embeddings with EVoC.
Six stages: an approximate kNN graph, a fuzzy simplicial set over it, a label-propagation initialisation, a UMAP-like node embedding, an MST over mutual reachability distances, then a hierarchy of clusterings pulled out of that tree by persistence.
The hierarchy is the point. cluster_layers_ holds one labelling per
granularity, finest first, and labels_ picks the layer with the highest
persistence score. Set approx_n_clusters instead if you know how many
clusters you want, and the finest layer is binary-searched for it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_neighbours
|
int
|
Neighbours per point in the kNN graph. |
15
|
noise_level
|
float
|
Repulsion strength in the embedding gradient. 0.0 is aggressive, 1.0 conservative. |
0.5
|
n_epochs
|
int
|
Embedding optimisation epochs. |
50
|
embedding_dim
|
int | None
|
Embedding dimensionality. None derives it from
|
None
|
neighbour_scale
|
float
|
Multiplier on the effective neighbour count when building the fuzzy graph. |
1.0
|
symmetrise
|
bool
|
Whether to symmetrise the fuzzy graph. |
True
|
min_samples
|
int
|
Points used for the core distance in the MST density estimate. |
5
|
base_min_cluster_size
|
int
|
Minimum cluster size at the finest layer. |
5
|
approx_n_clusters
|
int | None
|
Binary-search |
None
|
min_similarity_threshold
|
float
|
Jaccard similarity above which two layers count as redundant and the coarser one is dropped. |
0.2
|
max_layers
|
int
|
Cap on the layers returned. |
10
|
ann_algorithm
|
str
|
kNN backend. One of nndescent, hnsw, annoy, ivf, kmknn, balltree, exhaustive. |
'nndescent'
|
metric
|
str
|
Distance metric, euclidean or cosine. |
'euclidean'
|
n_tree
|
int
|
Annoy trees. |
50
|
search_budget
|
int | None
|
Annoy candidates per query. None uses the crate default. |
None
|
m
|
int
|
HNSW connections per layer. |
16
|
ef_construction
|
int
|
HNSW construction budget. |
200
|
ef_search
|
int
|
HNSW search budget. |
100
|
diversify_prob
|
float
|
NN-Descent diversification probability. |
1.0
|
delta
|
float
|
NN-Descent convergence threshold. |
0.001
|
ef_budget
|
int | None
|
NN-Descent beam budget when querying. Ignored when extract_knn is True, since no search runs. |
None
|
extract_knn
|
bool
|
For nndescent, return the graph the descent already built rather than beam-searching it. On by default: a self-kNN query re-does the work the descent just did. |
True
|
bt_budget
|
float
|
BallTree search budget, as a fraction of the sample count. |
0.05
|
n_list
|
int | None
|
IVF cells. None uses sqrt(n). |
None
|
n_probes
|
int | None
|
IVF cells probed per query. None uses sqrt(n_list). |
None
|
seed
|
int
|
Random seed. |
42
|
verbose
|
int
|
0 silent, 1 normal, 2 detailed. |
0
|
Attributes:
| Name | Type | Description |
|---|---|---|
labels_ |
ndarray | None
|
|
membership_strengths_ |
ndarray | None
|
|
cluster_layers_ |
ndarray | None
|
|
layer_strengths_ |
ndarray | None
|
|
persistence_scores_ |
ndarray | None
|
|
neighbour_graph_ |
tuple[ndarray, ndarray] | None
|
|
n_clusters_ |
int
|
Non-noise clusters in |
n_features_in_ |
int | None
|
Columns seen during |
Example
import numpy as np from evoc_rs import EVoC rng = np.random.default_rng(0) X = np.vstack([rng.normal(c * 20, 1, (200, 32)) for c in range(3)]) labels = EVoC(n_neighbours=15).fit_predict(X.astype(np.float32))
n_clusters_
property
¶
Non-noise clusters in labels_.
Returns:
| Type | Description |
|---|---|
int
|
The count, 0 when everything is noise. |
Raises:
| Type | Description |
|---|---|
NotFittedError
|
If |
fit
¶
fit(
X: ndarray,
y: None = None,
*,
precomputed_knn: tuple[ndarray, ndarray] | None = None,
) -> EVoC
Cluster X.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
|
required |
y
|
None
|
Ignored. Present so the estimator fits in a scikit-learn pipeline. |
None
|
precomputed_knn
|
tuple[ndarray, ndarray] | None
|
|
None
|
Returns:
| Type | Description |
|---|---|
EVoC
|
The fitted estimator, so calls chain. |
fit_predict
¶
fit_predict(
X: ndarray,
y: None = None,
*,
precomputed_knn: tuple[ndarray, ndarray] | None = None,
) -> ndarray
Cluster X and return the labels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
|
required |
y
|
None
|
Ignored. |
None
|
precomputed_knn
|
tuple[ndarray, ndarray] | None
|
As for |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
|
EVoCGpu
¶
EVoCGpu(
n_neighbours: int = 15,
*,
noise_level: float = 0.5,
n_epochs: int = 50,
embedding_dim: int | None = None,
neighbour_scale: float = 1.0,
symmetrise: bool = True,
min_samples: int = 5,
base_min_cluster_size: int = 5,
approx_n_clusters: int | None = None,
min_similarity_threshold: float = 0.2,
max_layers: int = 10,
ann_algorithm: str = "ivf_gpu",
metric: str = "euclidean",
n_list: int | None = None,
n_probes: int | None = None,
k: int | None = None,
k_build: int | None = None,
n_tree: int | None = None,
delta: float = 0.001,
rho: float | None = None,
beam_width: int | None = None,
max_beam_iters: int | None = None,
n_entry_points: int | None = None,
extract_knn: bool = True,
seed: int = 42,
verbose: int = 0,
)
Bases: EVoC
EVoC with the kNN stage on the GPU.
Everything downstream of the graph stays on the CPU, so this only pays off when the kNN search dominates: many points, high dimension, or an exhaustive search. float32 only, because WGSL has no f64.
Args and attributes are those of EVoC, with these differences:
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ann_algorithm
|
str
|
One of exhaustive_gpu, ivf_gpu, nndescent_gpu. |
'ivf_gpu'
|
k
|
int | None
|
CAGRA graph degree after pruning, for nndescent_gpu. None backfills
from |
None
|
k_build
|
int | None
|
Build degree before pruning. None backfills to
|
None
|
n_tree
|
int | None
|
Trees initialising the kNN graph. None uses the crate default. |
None
|
rho
|
float | None
|
NN-Descent sampling rate. None auto-picks. |
None
|
beam_width
|
int | None
|
Beam width when querying. None auto-picks. |
None
|
max_beam_iters
|
int | None
|
Beam iterations when querying. None auto-picks. |
None
|
n_entry_points
|
int | None
|
Entry points when querying. None auto-picks. |
None
|
extract_knn
|
bool
|
For nndescent_gpu, return the CAGRA graph the build already produced rather than beam-searching it. On by default, and worth keeping: it is roughly 5x faster for about 0.4% recall. |
True
|