Grouping data with no labels at all - and the three assumptions it makes that decide whether the groups mean anything.
Overview
The algorithm
Choose k. Place k centres. Assign every point to its nearest centre, move each centre to the mean of the points assigned to it, and repeat until nothing moves.
That is the whole thing, and it converges quickly. inertia_ is what it minimises: the total squared distance from each point to its centre.
The interface is the familiar one with a piece missing. fit(X) takes no y, because there is none. labels_ holds the group number for each training row, cluster_centers_ holds the centres, and predict assigns new points to the nearest existing centre.
The labels are arbitrary. Cluster 0 in one run may be cluster 2 in the next, with the same grouping. Comparing two clusterings therefore needs a metric that ignores the numbering, which is what adjusted_rand_score is for.
Worth knowing
Unsupervised: fit(X) with no y. The output is a group number per row, and the numbering is arbitrary.
You must choose n_clusters - the algorithm cannot discover how many groups there are.
inertia_ falls monotonically with k, so look for the bend; silhouette_score has an actual maximum.
It measures distance, so it must have scaled features - unscaled, it clusters whichever column has the largest units.
It assumes clusters are round, similar in size and similar in density; DBSCAN handles shapes it cannot.
The result depends on the random start, which is why n_init repeats it and keeps the best.
k-Means Clustering: A Practical Guide
Every model so far was told the answers. This one is given features and asked to find structure - which is a genuinely different job, and one whose results are much harder to check.
Fitting without a target
No y anywhere - the estimator is given features and asked to find groups.
example_01.pyscikit-learn
Output
Inertia cannot choose k for you
It falls forever, so its minimum is always the largest k you tried.
example_02.pyscikit-learn
Output
Silhouette does have a maximum
Which makes it the more useful of the two for choosing k.
example_03.pyscikit-learn
Output
Without scaling it clusters the units
One noise column measured in a larger unit, and the grouping it finds is worthless.
example_04.pyscikit-learn
Output
It only finds round, similar-sized groups
Two interleaving crescents are the shape it cannot see.
example_05.pyscikit-learn
Output
The starting point matters
Eight random starts, and they do not all land in the same place.
example_06.pyscikit-learn
Output
Choosing k is your problem
The algorithm cannot tell you how many groups exist. It will happily split one blob into five or merge five into two.
inertia_ looks like it should help and cannot, because it falls monotonically: more centres always means points are closer to a centre, and at k = n it is zero. The second editor shows the curve dropping from 4219 to 469 with no minimum in sight. The elbow is the heuristic — the point where the improvement flattens — and on this data the drops are 2213, 831, 472, 89, 78, 67, which bends after 4.
silhouette_score is the better tool because it has a genuine maximum. For each point it compares the distance to its own cluster against the distance to the nearest other cluster, and averages. Values run from -1 to 1, and higher means better-separated groups. The third editor peaks at k=4, which is the number of blobs the data was generated with.
Neither is authoritative. Both are heuristics on an ill-posed question, and the honest answer usually comes from outside: how many segments the business can act on, how many categories the taxonomy allows, what the groups turn out to mean when you look at them.
Scale it, or cluster the units
k-means is entirely distance-based, so an unscaled feature with large units decides everything.
The fourth editor makes this stark. One column carries a real grouping; the other is pure noise measured in a unit 500 times larger. Unscaled, the agreement with the true grouping is -0.0032 — chance. Scaled, it is 0.9867.
The clustering was not merely worse; it was entirely determined by a column containing nothing. This is the same argument the scaling module made for k-NN, and it applies with more force here because there is no label to notice the problem with. A supervised model that clusters on noise scores badly and tells you. An unsupervised one produces groups, and the groups look like a result.
StandardScaler in a pipeline before KMeans should be automatic.
What it assumes
Three assumptions, all baked into "assign each point to the nearest centre".
Clusters are round. The boundary between two centres is a straight line, so every cluster is a convex region. The fifth editor puts this against two interleaving crescents: k-means scores 0.27 and DBSCAN scores 1.00. No amount of tuning fixes it, because the shape is outside what the algorithm can express.
Clusters are similar in size. k-means tends to split a large cluster and merge small ones, because that reduces total squared distance.
Clusters have similar density. A tight group and a diffuse one confuse the distance comparison.
When these hold, k-means is fast, simple and hard to beat. When they do not, the alternatives are DBSCAN for arbitrary shapes and outliers, GaussianMixture for elliptical clusters of different sizes with soft assignments, and AgglomerativeClustering when a hierarchy is more useful than a flat partition.
The random start
The centres are initialised randomly, and the algorithm converges to a local minimum — so different starts give different answers.
The last editor runs eight single-start fits with random initialisation and gets inertias from 1034.9 to 1188.6. Three of the eight found the good solution and five did not.
n_init runs the whole thing several times and keeps the lowest inertia, which is why the default is 10 rather than 1. init="k-means++", also the default, spreads the initial centres out rather than placing them at random, which makes good solutions much more likely and is the reason the default configuration mostly avoids this.
Both defaults are sensible and both are worth knowing about, because a clustering that changes between runs is usually one of these two being overridden.
What the groups mean
Nothing, until you look.
k-means returns a partition whether or not there is structure to find — ask for four clusters in uniform noise and you get four. So the first question after fitting is always whether the groups are real, and the second is what distinguishes them.
The practical checks are comparing the silhouette against what random data of the same shape scores, looking at the cluster centres in the original units to see what characterises each group, and checking the sizes for a cluster containing three rows.
The step that gives clustering its value is naming the groups — describing each in terms someone can act on. A partition with no interpretation is a column of integers, and the algorithm cannot supply the interpretation.
Judging a clustering when there are no labels
Supervised models are checked against the truth. Clustering has none, so the metrics split into two families and it is worth knowing which you are allowed to use.
Internal measures use only the data and the labels the algorithm produced. silhouette_score compares within-cluster distance against nearest-other-cluster distance. calinski_harabasz_score and davies_bouldin_score are alternatives with different biases. All three reward compact, well-separated groups — which means they systematically favour exactly the round, equal-sized clusters that k-means produces, and would score a correct DBSCAN clustering of two crescents poorly. They measure the shape you asked for, not whether the grouping is meaningful.
External measures compare against known labels. adjusted_rand_score and normalized_mutual_info_score both ignore the arbitrary numbering, which is what makes them usable at all. Adjusted Rand is adjusted for chance, so 0.0 is what random labelling scores and negative values are worse than random — which is how the unscaled run above landed at -0.0032.
These are for the situation this track has been using throughout: generated data where the truth is known, or a subset somebody has labelled. In genuine unsupervised work there is nothing to compare against, and the honest evaluation is whether the groups turn out to be useful.
Where clustering earns its place
Three uses, of which only one is what people usually mean by clustering.
Segmentation. Finding groups of customers, documents or sessions that behave alike, so that each can be treated differently. This is the familiar use, and it is the one where the interpretation matters more than the algorithm: a partition nobody can name is not actionable.
Compression and feature construction. The cluster label becomes a categorical feature for a supervised model, or the distances to each centre become numeric ones. This often helps, and it is subject to the usual rule — the clustering must be fitted inside the folds, or the labels carry information from the test rows.
Finding what is not in any group. Points far from every centre are unusual, which makes clustering a crude anomaly detector. DBSCAN does this explicitly by labelling outliers -1 rather than forcing them into a cluster, which is one of its real advantages over k-means.
The use to be careful with is treating clusters as though they were discovered categories. The algorithm partitions whatever it is given; whether the partition corresponds to anything real is a separate question that the output cannot answer.
Can I use k-means on categorical data? Not sensibly - the mean of one-hot columns is not a category. KModes outside scikit-learn, or a distance-based method with a categorical metric.
What about many rows?MiniBatchKMeans fits on small random batches and is dramatically faster on large data, at a small cost in quality.
Why does my clustering change between runs? Either n_init=1 or no random_state. The defaults handle the first; set the second for reproducibility.
Should the clustering go in a pipeline? Yes, if its output feeds a supervised model - otherwise the cluster labels are learned from the test rows too.
Reading the clusters once you have them
Fitting takes one line; understanding the result takes rather more, and skipping it is how clustering projects end with a column of integers nobody uses.
Look at the centres in the original units.cluster_centers_ is in whatever space the model was fitted in, which after scaling is standard deviations rather than pounds or minutes. scaler.inverse_transform(km.cluster_centers_) puts them back, and reading the result column by column is what turns cluster 2 into "high spend, low frequency, recent".
Check the sizes.np.bincount(km.labels_) in one line. A cluster with four members is usually not a segment; it is an outlier group that k-means was forced to place somewhere because you asked for that many centres.
Compare each cluster against the overall average. Which features are most different from the global mean is a faster route to a description than reading the raw centres, especially with many columns.
Check stability. Refit on a random 80% and see whether the same groups appear. Clusters that dissolve when a fifth of the data changes are artefacts of the partition rather than structure in the data, and this test costs one loop.
The output of that work is a name and a description per group. That is the deliverable; the labels are an intermediate.
Is there a way to have k chosen automatically? Not by k-means. DBSCAN and HDBSCAN determine the number of groups from the density instead, which is a genuine advantage when you have no prior view.
Does predict() work on new data? Yes - it assigns each new point to the nearest existing centre without refitting, which is what makes a clustering usable as a feature in production.
Why is my silhouette score low even though the clusters look right? Silhouette rewards compact, well-separated, roughly spherical groups. A correct clustering of elongated or touching groups scores poorly on it, which is a limitation of the metric rather than of the clustering.
Does k-means work in high dimensions? Less well. Distances between points become more similar as dimensions grow, so "nearest centre" carries less information. Reducing dimensions first - with PCA, say - is common practice and usually helps.
Can two clusters end up empty? With random initialisation, yes; scikit-learn relocates empty clusters rather than leaving them, which is one more thing k-means++ makes unlikely.
Things to try
Watch inertia fail. The second editor's numbers fall forever. Compute the differences and find the bend yourself.
Break it with scale. The fourth editor's unscaled run scores below chance. Change 500 to 5 and see where the crossover is.
Try the wrong shape. In the fifth editor, raise noise to 0.15 and see whether DBSCAN still manages.
Cluster noise. Fit k=4 on np.random.rand(300, 2) and look at the silhouette. It will not be zero.
Where this leaves you
Scale first, choose k with silhouette rather than inertia, keep n_init at its default, and check that the groups mean something before reporting them. When the clusters are not round, the algorithm is the wrong one rather than badly tuned.
Check yourself
0 of 4
Answer without scrolling back up.
Why can inertia_ not be used to choose k?
Its minimum is always the largest k you tried. The elbow is a heuristic on the curve; silhouette has an actual maximum.
What happens if you run k-means on unscaled features?
In the editor, a pure-noise column with a 500x larger unit took the agreement with the true grouping to -0.0032, which is chance.
Why does k-means fail on two interleaving crescents?
Assigning each point to the nearest centre gives straight boundaries. DBSCAN scored 1.00 where k-means scored 0.27.
What does n_init do?
k-means converges to a local minimum, and eight single starts in the editor ranged from 1034.9 to 1188.6.
Cheat sheet
k-Means Clustering
Every model so far was told the answers. This one is given features and asked to find structure - which is a genuinely different job, and one whose results are much harder to check.
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.