Signature
R_K = 1 - W_K / W_1
| Inputs | Definition | Unit |
|---|---|---|
W_K | Sum over units of the squared Euclidean distance to the mean of their own cluster, W(K) in the article | squared units of the clustering variables |
W_1 | Sum of squared distances of all units from the overall mean, W(1); above zero | squared units of the clustering variables |
R_K | Proportion of the one-cluster sum of squares removed by the K-cluster solution | proportion |
|---|
Function
Grouping patients or other units by dissimilarity in cluster analysis
Maps the clustering variables measured on each unit, such as a patient's counts of emergency and outpatient care, to a set of groups found in the data without an outcome variable. Combinatorial methods such as k-means assign each unit to one group by minimising the dissimilarity within groups; mixture models such as latent class analysis give each unit a probability of belonging to each class. The notation follows the Cluster Analysis article, whose six-patient example is used throughout.
Computational function
Computational function: k-means clustering with within-cluster sum of squares and silhouettes
Runs k-means (Lloyd's algorithm) from given starting centroids on any number of units and clustering variables, and returns each unit's cluster, the cluster means, W(K), the share of scatter removed (HE-FM-CLU-003) and each unit's silhouette (HE-FM-CLU-005). The inputs differ from the formula's: a data matrix and starting centroids instead of two sums of squares.
Inputs and outputs:
X: Data matrix with one row per unit and one column per clustering variable, already scaled; required. Unit: as measured.;starts: Matrix of K starting centroids, one per row; required. Unit: as measured.;cluster: Cluster of each unit. Unit: label.;centres: Final cluster means. Unit: as measured.;W_K: Within-cluster sum of squares. Unit: squared units.;R_K: Share of the one-cluster sum of squares removed. Unit: proportion.;sil: Silhouette of each unit from Euclidean distances, set to 0 for a unit alone in its cluster. Unit: none.;sil_mean: Mean silhouette. Unit: none.Assumption: Quantitative variables scaled as intended before clustering, squared Euclidean distance for assignment and a fixed K; the result depends on the starts, so in practice several starts are run and the lowest W(K) kept.
Worked example (Six patients, two clusters, article example): Starting from P3 (2, 0) and P4 (5, 4), the algorithm puts P1 to P3 in one cluster and P4 to P6 in the other after one update, with means (1, 1) and (5, 5), W(2) of 8, a share removed of 0.8571 and silhouettes from 0.6188 to 0.7163, mean 0.6573.
X = [[0, 1], [1, 2], [2, 0], [5, 4], [6, 6], [4, 5]]; starts = [[2, 0], [5, 4]]; cluster = [1, 1, 1, 2, 2, 2]; W_K = 8; R_K = 0.8571; sil_mean = 0.6573Worked example (Three clusters from two different starts): From P3, P4 and P5 the algorithm reaches the best split, with P5 alone, W(3) of 5 and a share of 0.9107; from P1, P2 and P4 it stops at W(3) of 6.5, a share of 0.8839, a local minimum (computed here for illustration).
starts = [[2, 0], [5, 4], [6, 6]]; W_K = 5; starts = [[0, 1], [1, 2], [5, 4]]; W_K = 6.5Excel: For two clusters with centre cells CentreA and CentreB (each a row of the variables) and a unit's row Profile,
=IF(SUMXMY2(Profile,CentreA)<=SUMXMY2(Profile,CentreB),"A","B")assigns the unit; each centre is then recomputed with AVERAGEIF over the assignment column, and the two steps are repeated until no assignment changes.R:
kmeans_lloyd <- function(X, starts, iter = 100) { X <- as.matrix(X); C <- as.matrix(starts); K <- nrow(C); for (it in 1:iter) { D <- sapply(1:K, function(k) colSums((t(X)-C[k, ])^2)); cl <- max.col(-D, ties.method = "first"); C1 <- t(sapply(1:K, function(k) colMeans(X[cl == k, , drop = FALSE]))); if (all(abs(C1-C) < 1e-12)) break; C <- C1 }; W_K <- sum((X-C[cl, ])^2); W_1 <- sum((t(X)-colMeans(X))^2); E <- as.matrix(dist(X)); sil <- sapply(1:nrow(X), function(i) { own <- setdiff(which(cl == cl[i]), i); if (!length(own)) return(0); a <- mean(E[i, own]); b <- min(sapply(setdiff(unique(cl), cl[i]), function(k) mean(E[i, cl == k]))); (b-a)/max(a, b) }); list(cluster = cl, centres = C, W_K = W_K, R_K = 1-W_K/W_1, sil = sil, sil_mean = mean(sil)) }Base R only;kmeans_lloyd(rbind(c(0,1), c(1,2), c(2,0), c(5,4), c(6,6), c(4,5)), rbind(c(2,0), c(5,4)))returns W_K = 8, R_K = 0.8571 and sil_mean = 0.6573. The base functionkmeans(X, centers = starts, algorithm = "Lloyd")gives the same clusters.Python:
def kmeans_lloyd(X, C, it=100): K = len(C); sq = lambda u, v: sum((a-b)**2 for a, b in zip(u, v)); cl = [min(range(K), key=lambda k: sq(x, C[k])) for x in X]; C1 = [[sum(x[j] for x, c in zip(X, cl) if c == k)/cl.count(k) for j in range(len(X[0]))] for k in range(K)]; m = [sum(col)/len(X) for col in zip(*X)]; own = lambda i: [j for j in range(len(X)) if cl[j] == cl[i] and j != i]; a = [sum(math.dist(X[i], X[j]) for j in own(i))/len(own(i)) if own(i) else 0 for i in range(len(X))]; b = [min(sum(math.dist(X[i], X[j]) for j in range(len(X)) if cl[j] == k)/cl.count(k) for k in set(cl) if k != cl[i]) for i in range(len(X))]; sil = [(bi-ai)/max(ai, bi) if own(i) else 0 for i, (ai, bi) in enumerate(zip(a, b))]; return kmeans_lloyd(X, C1, it-1) if C1 != C and it > 0 else {"cluster": cl, "centres": C, "W_K": sum(sq(x, C[c]) for x, c in zip(X, cl)), "R_K": 1-sum(sq(x, C[c]) for x, c in zip(X, cl))/sum(sq(x, m) for x in X), "sil": sil, "sil_mean": sum(sil)/len(X)}Needsimport math; returns the same values as the R function, with clusters numbered from 0 and X and the starts as lists of rows.Test (Converged means are the averages of their members): At convergence each centre equals the mean of the units assigned to it, (1, 1) and (5, 5) in the article example. Expected result: TRUE. Excel check, with the first variable's values in EdValues and assignments in ClusterLabels:
=ABS(AVERAGEIF(ClusterLabels,"A",EdValues)-INDEX(CentreA,1,1))<1E-9Test (Every unit nearer its own centre): At convergence no unit is nearer another cluster's mean; in the article example P2 is at squared distance 1 from A and 25 from B. Expected result: TRUE. Excel check for one unit:
=SUMXMY2(Profile,CentreA)<=SUMXMY2(Profile,CentreB)Common error (Running k-means once): A single run can stop at a local minimum, as the second start in the three-cluster example does (6.5 against 5); reported solutions should come from several starts.
Source: scikit-learn developers. Clustering. scikit-learn User Guide, section 2.3, version 1.9.1. Accessed 3 October 2026. Section 2.3.2 (inertia, local minima, several initialisations) and section 2.3.11.5 (silhouette coefficient); Hastie T, Tibshirani R, Friedman J. The Elements of Statistical Learning: Data Mining, Inference, and Prediction. 2nd ed. New York: Springer; 2009. Section 14.3.6, Algorithm 14.1 (k-means alternates assignment to the closest mean and recomputation of the means until assignments do not change).
C(i) = argmin_k ||x_i - m_k||^2; m_k = mean of x_i with C(i) = k; W_K = sum_i ||x_i - m_C(i)||^2; R_K = 1 - W_K / W_1; s_i = (b_i - a_i) / max(a_i, b_i)
Try this function
Implementations
Excel
Share of scatter removed from named sums of squares
With W_K in WithinSS and W_1 in TotalSS, the formula returns the share removed, held in ScatterRemoved. For two variables in ranges EdValues and OpValues, W_1 is =DEVSQ(EdValues)+DEVSQ(OpValues).
=1-WithinSS/TotalSS
Assumptions
Within-cluster sum of squares from the best of several k-means starts
K-means can stop at a local minimum that depends on the starting centroids, so W_K is taken from several starts or, for tiny data, an exhaustive search.
Same units, variables and scaling for every number of clusters
W_K and W_1 are computed on the same data and weights; changing variables or scaling between solutions makes the shares incomparable.
Worked examples
Two clusters of the six patients
With one cluster the mean is (3, 3) and W(1) is 56; the two clusters with means (1, 1) and (5, 5) give W(2) of 8, removing 48 of the 56 units of scatter, a share of about 0.8571 (86 per cent), as in the article.
W_K = 8; W_1 = 56; R_K = 0.8571
Best three-cluster split of the six patients
The best three-cluster splits give W(3) of 5, a share of about 0.9107; the further gain of 3 units, about 5 per cent of the total, is small, so the kink is at two clusters, as in the article.
W_K = 5; W_1 = 56; R_K = 0.9107
Three clusters stuck at a local minimum
Starting k-means for three clusters from P1, P2 and P4 converges to clusters {P1, P3}, {P2} and {P4, P5, P6} with W(3) of 6.5 and a share of about 0.8839, worse than the best split's 5 (computed here for illustration).
W_K = 6.5; W_1 = 56; R_K = 0.8839
Common errors
Choosing the number of clusters by minimising the within-cluster sum of squares
W(K) generally falls as clusters are added, even when evaluated on new data, and reaches 0 with one unit per cluster, so neither its minimum nor cross-validation picks K; analysts look for the kink or use a criterion such as the gap statistic.
Reading the share removed as cost or outcome variation explained
The 86 per cent refers to scatter in the clustering variables only; in the example it says nothing about how much variation in annual cost, which was kept out of the clustering, the clusters explain.
Sources
K-means minimises the inertia, or within-cluster sum of squares, and can stop at a local minimum
scikit-learn developers. Clustering. scikit-learn User Guide, section 2.3, version 1.9.1. Accessed 3 October 2026. Section 2.3.2, K-means: the algorithm chooses centroids that minimise the inertia, or within-cluster sum-of-squares criterion, the sum over samples of the squared distance to the nearest centroid; given enough time it converges, but possibly to a local minimum that depends on the initial centroids, so the computation is often done several times with different initialisations.
Within-cluster scatter falls with K and the number of clusters is read from a kink
Hastie T, Tibshirani R, Friedman J. The Elements of Statistical Learning: Data Mining, Inference, and Prediction. 2nd ed. New York: Springer; 2009. Section 14.3.11, p. 519: the within-cluster dissimilarity W_K generally decreases with increasing K, even when evaluated on an independent test set, so cross-validation cannot be used; the number of clusters is estimated by identifying a kink in the plot of W_K against K, and the gap statistic compares log W_K with data spread uniformly over a rectangle containing the data.
Canonical Identity
Stable URI · Machine-readable · Resolvable · CC BY 4.0