Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

k-means: clustering, implemented from scratch

Heinrich Heine University Düsseldorf

Where this fits: classification, regression, clustering

Every procedure in this part of the book starts from a table: rows are instances, columns are features. The first question is always whether one column is singled out as the label: the quantity we want to predict, and one that is known for the rows we already have (the ground truth).

  • If there is a label, we speak of supervised learning: we learn the relationship between the remaining columns and the label in order to predict it for new rows. If the label is on a nominal scale (species, colour, yes/no), the task is called classification; if it is continuous (price, temperature), it is called regression. Formally, classification is a special case of regression; in practice it needs one extra idea to turn real-valued predictions into classes (the keyword is logistic regression, the central model of the course Introduction to Deep Learning).

  • If there is no label, we speak of unsupervised learning. Clustering invents the label: it divides the rows into groups, and the group number is a new column that was not there before. Such an invented, unobserved column is called a latent variable. The unsupervised counterpart of regression is feature engineering, that is, computing new columns from old ones (the principal components in the chapter Dimensionality reduction, for instance). The most general unsupervised goal is to learn the distribution of the data itself; such a generative model can then produce new rows (the chapter Expectation Maximization).

The most important practical difference is the assessment: in supervised learning you know the label and can hold back some of the rows and count the predictions on them (train-test split, the chapter Model selection). In unsupervised learning there is nothing to count; whether a clustering is “good” is a matter of plausibility, or of a summary measure chosen after the fact.

TaskLabelExample in this bookChapter
Classificationnominal, knownpredicting the iris species from four leaf measurements (example below); recognising items of clothing on Fashion-MNISTModel selection, Kernel methods
Regressioncontinuous, knownpredicting the price of a house in Melbourne from its location and sizeRegression analysis
Clusteringnone, it is inventeddividing iris instances into three groups without their speciesthis chapter, Expectation Maximization

A one-line classifier that also builds the bridge to regression: for the iris data, the rule “petal length under 2.5 cm, then setosa, otherwise not” predicts the species setosa without a single error. That is a threshold on one feature; logistic regression learns exactly such thresholds, but from several features at once.

Let us check this with the confusion matrix from the chapter Titanic EDA:

Confusion matrix [[tn, fp], [fn, tp]] =
[[100   0]
 [  0  50]]
Accuracy = 1.0

Not a single mix-up, accuracy 1; the rule “women survive” on the Titanic only reached 0.79. The iris data are a textbook example, after all.

We begin with clustering, because k-means is the simplest procedure that shows all the building blocks of machine learning: a model with parameters, an optimisation objective and an iterative algorithm.

k-means is an unsupervised learning procedure for dividing a dataset into kk clusters. Depending on the shape of the data, k-means may already be enough for a classification or a predictor, or it may be the starting point for more complicated algorithms. Here kk is the number of clusters, and it has to be fixed in advance. There are heuristics for finding the ‘optimal’ kk; one of them is to start at k=2k=2 and look at plots of the clusters until you are satisfied.

First we go through the idea in pseudocode, taking the petal length and petal width columns of the iris data as the example, that is, in Rd\mathbb{R}^d with d=2d=2:

  1. We fix a kk, the number of clusters. In the iris example: 3

  2. We fix kk distinct points c1,…,ck∈Rdc_1,\dots,c_k \in \mathbb{R}^d, the ‘centroids’. These can be restricted to points of the dataset, chosen simply by drawing uniformly at random.

  3. For every other point x∈Rdx \in \mathbb{R}^d we compute which centroid cic_i is nearest and assign xx to group ii.

  4. Then we update the ii-th centroid to the mean of all points in group ii. If nothing (or little enough) changes in the process, we are done.

One k-means iteration

[[4.5 1.5]
 [1.3 0.2]
 [6.1 1.9]]
<Figure size 600x600 with 1 Axes>
<Figure size 600x600 with 1 Axes>

You can also watch at leisure how the algorithm clusters the points step by step:

Loading...

What we see here is that we can run the procedure a second time, with the new centroids as the starting centroids, and get a better clustering. If the clusters (and hence the centroids) stop changing under repeated runs, we speak of convergence. Using the full dataset (not just 2 columns) of course gives better clusters. What we want now is a method that performs one k-means pass on an arbitrary dataset with given initial centroids. While we are at it, we can replace the previous implementation by a vectorised one:

A vectorised k-means implementation

<Figure size 1000x1000 with 1 Axes>
<Figure size 1000x1000 with 1 Axes>

A converging k-means implementation

iteration step  1
iteration step  2
iteration step  3
iteration step  4
iteration step  5
iteration step  6
<Figure size 1000x1000 with 1 Axes>

Which k is the right one?

<Figure size 640x480 with 1 Axes>

Robust k-means and the elbow plot

<Figure size 640x480 with 1 Axes>

An example with different data

<Figure size 700x700 with 1 Axes>
<Figure size 700x700 with 1 Axes>

kmeans++

