Inertia always falls as k rises, so it cannot pick one. The silhouette can, and the two often disagree.
Overview
Why inertia cannot answer the question
Inertia is the sum of squared distances from each point to the centroid of its cluster. K-means cuts it right. So It's the obvious thing to look at.
It's also useless on its own, and the reason is structural: inertia falls at each grow in k, always. With k equal to the number of points, each point is its own centroid and inertia is just zero. Watch the left chart as the spread control moves — the curve descends monotonically no matter what the data looks like.
So "choose the k with the lowest inertia" always answers "as many as possible". The metric measures how tightly points sit around their centres, not whether the grouping is any good.
Choosing k: Elbow and Silhouette
This module needs JavaScript: the
numbers are computed in the page rather than recorded.
Worth knowing
Inertia is the total squared distance from each point to its centroid. It falls at every k and reaches zero at k = n.
The elbow is where the fall stops being steep. It is judged by eye, and frequently there is no clear bend.
The silhouette compares each point's distance to its own cluster against the nearest other one. It has a genuine maximum.
Neither is a substitute for knowing what the clusters are for. k is often decided by the application, not the data.
Choosing k: Elbow and Silhouette
Two ways of picking the number of clusters, what each really measures, and why they disagree.
The elbow
The elbow method looks for the k where the curve stops falling steeply — where extra clusters stop buying much. On well-separated blobs there's a genuine bend at the true number. Up to that point each new cluster splits a real group, and after it each new cluster splits a group that was already coherent.
The problems are hands-on. The bend is judged by eye and different people pick different points. Very often, on real data, there simply is no bend — the curve is smooth, and reading an elbow into it's wishful. Raise the spread control until the blobs share and the bend disappears in front of you.
There's a formalisation, the kneedle method. This Finds the point of max curvature. It's better than eyeballing, and it still assumes a knee exists.
The silhouette
The silhouette measures a thing different: not tightness, but gap scaled to tightness.
For each point, let *a* be its mean distance to the other members of its own cluster, and *b* its mean distance to the members of the nearest other cluster. The silhouette is:
s = (b - a) / max(a, b)
Near +1 the point is much closer to its own cluster than to any other. Near 0 it sits on a boundary. Minus means it's closer to a different cluster than to its own — it's probably misassigned.
Blending over all points gives one number per k, and unlike inertia it doesn't improve automatically as k grows. Adding clusters eventually forces points close to a neighbouring cluster. This Drives *b* down and the score with it. So the silhouette has a real max, and that max is a defensible choice.
The right-hand chart shows this. The peak is at the true number of blobs, and it is a peak rather than a slope.
The cost is work: it needs pairwise distances, so O(n²), against inertia's O(n).
When they disagree
They often do, and the disagreement is helpful rather than a problem to resolve.
Inertia asks *are the clusters tight*. The silhouette asks *are they separated*. A dataset can have tight clusters that sit right next to each other, and the two metrics will point in different directions.
Switch the data to Two crescents and watch both. The silhouette doesn't recover the two crescents either. Because it's still built on distances to cluster members, and k-means hasn't made the crescents in the first place. That is the honest limit of both metrics: they test the clustering you gave them, and can't tell you the method was wrong.
The answer that is usually right
Neither metric knows what the clusters are for.
If you're segmenting customers so a marketing team can write one message per segment, k is roughly how many messages they can write. If you're compressing colours, k is the palette size you can afford. If clusters feed a downstream model, the number that makes that model best is the number.
Both metrics are worth finding, and the use often decides.
The silhouette of one point
Where inertia only ever falls as k grows. Reaching zero when each point is its own cluster — the silhouette has a real max, because it measures gap against tightness rather than tightness alone. For one point, let a be its mean distance to its own cluster and b its mean distance to the nearest other cluster. s = (b - a) / max(a, b):
a (own)
b (nearest other)
silhouette
reading
1.0
3.0
0.67
comfortably inside its cluster
2.5
3.0
0.17
near the boundary
3.0
1.0
−0.67
closer to another cluster — misassigned
Blending s over all points gives one number per k, and unlike inertia it doesn't improve automatically: add too many clusters and points are forced close to a neighbouring cluster, which drives b down and the score with it, so the curve peaks at a defensible k rather than sliding forever toward "more". The cost is O(n²) pairwise distances against inertia's O(n). Both still test only the clustering they were handed, though — on two interleaved crescents that k-means never separated, the silhouette can't recover them either. This Is the honest shared limit: these scores judge a split, they don't know the method was the wrong one.
The honest last word is that neither metric knows what the clusters are *for*. If you're segmenting customers so a team can write one message per segment, k is roughly how many messages they can write. If you're quantising colours, k is the palette you can afford. If the clusters feed a downstream model, the k that makes that model best is the answer. The elbow and the silhouette are both worth finding — the elbow reads tightness, the silhouette reads gap, and their disagreement is helpful rather than a problem to resolve — but the use often decides, and a formalisation like the kneedle method only helps once you've accepted that a knee exists at all.
Where it goes wrong with Choosing k
Choosing k by inertia alone. It will always say "more".
Seeing an elbow in a smooth curve. Check whether the bend lives a change of scale on the axis.
Trusting a silhouette on non-spherical clusters. It's distance-based and inherits the same assumption k-means makes.
Losing to scale. Both metrics are distances.
Questions people ask about Choosing k
Is the elbow method reliable? Only when the curve has a clear bend, which real data often lacks. When the inertia curve falls smoothly, treat the elbow as a hint and confirm with silhouette scores.
Can inertia pick k on its own? No. Inertia always drops as k grows and reaches zero when every point is its own cluster, so its minimum is a useless answer.
What is a good silhouette score? Above about 0.5 suggests clear structure, 0.25 to 0.5 means weak structure, and below that the clusters are barely separated. Compare scores across k on the same data rather than against a fixed bar.
What if the elbow and the silhouette disagree? Look at the clusters at both values of k and ask which one is useful for the job. Disagreement usually means the structure is ambiguous, so the downstream purpose should break the tie.
Should k be the number of classes I already know? If you know the true classes and want to recover them, start there. If the goal is finding structure, let the metrics and the use case decide, since natural groups often differ from labels.
Does k-means need k even if I only want a rough grouping? Yes, k is a required input. If you do not want to choose it, try hierarchical clustering or DBSCAN, which do not fix k up front.
Four ways to pick k, on data where you know the answer
The same four pick scores run twice: once on clean, well-separated blobs where they all agree. Once on shared ones where they don't. The disagreement is the handy part.
example_01.pyscikit-learn
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import (silhouette_score, calinski_harabasz_score,
davies_bouldin_score)
from sklearn.mixture import GaussianMixture
TRUE_K = 5
KS = range(2, 11)
def survey(X, label):
rows = []
for k in KS:
km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(X)
gm = GaussianMixture(n_components=k, random_state=0).fit(X)
rows.append((k, km.inertia_, silhouette_score(X, km.labels_),
calinski_harabasz_score(X, km.labels_),
davies_bouldin_score(X, km.labels_), gm.bic(X)))
print(label)
print("%4s %12s %11s %12s %11s %12s"
% ("k", "inertia", "silhouette", "calinski", "davies", "GMM BIC"))
for r in rows:
print("%4d %12.1f %11.4f %12.1f %11.4f %12.1f" % r)
picks = {
"silhouette": max(rows, key=lambda r: r[2])[0],
"calinski": max(rows, key=lambda r: r[3])[0],
"davies": min(rows, key=lambda r: r[4])[0],
"GMM BIC": min(rows, key=lambda r: r[5])[0],
}
print(" picks: " + ", ".join("%s k=%d" % (n, v) for n, v in picks.items()))
print(" the truth is k=%d. agreed: %d of 4."
% (TRUE_K, sum(v == TRUE_K for v in picks.values())))
print()
clean, _ = make_blobs(n_samples=900, centers=TRUE_K, cluster_std=0.55,
random_state=0)
survey(clean, "WELL SEPARATED blobs (cluster_std 0.55)")
messy, _ = make_blobs(n_samples=900, centers=TRUE_K, cluster_std=1.6,
random_state=0)
survey(messy, "OVERLAPPING blobs (cluster_std 1.6), same 5 centres")
print("when the structure is obvious the scores agree and you did not need")
print("them. when it is not, they disagree -- and that disagreement is")
print("information: there is no single k that is clearly right.")
Output
The next block shows why inertia alone cannot pick k and what happens on pure noise.
example_02.pyscikit-learn
import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_score
TRUE_K = 5
KS = range(2, 11)
clean, _ = make_blobs(n_samples=900, centers=TRUE_K, cluster_std=0.55,
random_state=0)
rows = []
for k in KS:
km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(clean)
rows.append((k, km.inertia_, silhouette_score(clean, km.labels_)))
print("why inertia is not on the picks list -- it falls no matter what:")
print("%6s %14s %14s" % ("k", "inertia", "drop"))
for i, r in enumerate(rows):
d = "%14.1f" % (rows[i - 1][1] - r[1]) if i else "%14s" % "-"
print("%6d %14.1f %s" % (r[0], r[1], d))
print(" at k = n every point is its own cluster and inertia is exactly 0.")
print(" the elbow method asks where the DROPS stop being dramatic, by eye.")
print()
print("the check nobody runs -- on data with no clusters at all:")
Xr = np.random.default_rng(0).uniform(size=(900, 2))
scores = {k: silhouette_score(Xr, KMeans(n_clusters=k, n_init=10,
random_state=0).fit(Xr).labels_)
for k in KS}
bk = max(scores, key=scores.get)
best_clean = max(r[2] for r in rows)
print(" 900 uniform random points: best silhouette is k=%d at %.4f"
% (bk, scores[bk]))
print(" the clean blobs scored %.4f. every method returns an answer" % best_clean)
print(" whether or not there is anything there. the SIZE of the score")
print(" is what tells you it was worth asking.")
print()
print("so: run several, check they agree, check the winner is meaningfully")
print("better than what noise scores -- and if you have a downstream task,")
print("score k on that instead. it is the only measure that certainly matters.")
Output
Check yourself
0 of 3
Answer without scrolling back up.
Why can inertia alone never choose k?
Minimising it always answers 'as many clusters as possible'. It measures tightness around centres, not whether the grouping is good.
What does a negative silhouette score for a point mean?
s = (b - a) / max(a, b), so s goes negative when the mean distance to the nearest other cluster is smaller than the mean distance within its own.
Why does the silhouette have a genuine maximum while inertia does not?
It measures separation relative to tightness. Splitting a coherent group hurts the separation term, so the score falls rather than improving automatically.
Cheat sheet
Choosing k: Elbow and Silhouette
Run the Elbow method and the Silhouette score on the same dataset. See what each one measures, where they disagree, and how to pick k when they do.
Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.