--- title: "Clustering by Merging K-Means Solutions with MergeKmeans" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Clustering by Merging K-Means Solutions with MergeKmeans} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6, fig.height = 5, fig.align = "center") set.seed(2026) ``` The K-means algorithm is fast and intuitive, but in its traditional form it can only succeed when clusters are spherical with approximately equal volumes. **MergeKmeans** implements the DEMP-K procedure of Melnykov and Michael (2020), which removes this restriction while preserving the speed of K-means: 1. run K-means with a number of components $K$ deliberately *larger* than the number of clusters sought, so that small spherical components fill the clusters whatever their shapes; 2. interpret the solution as a Gaussian mixture fitted by classification EM and compute the **pairwise overlap** $\omega_{kk'}$ (the sum of the two misclassification probabilities) between all pairs of components in closed form — for classical K-means simply $\omega_{kk'} = 2\Phi\!\left(-\|\mu_k - \mu_{k'}\| / (2\sigma)\right)$; 3. merge components by hierarchical clustering with $1-\omega_{kk'}$ as the dissimilarity, and cut the tree at the requested number of clusters $G$ or at an overlap threshold $\omega^*$. Because steps 2 and 3 operate on the $K \times K$ overlap matrix rather than on the $n$ observations, the whole post-processing cost is negligible and the procedure scales to millions of observations. ## Two half-circular clusters A classical failure case for K-means, taken from Section 4.1 of the paper: two well-separated half-circles. ```{r half-circles-data} library(MergeKmeans) n <- 1000 th <- runif(n, 0, pi) x <- rbind( cbind(cos(th[1:500]), sin(th[1:500])), cbind(1 - cos(th[501:1000]), 0.45 - sin(th[501:1000]))) x <- x + matrix(rnorm(2 * n, sd = 0.1), n) truth <- rep(1:2, each = 500) plot(x, col = truth, pch = 20, asp = 1, xlab = "x1", ylab = "x2") ``` Plain K-means with two centers cuts both half-circles in half. Instead we fit ten components and merge. Since the goal is to detect well-separated clusters of arbitrary shape, single linkage is the appropriate choice: ```{r half-circles-fit} fit <- MergeKmeans(x, K = 10, G = 2, linkage = "single", nstart = 25) fit table(estimated = fit$cluster, truth = truth) ``` ```{r half-circles-plot} plot(fit, what = "classification", asp = 1) ``` ## The overlap map When the number of clusters is unknown, the **overlap map** displays all pairwise overlaps with components ordered so that strongly overlapping ones are adjacent. Groups of dark cells correspond to components modeling a common cluster; pale cells in the bottom summary row mark the gaps between well-separated clusters — here, one pale cell splits the ten components into two groups of five. ```{r overlap-map} plot(fit, what = "overlap") ``` The merge tree offers a complementary view, and `recut()` lets you cut it at a different number of clusters (or at an overlap threshold $\omega^*$) without refitting: ```{r tree} plot(fit, what = "tree") recut(fit, omega.star = 0.01) ``` ## An inscribed cluster The second illustration of the paper: a circular cluster inscribed in a ring-shaped one. No rigid-motion of two spherical prototypes can separate these, yet merging a 12-component solution recovers the structure: ```{r inscribed} m <- 500 th2 <- runif(m, 0, 2 * pi) y <- rbind(cbind(rnorm(m, 3, 0.2) * cos(th2), rnorm(m, 3, 0.2) * sin(th2)), matrix(rnorm(2 * m, sd = 0.4), m)) truth2 <- rep(1:2, each = m) fit2 <- MergeKmeans(y, K = 12, G = 2, linkage = "single", nstart = 25) table(estimated = fit2$cluster, truth = truth2) plot(fit2, what = "classification", asp = 1) ``` ## Choosing K and predicting new data The merging procedure is robust to the choice of $K$ as long as $K$ is large enough for components to fill the clusters. A practical guide is the elbow of the proportion of variability explained by the between-component variability: ```{r chooseK} chooseK(x, K = seq(2, 20, by = 2), nstart = 10) ``` New observations are assigned to the nearest component and then mapped to its merged cluster: ```{r predict} predict(fit, rbind(c(0, 1), c(1, -0.6))) ``` ## Compact overlapping clusters For compact, possibly overlapping clusters, Ward's linkage is the recommended choice (it is also the package default). Here three Gaussian blobs with unequal spreads are recovered from a 15-component solution: ```{r ward} z <- rbind(matrix(rnorm(600), ncol = 2), matrix(rnorm(600, mean = 4, sd = 1.4), ncol = 2), cbind(rnorm(300, 8), rnorm(300))) fit3 <- MergeKmeans(z, K = 15, G = 3, linkage = "ward.D", nstart = 25) plot(fit3, what = "classification", asp = 1) ``` ## Beyond classical K-means `MergeKmeans()` also provides the three generalized K-means variants of the paper's Appendix A, each corresponding to a Gaussian mixture with a different covariance restriction: `"HoEC"` (common elliptical covariance), `"HeSC"` (component-specific spherical variances), and `"HeEC"` (unrestricted covariances; the overlap computation then uses the Davies algorithm from the **CompQuadForm** package). The spherical `"HoSC"` default remains the recommendation for large datasets. ## Reference Melnykov, V. and Michael, S. (2020). Clustering large datasets by merging K-means solutions. *Journal of Classification*, **37**, 97–123. [doi:10.1007/s00357-019-09314-8](https://doi.org/10.1007/s00357-019-09314-8)