Silhouette Score Calculator
Paste your data points and cluster labels to get the silhouette score, the per-cluster means, and the full a(i)/b(i)/s(i) working for every point, with misassigned points flagged. Matches scikit-learn silhouette_score. No signup, nothing uploaded.
How it works
The silhouette score measures how well each point fits its assigned cluster compared with the nearest neighbouring cluster. It needs no ground-truth labels, which makes it an internal validity index, the standard way to judge a k-means, hierarchical, or DBSCAN result, and to compare different choices of k. It was introduced by Peter Rousseeuw in 1987 and is what scikit-learn returns from silhouette_score.
For a point i in cluster C, the tool computes three quantities:
- a(i), cohesion. The mean distance from i to every other point in its own cluster:
a(i) = (1 / (|C| − 1)) · Σ d(i, j)over j in C, j ≠ i. Lower is better, the point is close to its cluster-mates. - b(i), separation. For every other cluster C′, take the mean distance from i to all of its points, then keep the smallest:
b(i) = min over C′ of (1 / |C′|) · Σ d(i, j). That nearest rival cluster is the one the point would most plausibly belong to instead. - s(i), the silhouette.
s(i) = (b(i) − a(i)) / max(a(i), b(i)), which falls between −1 and 1. Near 1 means the point is far from other clusters and snug in its own; near 0 means it sits on a boundary; negative means it is closer to a neighbour and probably misassigned. A point alone in its cluster getss(i) = 0by convention.
The overall score is the plain average of s(i) across all N points. Distance d(·,·) is Euclidean √(Σ (xₖ − yₖ)²) by default, matching scikit-learn, or Manhattan Σ |xₖ − yₖ| when selected. The computation is O(N²) in the number of points, which stays instant in the browser for the few-thousand-point inputs this tool accepts. As a credibility check it also recomputes the score a second way, as the size-weighted average of the per-cluster mean silhouettes, and confirms the two routes agree.
Reading the score: the four bands
The number itself is only half the answer. The bands below are the ones Kaufman and Rousseeuw published in Finding Groups in Data (1990) and the ones this tool labels your result with:
- Above 0.70, strong structure. Clusters are dense and clearly separated. The labelling holds up.
- 0.51 to 0.70, reasonable structure. A sensible clustering; the clusters are fairly well separated but not textbook-clean.
- 0.26 to 0.50, weak, possibly artificial. Some structure, but the clusters are not well separated. Treat the grouping as a hypothesis.
- 0.25 or below, no substantial structure. The clusters overlap so much that the labels carry almost no information.
- Below 0, likely misassigned. The average point is nearer a neighbouring cluster than its own. Something is wrong with k, the metric, or the feature scaling.
The boundaries are continuous, so a value sitting exactly on one is resolved downwards: 0.70 reads as reasonable (only above 0.70 is strong) and 0.50 reads as weak (only 0.51 and up is reasonable). That matters more than it sounds, a great many published scores land in the 0.45–0.55 window, where the honest reading is “there is structure here, but do not build a decision on this k alone.”
Using the score to pick the number of clusters
Because silhouette needs no ground-truth labels, the usual workflow is to cluster the same data at k = 2, 3, 4, … , score each labelling, and keep the k with the highest score. Paste one labelling at a time here and write the numbers down; the third worked example below does exactly that on six 1-D points, where k = 3 (0.8764) clearly beats k = 2 (0.7513).
Two caveats are worth knowing. First, silhouette prefers compact, roughly spherical clusters, which gives it a mild bias towards small k, merging two genuine groups into one big blob can still score respectably. Second, a single average hides a lopsided result, so read the per-cluster means as well: one cluster at 0.85 and another at 0.15 averages to a comfortable-looking 0.50 that describes neither. Confirming the same k with a second internal index is cheap insurance, the Davies-Bouldin index (lower is better) and the Calinski-Harabasz index (higher is better) both take the same points-and-labels input. If you do have true labels to compare against, silhouette is the wrong tool entirely, use the adjusted Rand index, which measures agreement between two labellings rather than geometry.
Choosing the distance metric
The metric decides what “close” means, so it changes the score. Euclidean distance is the default here and in scikit-learn, and it is the right pairing for k-means, which itself minimises squared Euclidean distance. Manhattan distance sums absolute coordinate differences instead, which is less dominated by a single large gap and is often preferred for high-dimensional or sparse feature vectors. Whichever you pick, scale your features first: a column measured in rupees and a column measured as a 0–1 ratio are not comparable, and the rupee column will decide every distance on its own. Standardising each column to zero mean and unit variance before clustering is the usual fix, and it frequently moves the silhouette score more than the choice of metric does.
Edge cases, and where the score misleads
Four boundary cases are defined rather than left to float, and this tool follows scikit-learn on all of them. A point that is the only member of its cluster has no a(i) to compute, so it contributes s(i) = 0 by convention. A point whose nearest rival cluster is exactly as far away as its own cluster-mates has b(i) = a(i) and therefore s(i) = 0 exactly, genuinely on the fence, not an error. Duplicate coincident points can make max(a(i), b(i)) zero, which would divide by zero; that case also returns 0. And a labelling with fewer than two distinct clusters, or one where every cluster is a singleton, leaves the score undefined, the tool refuses the input with a message naming the problem instead of returning a silent NaN.
Two failure modes are not the formula's fault but are worth watching. A density-based result from DBSCAN or HDBSCAN can be entirely correct and still score badly, because crescent and ring-shaped clusters are not compact in the way silhouette rewards; a low score on non-convex shapes is evidence about the metric, not about your clustering. And DBSCAN's noise points, labelled −1, are not a cluster: leaving them in makes the tool treat the noise as a group and drags the score down, so drop those rows before pasting. Finally, the O(N²) pairwise pass means cost grows with the square of the sample count, past a few thousand points, estimating the score from a random subsample (scikit-learn's sample_size argument) is standard practice.
Worked examples
Every line below was computed by hand and then reconciled against this calculator and scikit-learn. All distances are Euclidean. Paste any of these into the tool above to see the same numbers in the per-sample table.
Frequently asked questions
Compare the same labellings with the Calinski-Harabasz Index Calculator →
Sources & references
- scikit-learn: sklearn.metrics.silhouette_score and silhouette_samples (the (b − a) / max(a, b) definition, the [-1, 1] range, and the single-point convention)
- Rousseeuw, P.J. (1987): Silhouettes: a graphical aid to the interpretation and validation of cluster analysis (the original a(i), b(i), s(i))
- Kaufman, L. & Rousseeuw, P.J. (1990): Finding Groups in Data (the strong / reasonable / weak / none interpretation bands)
The formulas on this page were last cross-checked against these sources on 2026-06-11. The silhouette score is a stable mathematical definition, so this tool needs no rate or schedule updates, only the worked examples are periodically re-reconciled against scikit-learn.
Related tools
Comments & feedback
Spotted a bug or want an improvement? Tell us, our team reviews every comment, and good ideas get built. Comments are public and anonymous.
Found a bug, edge case, or want to suggest an improvement?
Email me at [email protected] , most fixes ship within 24 hours.