Clustering API
The clustering API is under active development. The objects documented here are
the intended public entry points exported by compresso.clustering.
Types
- class compresso.clustering.SparseVector(indices, values, size)[source]
Small sparse vector used as a reusable cluster handle.
- Parameters:
indices (ndarray)
values (ndarray)
size (int)
- class compresso.clustering.ScoredTag(tag_id, name, score, count=0.0, metadata=<factory>)[source]
- Parameters:
tag_id (int)
name (str)
score (float)
count (float)
metadata (Mapping[str, Any])
- class compresso.clustering.SparseCluster(cluster_id, centroid, entity_indices, source_cluster_ids=(), parent_cluster_ids=(), child_cluster_ids=(), tags=(), label=None, description=None, stats=<factory>, metadata=<factory>)[source]
- Parameters:
cluster_id (str)
centroid (SparseVector)
entity_indices (ndarray)
source_cluster_ids (tuple[str, ...])
parent_cluster_ids (tuple[str, ...])
child_cluster_ids (tuple[str, ...])
tags (tuple[ScoredTag, ...])
label (str | None)
description (str | None)
stats (Mapping[str, Any])
metadata (Mapping[str, Any])
- compresso.clustering.SparseClusterGraph
alias of
SparseClusterSet
- class compresso.clustering.SparseClusterSet(clusters, n_entities, n_features, active_cluster_ids=None, entity_ids=None, feature_ids=None, assignment_mode='dominant_signed', history=(), metadata=<factory>)[source]
- Parameters:
clusters (tuple[SparseCluster, ...])
n_entities (int)
n_features (int)
active_cluster_ids (tuple[str, ...] | None)
entity_ids (ndarray | None)
feature_ids (ndarray | None)
assignment_mode (str)
history (tuple[Mapping[str, Any], ...])
metadata (Mapping[str, Any])
- property entity_to_cluster_ids: dict[int, list[str]]
Map entity index to active cluster ids.
- fill_missing_cluster_labels(label_fn=None, text_fn=None, *, roots=None, active_roots_only=True, overwrite=False, verbose=False)[source]
Count or fill missing labels below selected graph roots.
When
label_fnis not provided this is a count-only traversal. Whenlabel_fnis provided, the method returns a new graph with filled labels and leaves the original graph unchanged.- Return type:
tuple[SparseClusterSet,int,int]- Parameters:
label_fn (Callable[[object], object] | None)
text_fn (Callable[[SparseCluster], object] | None)
roots (Iterable[str | SparseCluster] | None)
active_roots_only (bool)
overwrite (bool)
verbose (bool)
Pipeline
- class compresso.clustering.ClusteringPipeline(steps, verbose=False)[source]
Composable class-based sparse clustering pipeline.
A pipeline starts with one clustering step that consumes an
SRPTensor. Every later step consumes and returns aSparseClusterSet. This separates discovery from optional graph linking, merging, labeling, tagging, and filtering.- Parameters:
steps (
Sequence[Callable[[SRPTensor],SparseClusterSet] |Callable[[SparseClusterSet],SparseClusterSet]]) – Sequence of class-based steps. The first must be anAbstractClustering; later steps are usuallyAbstractClusterTransforminstances.verbose (
bool) – Print one-line progress for each pipeline step.
Examples
>>> graph = ClusteringPipeline([ ... TopMSignedClustering(top_m=3, min_cluster_size=5), ... EntityContainmentLink(threshold=1.0), ... MaterializeLinkMerges(), ... SizeFilter(min_cluster_size=10), ... ]).fit(srp)
- class compresso.clustering.AbstractClusterTransform[source]
Base class for pipeline steps that transform an existing cluster graph.
Transform steps consume and return a
SparseClusterSet. They are used after a clustering step for linking, merging, labeling, tagging, or filtering clusters.
- class compresso.clustering.AbstractClustering[source]
Base class for pipeline steps that build clusters from an
SRPTensor.Clustering steps are the first step in a
ClusteringPipeline. They consume sparse entity representations and return aSparseClusterSet.
Clustering Steps
- class compresso.clustering.DominantSignedClustering(min_cluster_size=1, show_progress=False)[source]
Cluster each entity by its single strongest signed feature.
This is the simplest activation clustering mode. For every SRP row, the feature with largest absolute activation is selected, including its sign. Entities with the same
(feature, sign)key form one cluster.- Parameters:
min_cluster_size (
int) – Drop clusters with fewer entities than this value during construction.show_progress (
bool) – Show a tqdm progress bar while assigning rows.
- class compresso.clustering.TopMSignedClustering(top_m=1, min_cluster_size=1, show_progress=False)[source]
Cluster each entity by each of its top-m signed features.
Every entity may belong to multiple clusters: one for each of its strongest
top_msigned feature activations. Withtop_m=1this is equivalent toDominantSignedClustering.- Parameters:
top_m (
int) – Number of strongest features per entity to use.min_cluster_size (
int) – Drop clusters with fewer entities than this value.show_progress (
bool) – Show tqdm progress while building clusters.
- class compresso.clustering.ComboSignedClustering(top_m=1, combo_size=1, min_cluster_size=1, show_progress=False)[source]
Cluster entities by exact combinations of signed features.
For each entity, take its top
top_msigned features and create exact AND-combination keys of lengthcombo_size. Two entities share a cluster only when they contain the same signed feature combination.- Parameters:
top_m (
int) – Candidate feature pool size for each entity.combo_size (
int) – Size of exact signed-feature combinations.min_cluster_size (
int) – Drop clusters with fewer entities than this value.show_progress (
bool) – Show tqdm progress while building clusters.
- class compresso.clustering.FeaturePathClustering(top_m=1, max_depth=None, min_cluster_size=None, min_activation=None, show_progress=False)[source]
Build a hierarchy by recursively splitting on next strongest features.
At the root level each entity starts from one of its top
top_msigned features. Inside each cluster, entities are split again by the next strongest feature not already used in the path. This creates an explicit feature-path hierarchy such asfeature A -> feature B -> feature C.- Parameters:
top_m (
int) – Number of starting signed features per entity.max_depth (
int|None) – Maximum feature-path depth.Noneallows paths up to available sparse features.min_cluster_size (
int|None) – Stop or drop nodes smaller than this size.Nonedisables the size stop.min_activation (
float|None) – Ignore candidate features whose absolute activation is below this value.Nonedisables the threshold.show_progress (
bool) – Show tqdm progress while building paths.
- class compresso.clustering.SRPSimilarityClustering(threshold, top_k=100, min_cluster_size=2, normalize_rows=True, min_local_density=None, centroid_top_k=None, batch_size=1024, show_progress=False)[source]
Build clusters as connected components in SRP similarity space.
The SRP rows are compared by dense similarity, edges with similarity above
thresholdare kept, and connected components become clusters. This is useful when the cluster should be defined by representation similarity rather than by a shared feature id.- Parameters:
threshold (
float) – Minimum pairwise similarity for an edge.top_k (
int|None) – Limit each row to its top-k nearest neighbors before thresholding.Nonecompares against all rows.min_cluster_size (
int) – Drop connected components smaller than this size.normalize_rows (
bool) – IfTrue, L2-normalize rows before similarity computation.min_local_density (
float|None) – Optional fraction of within-component neighbors an entity must keep to remain in a component.centroid_top_k (
int|None) – If provided, keep only this many largest centroid features.batch_size (
int) – Number of rows scored per matrix multiplication batch.show_progress (
bool) – Show tqdm progress while scoring batches.
Linking and Merging
- class compresso.clustering.EntityContainmentLink(threshold=1.0, child_scope='leaves', parent_scope='all', require_parent_larger=True, skip_existing_ancestors=True, verbose=False, show_progress=False)[source]
Add parent-child links based on entity containment without merging nodes.
This is a graph-linking step, not a merge step. It preserves the active frontier and only adds DAG edges from contained child clusters to broader parent clusters. A child may receive multiple parents.
- Parameters:
threshold (
float) – Minimum entity containment score in[0, 1].child_scope (
Literal['active','all','leaves','roots']) – Which clusters may become children:"active","all","leaves", or"roots".parent_scope (
Literal['active','all','leaves','roots']) – Which clusters may become parents.require_parent_larger (
bool) – Require the parent candidate to contain more entities than the child.skip_existing_ancestors (
bool) – Avoid adding links that are already implied by existing ancestry.verbose (
bool) – Print linking progress.show_progress (
bool) – Show tqdm progress while scanning child clusters.
- class compresso.clustering.FeatureContainmentLink(threshold=1.0, signed=True, child_scope='leaves', parent_scope='all', require_parent_larger=True, skip_existing_ancestors=True, verbose=False, show_progress=False)[source]
Add parent-child links based on feature-support containment.
This is the feature analogue of
EntityContainmentLink. It creates graph edges without creating merge nodes or changing the active frontier.- Parameters:
threshold (
float) – Minimum feature-containment score in[0, 1].signed (
bool) – Compare signed(feature, sign)pairs instead of feature ids only.child_scope (
Literal['active','all','leaves','roots']) – Which clusters may become children.parent_scope (
Literal['active','all','leaves','roots']) – Which clusters may become parents.require_parent_larger (
bool) – Require the parent candidate to have a larger feature support.skip_existing_ancestors (
bool) – Avoid adding links already implied by existing ancestry.verbose (
bool) – Print linking progress.show_progress (
bool) – Show tqdm progress while scanning child clusters.
- class compresso.clustering.MaterializeLinkMerges(parent_scope='active', include_descendants=False, min_children=1, normalize_centroids=True, activate=True, verbose=False)[source]
Convert existing links into explicit merge-parent nodes.
Link steps create edges only. This transform adds a new non-destructive parent node for linked structures so that downstream renderers and recommendation code can treat the linked group as a concrete cluster.
- Parameters:
parent_scope (
Literal['active','all','leaves','roots']) – Which linked parent clusters should be materialized.include_descendants (
bool) – IfTrue, include all descendants of a linked parent, not just its direct children.min_children (
int) – Minimum number of linked children required to create a materialized node.normalize_centroids (
bool) – L2-normalize materialized parent centroids.activate (
bool) – IfTrue, add materialized nodes to the active frontier.verbose (
bool) – Print materialization details.
- class compresso.clustering.EntityIoUMerge(threshold, max_rounds=10, normalize_centroids=True, verbose=False, show_progress=False)[source]
Merge active clusters whose entity sets have high intersection-over-union.
Active clusters are treated as nodes in a similarity graph. Pairs with entity IoU greater than or equal to
thresholdare connected, connected components are materialized as new parent clusters, and the process repeats until convergence ormax_rounds.- Parameters:
threshold (
float) – Minimum entity IoU in[0, 1].max_rounds (
int) – Maximum iterative merge rounds.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge progress.show_progress (
bool) – Show tqdm progress while comparing clusters.
- class compresso.clustering.EntityContainmentMerge(threshold=1.0, max_rounds=10, normalize_centroids=True, verbose=False, show_progress=False)[source]
Merge active clusters when one entity set is mostly contained in another.
Containment is
|A intersection B| / min(|A|, |B|). A strict subset has score1.0even when IoU is small. This is useful for collapsing small highly-specific clusters into broader parents.- Parameters:
threshold (
float) – Minimum containment score in[0, 1].max_rounds (
int) – Maximum iterative merge rounds.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge progress.show_progress (
bool) – Show tqdm progress while comparing clusters.
- class compresso.clustering.FeatureContainmentMerge(threshold=1.0, signed=True, max_rounds=10, normalize_centroids=True, verbose=False, show_progress=False)[source]
Merge active clusters when feature supports are mostly contained.
Feature containment is
|F_A intersection F_B| / min(|F_A|, |F_B|). Withsigned=True, positive and negative use of the same feature are treated as different support elements.- Parameters:
threshold (
float) – Minimum feature-containment score in[0, 1].signed (
bool) – Compare signed(feature, sign)pairs instead of feature ids only.max_rounds (
int) – Maximum iterative merge rounds.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge progress.show_progress (
bool) – Show tqdm progress while comparing clusters.
- class compresso.clustering.CentroidSimilarityMerge(threshold, metric='cosine', top_k=None, max_rounds=10, min_group_size=2, normalize_centroids=True, verbose=False, show_progress=False)[source]
Merge active clusters whose sparse centroids are similar.
This creates non-destructive parent nodes from connected components in a centroid-similarity graph. It is useful after initial clustering when different feature handles point to nearby regions in sparse space.
- Parameters:
threshold (
float) – Minimum centroid similarity. For cosine this must be in[-1, 1].metric (
Literal['cosine','dot']) – Similarity function:"cosine"or raw"dot"product.top_k (
int|None) – Optional nearest-neighbor restriction. A pair is considered only when one cluster is in the other’s top-k neighbors.max_rounds (
int) – Maximum iterative merge rounds.min_group_size (
int) – Minimum connected component size to materialize.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge progress.show_progress (
bool) – Show tqdm progress while comparing centroids.
- class compresso.clustering.LabelDuplicateMerge(cluster_scope='active', case_sensitive=False, mark_children_hidden=True, min_group_size=2, normalize_centroids=True, verbose=False)[source]
Merge clusters that have exactly the same label string.
This is useful after LLM or rule-based labeling, where duplicate labels can indicate duplicate semantic segments. When
mark_children_hidden=True, merged children are preserved but marked as hidden for later compaction or UI rendering.- Parameters:
cluster_scope (
Literal['active','all','leaves','roots']) – Which clusters are considered for duplicate-label grouping.case_sensitive (
bool) – IfFalse, normalize labels by case before grouping.mark_children_hidden (
bool) – Mark duplicate children with metadata keyrender_hidden.min_group_size (
int) – Minimum number of clusters with the same label required to merge.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge summary.
- class compresso.clustering.SemanticSimilarityMerge(embed_fn, threshold=0.9, text_fn=None, label_fn=None, label_text_fn=None, cluster_scope='active', max_rounds=10, min_group_size=2, normalize_embeddings=True, normalize_centroids=True, verbose=False, show_progress=False)[source]
Merge clusters whose labels/descriptions are semantically similar.
The user supplies
embed_fnso Compresso does not depend on a specific embedding model or API key. Candidate cluster texts are embedded, similar clusters are grouped with a maximal-clique strategy, and new non-destructive semantic parent nodes are created. Optional callbacks can label those new parent nodes.- Parameters:
embed_fn (
Callable[[list[str]],ndarray]) – Function mapping a list of cluster texts to a 2D NumPy embedding array.threshold (
float) – Minimum cosine similarity between cluster text embeddings.text_fn (
Callable[[SparseCluster],str] |None) – Function mapping a cluster to text. Defaults to cluster description, then label, then empty text.label_fn (
Callable[[object],object] |None) – Optional user function that names a newly created semantic parent.label_text_fn (
Callable[[SparseCluster,list[SparseCluster]],object] |None) – Optional function that builds the input object passed tolabel_fnfrom the parent cluster and its children.cluster_scope (
Literal['active','all','leaves','roots']) – Which clusters should be considered for semantic merging.max_rounds (
int) – Maximum iterative semantic merge rounds.min_group_size (
int) – Minimum similar group size to materialize.normalize_embeddings (
bool) – L2-normalize text embeddings before similarity.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge progress.show_progress (
bool) – Show tqdm progress while processing rounds.
- class compresso.clustering.TagSimilarityMerge(threshold, metric='weighted_jaccard', max_rounds=10, normalize_centroids=True, verbose=False, show_progress=False)[source]
Merge active clusters with similar assigned tag profiles.
Run
AssignTagsbefore this step. Tags are compared either by weighted Jaccard over tag scores or by cosine similarity of tag-score vectors. Matching groups are materialized as non-destructive parents.- Parameters:
threshold (
float) – Minimum tag-profile similarity in[0, 1].metric (
Literal['weighted_jaccard','cosine']) – Tag similarity metric:"weighted_jaccard"or"cosine".max_rounds (
int) – Maximum iterative merge rounds.normalize_centroids (
bool) – L2-normalize newly created parent centroids.verbose (
bool) – Print merge progress.show_progress (
bool) – Show tqdm progress while comparing clusters.
Post-processing
- class compresso.clustering.CompactHiddenClusters(hidden_key='render_hidden', verbose=False)[source]
Remove hidden clusters and rewire visible graph edges.
Hidden nodes are usually produced by
LabelDuplicateMergewithmark_children_hidden=True. This transform physically removes them from the graph while preserving visible ancestor/descendant connectivity.- Parameters:
hidden_key (
str) – Metadata key used to decide whether a cluster should be removed.verbose (
bool) – Print compaction summary.
- class compresso.clustering.PruneRedundantRoots(verbose=False)[source]
Remove active clusters that are descendants of another active cluster.
This is usually used after link/materialization steps to make the active frontier easier to render. It does not delete nodes; it only updates
active_cluster_ids.- Parameters:
verbose (
bool) – Print pruning summary.
- class compresso.clustering.AssignTags(entity_tag_matrix, tag_names, method='tfidf', top_k=5, min_score=0.0)[source]
Assign top tags to clusters from an entity-tag matrix.
The tag matrix is expected to be shaped
(n_entities, n_tags)and can be a dense or sparse matrix-like object accepted by the implementation. Tags are aggregated over each cluster’s entity indices and stored asScoredTagobjects.- Parameters:
entity_tag_matrix (
object) – Matrix containing entity-tag counts or weights.tag_names (
Sequence[str]) – Names corresponding to columns ofentity_tag_matrix.method (
Literal['tfidf','counts']) – Scoring method:"tfidf"downweights globally common tags, while"counts"uses raw aggregate counts.top_k (
int) – Maximum number of tags stored per cluster.min_score (
float) – Drop tags whose score is not greater than this threshold.
- class compresso.clustering.LabelClusters(entity_metadata, text_extractor, label_fn, cluster_scope='active', overwrite=False, verbose=False, show_progress=False)[source]
Populate cluster labels/descriptions with user-provided callbacks.
Compresso coordinates the loop but does not own prompting, API keys, or model initialization.
text_extractorconverts a cluster plus metadata into a domain-specific input object, andlabel_fnconverts that object into a label result. The result may be a string,(label, description), or a mapping understood by the implementation.- Parameters:
entity_metadata (
object) – Metadata table or object used bytext_extractor.text_extractor (
Callable[[SparseCluster,object],object]) – Callable(cluster, entity_metadata) -> object.label_fn (
Callable[[object],object]) – Callable that returns a label/description for one extracted text object.cluster_scope (
Literal['active','all','leaves','roots']) – Which clusters should be labeled.overwrite (
bool) – IfFalse, skip clusters that already have a label.verbose (
bool) – Print labeling progress.show_progress (
bool) – Show tqdm progress while labeling clusters.
- class compresso.clustering.AssignUnclusteredToNearestCluster(srp, metric='cosine', min_similarity=None, top_k_clusters=1, cluster_scope='active', coverage_scope='active', assigned_weight=1.0, centroid_top_m=None, centroid_top_k=None, normalize_centroids=True, verbose=False)[source]
Expand coverage by assigning uncovered entities to nearest clusters.
This step does not create singleton clusters. Instead, for each cluster that receives newly assigned entities, it creates an expanded parent node with the original cluster as a child. This preserves the discovered core cluster while adding coverage for entities outside the current frontier.
- Parameters:
srp (
SRPTensor) – Original entity representations used for nearest-cluster assignment.metric (
Literal['cosine','dot']) – Similarity between entity rows and cluster centroids:"cosine"or"dot".min_similarity (
float|None) – Optional minimum similarity required for assignment.top_k_clusters (
int) – Number of nearest clusters to assign each uncovered entity to.cluster_scope (
Literal['active','all','leaves','roots']) – Which clusters can receive assignments.coverage_scope (
Literal['active','all']) – Which clusters count as already covering an entity:"active"or"all".assigned_weight (
float) – Weight of newly assigned entity vectors when recomputing expanded centroids.centroid_top_m (
int|None) – Keep only this many largest centroid features in expanded parents.centroid_top_k (
int|None) – Deprecated alias forcentroid_top_m.normalize_centroids (
bool) – L2-normalize expanded parent centroids.verbose (
bool) – Print assignment summary.
- class compresso.clustering.SizeFilter(min_cluster_size)[source]
Keep only active clusters with at least
min_cluster_sizeentities.This changes the active frontier only; filtered-out clusters remain in the graph and can still be inspected through
clusters.clusters.- Parameters:
min_cluster_size (
int) – Minimum entity count required for an active cluster to stay active.
Persistence and Helpers
- compresso.clustering.save_cluster_graph(graph, path)[source]
- Return type:
Path- Parameters:
graph (SparseClusterSet)
path (str | Path)
- compresso.clustering.graph_to_dict(graph)[source]
- Return type:
dict[str,Any]- Parameters:
graph (SparseClusterSet)
- compresso.clustering.graph_from_dict(data)[source]
- Return type:
- Parameters:
data (Mapping[str, Any])
- compresso.clustering.cluster_srp(srp, *, mode='dominant_signed', top_m=1, combo_size=1, min_cluster_size=1, post_merge_min_cluster_size=None, entity_ids=None, activation_iou_threshold=None, entity_tag_matrix=None, tag_names=None, tag_method='tfidf', top_k_tags=5, tag_similarity_threshold=None, tag_similarity_metric='weighted_jaccard', max_merge_rounds=10, verbose=False, show_progress=False)[source]
Convenience pipeline for sparse clustering.
Semantic labeling/merging is intentionally not part of v1; callers can add it later as callbacks operating on the returned SparseClusterSet.
- Return type:
- Parameters:
srp (SRPTensor)
mode (Literal['dominant_signed', 'top_m_signed', 'combo_signed'])
top_m (int)
combo_size (int)
min_cluster_size (int)
post_merge_min_cluster_size (int | None)
entity_ids (ndarray | None)
activation_iou_threshold (float | None)
tag_names (Sequence[str] | None)
tag_method (Literal['tfidf', 'counts'])
top_k_tags (int)
tag_similarity_threshold (float | None)
tag_similarity_metric (Literal['weighted_jaccard', 'cosine'])
max_merge_rounds (int)
verbose (bool)
show_progress (bool)
- compresso.clustering.run_clustering_pipeline(srp, steps, *, verbose=False)[source]
Run an explicit sparse clustering pipeline.
The first step consumes an
SRPTensorand must return aSparseClusterSet. Every following step consumes and returns aSparseClusterSet. This keeps base cluster construction separate from optional merge/tag/filter phases while staying easy to compose withfunctools.partialor small lambdas.- Return type:
- Parameters:
srp (SRPTensor)
steps (Sequence[Callable[[SRPTensor], SparseClusterSet] | Callable[[SparseClusterSet], SparseClusterSet]])
verbose (bool)