To counteract the problem of bad initial centroids, you can use the kmeans++ algorithm:

  1. Choose a first centroid uniformly at random among all the data points

  2. For every point xx, compute D(x)D(x), the distance to the nearest centroid

  3. Choose the next centroid from a weighted distribution that picks each xx with weight proportional to D(x)2D(x)^2.

  4. Repeat steps 2–3 until kk centroids have been found.

  5. Ordinary k-means up to convergence

<Figure size 700x700 with 1 Axes>

Trivia

A few more things worth knowing about k-means:

  • The average time complexity is in O(k∗n∗T)O(k*n*T), with nn the sample size and TT the number of iterations.

  • The worst-case complexity is in O(n(k+2/d))O(n^{(k+2/d)}), where dd is the number of variables (the dimension). Arthur, Vassilvitskii: “How slow is the k-means method?”, 2006

  • What happens in theory? What gets minimised is the so-called inertia, the sum of the squared distances of all points from their nearest centroids, J(c1,…,ck)=∑imin⁡j∥xi−cj∥2J(c_1,\dots,c_k) = \sum_i \min_j \lVert x_i - c_j \rVert^2. That also points at the biggest problem: when the clusters are not convex and homogeneous, this is a less sensible thing to optimise. The curse of dimensionality bites here too: in high-dimensional spaces distances behave unintuitively – points drawn uniformly from a ball, for example, lie near the boundary more often than near the middle. One more reason to learn about principal component analysis.

  • The bisecting k-means variant: First 2-means, then one of the largest clusters is split with 2-means, and so on, until there are k clusters altogether.

  • The mini-batch k-means variant: A compromise between our first variant (the one with the animation) and the last one. It has great advantages for online data processing (streaming) and for large amounts of data in general.

  • For k-means procedures to succeed, the data need to fall into clusters of roughly ellipsoidal shape with similar variance. Examples where it can go wrong are plotted in the scikit-learn documentation.

  • The elbow criterion is not a sensible one. Details and alternatives have been discussed in the literature for years Schubert (2023).

k-means in scikit-learn

There is of course no need to reinvent the wheel: scikit-learn comes with k-means implementations of its own:

[[6.85384615 3.07692308 5.71538462 2.05384615]
 [5.006      3.428      1.462      0.246     ]
 [5.88360656 2.74098361 4.38852459 1.43442623]]
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 0 2 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 2 0 0 0 0 2 0 0 0 0
 0 0 2 2 0 0 0 0 2 0 2 0 2 0 0 2 2 0 0 0 0 0 2 0 0 0 0 2 0 0 0 2 0 0 0 2 0
 0 2]
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]
NMI = I(P;C) / mean(H(P), H(C)) between prediction P and class C: 0.7419116631817836

Where k-means reaches its limits

The assignment step assigns every point to the nearest centroid. That decomposes the whole plane (in general, the whole feature space) into kk regions, the Voronoi cells of the centroids: the boundary between two cells is the perpendicular bisector of the line segment joining the two centroids, hence a straight line (in higher dimensions, a hyperplane). Every cell is an intersection of half-planes and therefore convex. So what k-means finds is always a decomposition into convex pieces with straight boundaries – whatever the data look like.

The typical weaknesses that give k-means away all follow from this:

  • Non-convex clusters. Two rings lying one inside the other, two half-moons, two spirals: every straight line cuts through both, so no choice of centroids can separate them. We saw this above with the rings; the chapter Kernel methods shows the way out: map the data first, so that the clusters become convex.

  • Very different cluster sizes. A large cluster draws centroids towards itself and gets split up, while small clusters are merged into one – the inertia is counted in points, not in clusters.

  • Very different extent (variance). The boundary lies halfway between the centroids, not where the broad cluster ends: the narrow cluster steals the outer points of the broad one.

  • Outliers. A single far-away point shifts a centroid (the mean is not robust), or, with an unlucky initialisation, even gets a centroid of its own.

  • Features on different scales. The Euclidean distance adds up squares; with one feature in metres and one in millimetres, the second is weighted a thousand times more strongly. Scale first; see Dimensionality reduction.

  • Overlapping clusters. Where the distributions run into one another there is no sensible hard boundary; a Gaussian mixture model with soft assignments (Expectation-Maximization) is then the better fit.

Add to that what we already know: kk has to be chosen in advance, and the result depends on the initialisation. The three blobs below – one large and broad, two small and narrow – show the size problem in a single picture:

<Figure size 1300x550 with 2 Axes>

The boundaries are straight lines, the cells convex – and k-means invests two of its three centroids in the large cluster and merges the two small ones into one. That is not a failure of the procedure; it is precisely the decomposition with the smallest inertia: halving 600 points saves more squared distance than separating 210. If your data look like this, you need a procedure that also models the shape and the size of the clusters: a Gaussian mixture model, with its own covariance matrix and its own weight for each component, would have no trouble here.

References
  1. Schubert, E. (2023). Stop using the elbow criterion for k-means and how to choose the number of clusters instead. ACM SIGKDD Explorations Newsletter, 25(1), 36–42. 10.1145/3606274.3606278