Benchmarking
soft_clustering.benchmarking is a unified framework for evaluating soft
clustering algorithms on equal terms — runtime, memory, scalability, and
clustering quality — across the heterogeneous fit interfaces used by the
estimators in this library.
The suite is part of the installed package, so it is available immediately
after pip install soft-clustering. Running a benchmark additionally requires
pandas, psutil and scikit-learn:
pip install "soft-clustering[bench]"
These are deliberately kept out of the core requirements: they are needed to
run a benchmark, never to fit a model. soft_clustering.benchmarking imports
them defensively, so the module remains importable without them and raises a
directed error only when you reach a feature that needs one.
Quick start
from soft_clustering import FCM, GK, PCM
from soft_clustering.benchmarking import (
BenchmarkAdapter,
BenchmarkReport,
ClusteringBenchmark,
ClusteringQualityBenchmark,
RuntimeBenchmark,
get_dataset,
)
X, y = get_dataset("iris")
models = [
BenchmarkAdapter(FCM(random_state=0), n_clusters=3, name="FCM"),
BenchmarkAdapter(GK(random_state=0), n_clusters=3, name="GK"),
BenchmarkAdapter(PCM(random_state=0), n_clusters=3, name="PCM"),
]
results = ClusteringBenchmark(
models=models,
benchmarks=[RuntimeBenchmark(n_repeats=3), ClusteringQualityBenchmark()],
).run(X, y)
report = BenchmarkReport(results)
print(report.leaderboard("ari"))
report.to_csv("results.csv")
BenchmarkAdapter
Every estimator in this library inherits from BaseSoftClusterer, which already
reconciles the differing fit signatures and publishes canonical fitted
attributes (memberships_, labels_, centers_, n_clusters). SCPP
estimators can therefore be benchmarked directly, with no wrapper:
ClusteringBenchmark(
models=[FCM(n_clusters=3, random_state=0), KFCM(n_clusters=3)],
benchmarks=[RuntimeBenchmark()],
).run(X, y)
BenchmarkAdapter remains useful for two things.
Labelling a model. Four estimators are exported under an alias — FCM is
the class FuzzyCMeans, GK is GustafsonKessel, GMM is
GaussianMixtureEM, and PCM is PossibilisticCMeans. Reports label a model
by its class name, so pass name= when you want the public API name in the
results table:
BenchmarkAdapter(FCM(n_clusters=3, random_state=0), name="FCM")
Wrapping a model that is not an SCPP estimator, such as a scikit-learn
clusterer. For those the adapter inspects the fit signature, calls whichever of
fit_predict(X, K), fit_predict(X) or fit(X) applies, transposes a
membership matrix stored as (n_clusters, n_samples), densifies a sparse one,
and searches the attribute names the protocol knows about. Pass n_clusters=
if the foreign model requires K positionally.
Note
The attribute names searched are BaseSoftClusterer._membership_attrs and
._centers_attrs — the benchmarking code reads that registry rather than
keeping its own copy. An estimator that stores its memberships under a new name
should add it there, and every benchmark picks it up.
Benchmark backends
Backend |
Reports |
|---|---|
|
|
|
|
|
|
|
silhouette, Calinski-Harabasz, Davies-Bouldin; ARI and NMI when |
Write your own by subclassing BaseBenchmark and implementing
evaluate(model, X, y) to return a dictionary of metrics.
Datasets
get_dataset(name) returns (X, y) for any registered dataset. Three groups
are available — real (bundled with scikit-learn), synthetic (generated
locally), and openml (downloaded on first use):
from soft_clustering.benchmarking import (
available_datasets,
benchmark_suite,
dataset_info,
get_dataset,
)
available_datasets() # every registered name
dataset_info("iris") # {'name': 'iris', 'n_samples': 150, ...}
benchmark_suite("synthetic") # {name: (X, y)} for a whole group
Metrics
The validity indices are usable on their own, independently of the benchmark runner:
from soft_clustering.benchmarking import clustering_metrics, soft_clustering_metrics
soft_clustering_metrics(X, U, centers=centers)
# partition_coefficient, modified_partition_coefficient, partition_entropy,
# fuzzy_hypervolume, xie_beni, fuzzy_compactness, fuzzy_separation
clustering_metrics(X, labels, y_true=y)
# silhouette, calinski_harabasz, davies_bouldin, ari, nmi