Skip to main content

Fast Manhattan Silhouette

Fast exact silhouette evaluation under Manhattan distance.

Runtime comparison on million-point benchmark instances

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: if True, use a specialized kernel for one-dimensional data when cluster intervals are disjoint
  • compute_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 implementation
  • fast_by_axis_score: an axis-oriented implementation
  • sklearn_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

Metadata

Release files for manhattan-silhouette 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for manhattan-silhouette 0.1.1
File Size Uploaded
manhattan_silhouette-0.1.1.tar.gz 11.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for manhattan-silhouette 0.1.1
File Interpreter ABI Platform
manhattan_silhouette-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 25.7 kB

Release files / manhattan_silhouette-0.1.1.tar.gz

Download URL manhattan_silhouette-0.1.1.tar.gz
Size 11.4 kB
Tags Source
SHA-256 checksum
How to use checksums
de30db4d92459ba1372da00c681aff34194a6813e799bfbf9b54a547daa1b776
BLAKE2b-256 checksum
How to use checksums
47d210cd5767af2eb4492468b9ca769945c31c5e5625f664ed395576a90323ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 28, 2026.

Transparency log

Release files / manhattan_silhouette-0.1.1-py3-none-any.whl

Download URL manhattan_silhouette-0.1.1-py3-none-any.whl
Size 14.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6b89cb7f163c76f27bd3a940b728e062863b34433cf80bb1e794e6f94858d2f0
BLAKE2b-256 checksum
How to use checksums
0e7014beec72e7a17d6f6c738edff9accf6a6b21f5633e9991ea86babed08d52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page