Machine Learning·Lesson 26·14 min·0/3 exercises

Clustering

k-means always returns clusters — which is not evidence that clusters exist

KMeansinertiasilhouette_scoreDBSCANGaussianMixturecluster profiling

Watch it happen

Play it through, or step back and forth yourself.

supervised
X and y
predict the answer
unsupervised
X only
find structure
Without a target there's no test set, no accuracy, and no obvious way to be wrong. That freedom is the difficulty: unsupervised results are much easier to over-believe.

Everything so far had a y. Unsupervised learning has none — you are looking for structure rather than predicting a known answer, which also means there's no obvious way to tell whether you found any.

The idea

Everything so far had a y. Unsupervised learning has none — you're looking for structure rather than predicting a known answer. Which also means there's no test set, no accuracy, and no obvious way to be wrong. That freedom is the difficulty: unsupervised results are much easier to over-believe.

How k-means works

  1. Place k centres (k-means++ picks spread-out starting points).
  2. Assign each row to its nearest centre.
  3. Move each centre to the mean of its assigned rows.
  4. Repeat until nothing moves.
from sklearn.cluster import KMeans

X_scaled = preprocessing.fit_transform(X)
km = KMeans(n_clusters=3, n_init=10, random_state=0).fit(X_scaled)

km.labels_            # which cluster each row landed in
km.cluster_centers_   # where the centres ended up
km.inertia_           # total squared distance to centres

It converges to a local optimum that depends on where the centres started, which is why n_init=10 runs it ten times and keeps the best.

What it assumes

Quite a lot. "Nearest centre" carves space into straight-edged cells, so k-means can only produce convex, roughly round groups of similar size and density. Give it elongated clusters and it cuts them in half; give it nested rings and it cannot represent them at all.

  • DBSCAN finds arbitrary shapes and can label points as noise, which k-means never does.
  • GaussianMixture allows elongated clusters and gives soft memberships — probabilities rather than hard assignments.
  • AgglomerativeClustering builds a hierarchy you can cut at any level.

And since it's a distance method, scaling is mandatory — lesson 10 in full force. Unscaled, hour (range 15) would dominate distance_km (range 6) for no reason but units, and you'd be clustering by time of day without meaning to.

Choosing k

k    inertia    silhouette
2     6210.1       0.1330
3     5322.2       0.1743   ← peak
4     4941.9       0.1509
5     4677.7       0.1298
6     4461.9       0.1226

Inertia falls forever — at k = n every point is its own centre and inertia is zero — so you look for an "elbow", and elbows are in the eye of the beholder.

Silhouette is better: for each row it compares the distance to its own cluster against the nearest other cluster, giving −1 to 1. It has a genuine maximum, so it can actually choose.

And ours is weak

The peak is 0.174 at k=3. As a rough guide: above 0.5 means well-separated clusters, above 0.25 is worth a look, and 0.17 means the structure is faint at best.

So the honest reading is: k=3 is the best available answer, and there may not be much of a question. Saying that is more useful than presenting three clusters as a finding.

It always returns clusters

This is the thing to hold onto. Ask k-means for three clusters and you get three — on any data whatsoever, including pure noise. The algorithm has no way to tell you "there is no structure here".

Getting clusters is not evidence that clusters exist. That's what the silhouette score is for, and why the next step matters.

Validate against something you didn't cluster on

cluster   rows   late rate   avg minutes
      0    368       31.8%          27.6
      1    380        8.7%          22.5
      2    152       32.9%          28.0

Cluster 1 is 8.7% late against 31.8% and 32.9%. It has separated the easy deliveries from the hard ones without ever seeing the target.

That's the right way to validate clustering: profile the groups against a column you didn't cluster on. If they differ on something meaningful, the structure is probably real even when the silhouette is unimpressive.

What clustering is actually for

  • Describing your data — "we have three kinds of delivery" is a sentence people can act on.
  • Segmentation — customer groups, routes, regions, for humans to make decisions about.
  • Exploration before you have labels.
  • Anomaly detection — rows far from every centre.

Not for prediction. You have a target and a supervised model that reaches 0.879 AUC; the clustering reaches nothing, because that was never the job.

See it run

The lesson's code, ready to run and to fiddle with.

Putting the kettle on…

Starting up…

Worked example

not graded

Already written and ready to go — press Run to see what it does, then change a number, a column name, anything, and run it again.

tryclustering on pure noise — np.random.default_rng(0).normal(size=Xs.shape) — and checking the silhouette.

Press Run — the output appears here.

Your turn

3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.

Sweep k over [2, 3, 4, 5] and return the silhouette scores, rounded to 4 places. The peak tells you which k to pick.

your answer

Validate the clusters. Fit k=3, then return the late rate per cluster as a list rounded to 3 places, in cluster order.

your answer

Prove that k-means always returns clusters. Fit k=3 on pure random noise of the same shape and return [n_clusters_found, silhouette], score rounded to 3 places.

your answer