Skip to main content

A faster algorithm to compute the Silhouette width under Manhattan distance

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

manhattan_silhouette-0.1.1.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

manhattan_silhouette-0.1.1-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

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

Hashes for manhattan_silhouette-0.1.1.tar.gz
Algorithm Hash digest
SHA256 de30db4d92459ba1372da00c681aff34194a6813e799bfbf9b54a547daa1b776
MD5 d6a138ec97cf491fa56b9b7400b37406
BLAKE2b-256 47d210cd5767af2eb4492468b9ca769945c31c5e5625f664ed395576a90323ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for manhattan_silhouette-0.1.1.tar.gz:

Publisher: release.yml on anomatomato/manhattan-silhouette

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file manhattan_silhouette-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for manhattan_silhouette-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6b89cb7f163c76f27bd3a940b728e062863b34433cf80bb1e794e6f94858d2f0
MD5 24a5f16989780e094ad47275ddda5c61
BLAKE2b-256 0e7014beec72e7a17d6f6c738edff9accf6a6b21f5633e9991ea86babed08d52

See more details on using hashes here.

Provenance

The following attestation bundles were made for manhattan_silhouette-0.1.1-py3-none-any.whl:

Publisher: release.yml on anomatomato/manhattan-silhouette

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page