A faster algorithm to compute the Silhouette width under Manhattan distance
Project description
Fast Manhattan Silhouette
Fast exact silhouette evaluation under Manhattan distance.
Figure 1: Runtime comparison between a generic pairwise-distance baseline and Manhattan-specific implementations on synthetic benchmark instances.
Overview
Evaluating clustering quality is a common task in cluster analysis. The silhouette width compares, for each data point, the average distance to points in its own cluster with the average distance to points in the nearest other cluster. The mean over all samples is often called the Average Silhouette Width (ASW).
Generic silhouette implementations usually work from pairwise distances. This is simple and metric-independent, but it becomes expensive for large datasets because the full distance matrix has quadratic size.
manhattan-silhouette computes exact silhouette values for fixed cluster labels
under Manhattan (L1) distance without materializing the full n × n distance
matrix. It uses the additive structure of the Manhattan distance to make repeated scoring and large synthetic benchmarks
practical.
The package answers the question:
Given data points and cluster labels, how can we compute the silhouette widths under Manhattan distance in subquadratic time?
| Standard Silhouette | Fast Manhattan Silhouette |
|---|---|
| - Compute pairwise distances | - Uses sorted one-dimensional sweeps |
| - Time: $\mathcal{O}(n^{2}d)$ | - Time: $\mathcal{O}(nd(\log n+k))$ |
| - Memory: $\mathcal{O}(n^{2})$ | - Memory: $\mathcal{O}(nk)$ or $\mathcal{O}(nd)$ |
Installation
pip install manhattan-silhouette
For development from source:
git clone git@github.com:anomatomato/manhattan-silhouette.git
cd manhattan-silhouette
uv sync --all-extras --all-groups
Examples
The public API mirrors the two common silhouette use cases:
silhouette_samples_manhattan(...)returns one silhouette value per sample.silhouette_score_manhattan(...)returns the mean silhouette score.
Quickstart
import numpy as np
from manhattan_silhouette import (
silhouette_samples_manhattan,
silhouette_score_manhattan,
)
X = np.array(
[
[0.0, 0.0],
[0.2, 0.1],
[3.0, 3.1],
[3.3, 3.0],
],
dtype=np.float64,
)
labels = np.array([0, 0, 1, 1], dtype=np.intp)
samples = silhouette_samples_manhattan(X, labels)
score = silhouette_score_manhattan(X, labels)
print(samples)
print(score)
API
silhouette_samples_manhattan(
X,
labels,
check_1d_disjoint=False,
compute_by_cluster=True,
)
Returns an array of shape (n_samples,) with one silhouette value per sample.
silhouette_score_manhattan(
X,
labels,
check_1d_disjoint=False,
compute_by_cluster=True,
)
Returns the mean silhouette value as a float.
Parameters:
X: array-like of shape(n_samples, n_features)labels: array-like of shape(n_samples,)check_1d_disjoint: ifTrue, use a specialized kernel for one-dimensional data when cluster intervals are disjointcompute_by_cluster: choose the cluster-oriented implementation (True, default) or the axis-oriented implementation (False)
Experimental Results
We benchmarked the implementation on synthetic Gaussian-blob and uniform instances. The benchmark compares:
fast_by_cluster_score: the default cluster-oriented implementationfast_by_axis_score: an axis-oriented implementationsklearn_manhattan: a generic scikit-learn Manhattan silhouette baseline
On million-point instances with five clusters, the cluster-oriented implementation was several thousand times faster than the sklearn baseline:
| Dimensions | Standard baseline (s) | fast_by_cluster_score (s) |
Speedup |
|---|---|---|---|
| 1 | 2322.3 | 0.161 | 14,467× |
| 2 | 2281.6 | 0.274 | 8,318× |
| 3 | 2572.1 | 0.406 | 6,341× |
More plots and the scripts that generated them are available in
evaluation/runtime_manhattan_silhouette/.
Development
Install development dependencies:
uv sync --all-groups
Run tests:
uv run pytest
Build the source distribution and wheel:
uv build
Check package metadata before uploading:
uvx twine check dist/*
Contribution
Contributions are welcome. Useful contributions include:
- bug reports with small reproducible examples
- comparisons against trusted silhouette implementations
- documentation improvements
- performance investigations on additional datasets
Before opening a pull request, please run the test suite with uv run pytest.
References
[1] Rousseeuw, P. J. (1987). Silhouettes: A graphical aid to the interpretation and validation of cluster analysis. Journal of Computational and Applied Mathematics, 20, 53–65. https://doi.org/10.1016/0377-0427(87)90125-7
[2] Chen, Y., Debnath, T., Cai, A., & Song, M. (2023). Circular Silhouette and a Fast Algorithm. IEEE Transactions on Pattern Analysis and Machine Intelligence, 45(11), 14038–14044. https://doi.org/10.1109/TPAMI.2023.3310495
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file manhattan_silhouette-0.1.1.tar.gz.
File metadata
- Download URL: manhattan_silhouette-0.1.1.tar.gz
- Upload date:
- Size: 11.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de30db4d92459ba1372da00c681aff34194a6813e799bfbf9b54a547daa1b776
|
|
| MD5 |
d6a138ec97cf491fa56b9b7400b37406
|
|
| BLAKE2b-256 |
47d210cd5767af2eb4492468b9ca769945c31c5e5625f664ed395576a90323ef
|
Provenance
The following attestation bundles were made for manhattan_silhouette-0.1.1.tar.gz:
Publisher:
release.yml on anomatomato/manhattan-silhouette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
manhattan_silhouette-0.1.1.tar.gz -
Subject digest:
de30db4d92459ba1372da00c681aff34194a6813e799bfbf9b54a547daa1b776 - Sigstore transparency entry: 1997607313
- Sigstore integration time:
-
Permalink:
anomatomato/manhattan-silhouette@efd5aac3ec8a51c23eeaa64548aff0b5596fa43b -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/anomatomato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@efd5aac3ec8a51c23eeaa64548aff0b5596fa43b -
Trigger Event:
push
-
Statement type:
File details
Details for the file manhattan_silhouette-0.1.1-py3-none-any.whl.
File metadata
- Download URL: manhattan_silhouette-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b89cb7f163c76f27bd3a940b728e062863b34433cf80bb1e794e6f94858d2f0
|
|
| MD5 |
24a5f16989780e094ad47275ddda5c61
|
|
| BLAKE2b-256 |
0e7014beec72e7a17d6f6c738edff9accf6a6b21f5633e9991ea86babed08d52
|
Provenance
The following attestation bundles were made for manhattan_silhouette-0.1.1-py3-none-any.whl:
Publisher:
release.yml on anomatomato/manhattan-silhouette
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
manhattan_silhouette-0.1.1-py3-none-any.whl -
Subject digest:
6b89cb7f163c76f27bd3a940b728e062863b34433cf80bb1e794e6f94858d2f0 - Sigstore transparency entry: 1997607382
- Sigstore integration time:
-
Permalink:
anomatomato/manhattan-silhouette@efd5aac3ec8a51c23eeaa64548aff0b5596fa43b -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/anomatomato
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@efd5aac3ec8a51c23eeaa64548aff0b5596fa43b -
Trigger Event:
push
-
Statement type: