After projecting embeddings with ls-umap, the ls-cluster step assigns every
point a cluster id. Latent Scope 1.0 supports four clustering methods and lets
you choose whether to cluster on the 2D UMAP projection or the original
high-dimensional embedding (issue #41).
# ls-cluster <dataset_id> <umap_id> <samples> <min_samples> <cluster_selection_epsilon> [column]
# [--method {evoc,hdbscan,kmeans,gmm}] [--cluster_on {umap,embedding}]
# [--n_neighbors N] [--noise_level F] [--approx_n_clusters N]
# [--base_n_clusters N] [--seed N] [--assign-noise]
# [--name ...] [--description ...]
ls-cluster mydataset umap-001 5 3 0.0 --method hdbscanThe positionals samples, min_samples, and cluster_selection_epsilon are
always required (in that order); min_samples and cluster_selection_epsilon
are only meaningful for HDBSCAN but must still be supplied for the other methods.
| Method | Library | What samples means |
Emits noise (-1)? |
|---|---|---|---|
evoc (default) |
EVoC | base_min_cluster_size |
yes |
hdbscan |
hdbscan / cuML |
min_cluster_size |
yes |
kmeans |
scikit-learn / cuML | number of clusters | no |
gmm |
scikit-learn (GaussianMixture) |
number of clusters (components) | no |
-
EVoC and HDBSCAN are density-based:
samplesis the minimum cluster size, and points that don't fit a cluster are marked as noise (-1). By default the noise points are kept as an explicit extra cluster labeled "Unclustered" (with no hull drawn around it), so the map stays honest about what the algorithm couldn't place. Pass--assign-noiseto instead reassign every noise point to its nearest cluster centroid (the pre-1.0 behavior). Either way the run prints the noise count and percentage, the original-1labels are preserved in theraw_clustercolumn, and the run metadata recordsn_noise,assign_noise, and (when present) the id of theunclustered_cluster. -
KMeans and GMM are partitional:
samplesis the target number of clusters, and every point is always assigned (no noise).min_samplesandcluster_selection_epsilonare ignored for these methods but still positional:# 20 clusters via KMeans; the 3 and 0.0 are ignored placeholders ls-cluster mydataset umap-001 20 3 0.0 --method kmeans ls-cluster mydataset umap-001 15 3 0.0 --method gmm
EVoC-only tuning flags: --n_neighbors (kNN graph, default 15),
--noise_level (0.0–1.0, default 0.5), --approx_n_clusters (aim for roughly
this many clusters in the final output), and --base_n_clusters (target
exactly this many clusters at the finest layer of the hierarchy). The
min_samples positional is forwarded to EVoC as well as HDBSCAN. --seed
makes evoc, kmeans, and gmm runs reproducible (HDBSCAN is deterministic
for a fixed input).
min_cluster_size (the samples positional) has cliff behavior: small
changes can collapse the clustering. On one real dataset, moving
min_cluster_size from 150 to 160 dropped the result from 53 clusters to 3,
and on another from 110 to 120 dropped it from 55 to 5. Where the cliff sits is
specific to each embedding, so sweep the value in small steps around your
current setting rather than jumping by large factors. Separately,
min_samples=1 is an effective lever for reducing the noise fraction — in the
same report it cut noise from 33% to ~25% of the dataset — without collapsing
the clustering the way a larger min_cluster_size can.
--cluster_on {umap,embedding} selects which space is clustered:
umap— the 2D projection fromls-umap(fast, matches what you see on the map).embedding— the original high-dimensional vectors (captures structure that UMAP may have flattened).
When omitted, the default preserves the historical per-method behavior:
| Method | Default --cluster_on |
|---|---|
evoc |
embedding |
hdbscan, kmeans, gmm |
umap |
The effective value (whether defaulted or explicit) is always written to
cluster-NNN.json as cluster_on. Note the 2D UMAP coordinates are still used
for plotting, convex hulls, and noise reassignment regardless of this choice.
Any cluster (or umap) run can carry a human-friendly title and description:
ls-cluster mydataset umap-001 5 3 0.0 --method hdbscan \
--name "HDBSCAN min5" --description "density clustering on the umap projection"These are stored in the run's metadata JSON (cluster-NNN.json /
umap-NNN.json) and shown in the Setup UI, which now renders a browsable
gallery of runs — thumbnail, title, parameter badges, and cluster quality
metrics — instead of a bare cluster-001, cluster-002 id list. You can edit a
run's name/description inline in the gallery without re-running it.
HDBSCAN and KMeans use their cuML equivalents when a GPU backend is active; EVoC
and GMM always run on CPU. See docs/gpu-acceleration.md
for LATENT_SCOPE_DEVICE and the optional latentscope[gpu] install.
Label the clusters (optionally with an LLM) and build a scope:
# ls-label <dataset_id> <text_column> <cluster_id> <chat_model_id> <samples> <context>
ls-label mydataset text cluster-001 openai-gpt-4o-mini 0 "" # optional; else use the default labels
ls-scope mydataset embedding-001 umap-001 cluster-001 default "My scope" "description"