Written and maintained by CASRAI Editorial Board
Last updated
Clustering analysis in R is done with functions that ship with the base stats package: scale() to put variables on one footing, dist() to measure dissimilarity, kmeans() for partitioning, and hclust() with cutree() for hierarchical clustering. This guide runs both approaches end to end on one data frame and spells out the argument defaults that most often change a result: the random starting centres in kmeans(), the ward.D versus ward.D2 choice in hclust(), and which of k and h wins in cutree(). Every function and argument below was checked against the R reference manual on 2026-10-29.
What cluster analysis in R is used for in research
Cluster analysis groups rows (participants, samples, sites, documents) so that rows in the same group are more alike than rows in different groups, without a pre-labelled outcome. Researchers use it to look for subgroups in survey or biomarker data, to organise samples before a heatmap, and to check whether an assumed grouping shows up in the data. It is an unsupervised method; see supervised vs unsupervised learning for the distinction.
In R the two routes you will meet most are partitioning (kmeans(), where you choose the number of clusters first) and hierarchical clustering (hclust(), where you build a full tree and cut it afterwards). The worked method for k-means itself, including the formula, is in What Is K-Means Clustering?; the same task in another language is covered in cluster analysis in Python, and the point-and-click equivalent in cluster analysis in SPSS.
Install or access (official source only)
R is free software released under the GNU General Public License (R Project, r-project.org/about.html, checked 2026-10-29), and installers are distributed through CRAN, the Comprehensive R Archive Network (cran.r-project.org/mirrors.html). Nothing in this guide needs an extra package: scale(), dist(), kmeans(), hclust() and cutree() are in R’s standard distribution. The cluster package (Rousseeuw et al., a CRAN recommended package, version 2.1.8.3 published 2026-07-30) adds further clustering functions and is loaded with library(cluster) if you want it.
Step-by-step: clustering data in R
The steps use R’s built-in iris data frame (four numeric measurement columns) so that every line can be pasted into a fresh session. Replace iris[, 1:4] with your own numeric columns.
- Select numeric columns and handle missing values.
df = na.omit(iris[, 1:4])dist()can work around missing values (see Troubleshooting), but dropping or imputing them yourself keeps the two methods comparable. - Scale the variables.
x = scale(df)By default
scale(x, center = TRUE, scale = TRUE)subtracts each column mean and divides by each column standard deviation, and stores the values used in the"scaled:center"and"scaled:scale"attributes. Without this step, a variable measured in large units dominates every distance. Scaling before clustering is standard practice rather than a requirement stated in the function documentation. - Run k-means.
set.seed(42) km = kmeans(x, centers = 3, nstart = 25)The usage is
kmeans(x, centers, iter.max = 10, nstart = 1, algorithm = c("Hartigan-Wong", "Lloyd", "Forgy", "MacQueen"), trace = FALSE). Whencentersis a single number, the documentation says a random set of distinct rows ofxis chosen as the initial centres, so the call depends on the random seed.nstart = 25asks for 25 random starting sets, andset.seed()makes the run repeatable. - Look for a sensible k.
wss = sapply(1:10, function(k) kmeans(x, centers = k, nstart = 25)$tot.withinss) plot(1:10, wss, type = "b", xlab = "Number of clusters k", ylab = "Total within-cluster sum of squares")Plot
tot.withinssagainst k and look for where adding clusters stops buying much. This is a judgement heuristic, not a test; the same logic is explained in what a scree plot shows. - Run hierarchical clustering.
d = dist(x, method = "euclidean") hc = hclust(d, method = "ward.D2") plot(hc, labels = FALSE)hclust()takes the dissimilarities produced bydist(), not the raw data frame. Plotting the result draws the dendrogram. - Cut the tree into clusters.
groups = cutree(hc, k = 3) table(groups)cutree(tree, k = NULL, h = NULL)returns a membership vector when you give one value of k or h, and a matrix when you give several. - Compare the two solutions and attach labels to your data.
table(kmeans = km$cluster, hclust = groups) df$cluster = factor(km$cluster)
Choosing the distance and the linkage
The documented options are below. They are the arguments to vary when you test how stable a clustering is.
| Function | Argument | Options and default (R reference manual) |
|---|---|---|
dist() |
method |
“euclidean” (default), “maximum”, “manhattan”, “canberra”, “binary”, “minkowski” |
hclust() |
method |
“ward.D”, “ward.D2”, “single”, “complete” (default), “average” (UPGMA), “mcquitty” (WPGMA), “median” (WPGMC), “centroid” (UPGMC) |
kmeans() |
algorithm |
“Hartigan-Wong” (default), “Lloyd”, “Forgy”, “MacQueen”; “Lloyd” and “Forgy” name the same algorithm |
cutree() |
k, h |
k = desired number of groups; h = height at which to cut; if both are given, k takes precedence |
Output and how to read it
Reading the kmeans object
The object returned by kmeans() holds cluster (each row’s assignment), centers (the cluster means), totss, withinss (per cluster), tot.withinss, betweenss, size and iter. The documentation defines betweenss as totss - tot.withinss, so km$betweenss / km$totss is the share of total variation that lies between clusters. A higher share means a tighter fit for that k, but the share generally rises as k grows, so it should not be used alone to pick k. Because the centres are on the scaled variables here, convert back with the stored "scaled:center" and "scaled:scale" attributes if you need group means in original units.
Reading the hclust object and the dendrogram
The tree is stored in merge (the order of joins), height (the dissimilarity at each join), order (the leaf order used for plotting) and labels. On the dendrogram, a tall vertical gap before a join means the clusters being merged were far apart; cutting below that gap with cutree(hc, h = ...) keeps them separate. Whichever route you use, report the distance, the linkage or algorithm, the number of clusters, and the seed and nstart for k-means, so others can reproduce the clusters in R.
Troubleshooting
Different clusters every time you run kmeans()
Initial centres are chosen at random, so unseeded runs can land on different solutions. Call set.seed() before kmeans(), raise nstart above its default of 1 so that several starts are tried, and compare tot.withinss across runs. The documentation notes that Hartigan-Wong usually does best but recommends trying several random starts.
ward.D gives a different tree from the one you expected
Only "ward.D2" implements Ward’s criterion, because it squares the dissimilarities before updating clusters. "ward.D" does not implement Ward’s 1963 criterion; it matches the old "ward" option from R 3.0.3 and earlier, which matters if you are reproducing older code. In the cluster package, agnes(*, method = "ward") corresponds to hclust(*, "ward.D2").
Dendrogram inversions with centroid or median linkage
The documentation warns that "median" and "centroid" linkage can produce inversions in the dendrogram, and recommends "centroid" only with squared Euclidean distances (for example hclust(dist(x)^2, method = "centroid")).
NA values in dist()
Missing values are allowed in dist() and are excluded from all computations involving the row they occur in. If every pair is excluded for a distance, the result is NA, and hclust() cannot use it. Check with anyNA(d) and remove or impute the offending rows.
Clusters in R that cutree() returns look wrong
If you pass both k and h, k is used and h is ignored. Pass only the one you mean.
Free alternatives
R itself is free, so the practical choice is between functions inside it. All three below are documented by the R project or CRAN.
| Option | What it provides | Where it comes from |
|---|---|---|
stats::kmeans() |
Partitioning into a chosen number of clusters, with four algorithms | Base R, stats package |
stats::hclust() with cutree() |
Agglomerative hierarchical clustering with eight linkage methods and tree cutting by k or h | Base R, stats package |
cluster package |
“Finding Groups in Data”: extended cluster analysis functions based on Kaufman and Rousseeuw (1990) | CRAN recommended package, Rousseeuw et al. |
To see a hierarchical clustering drawn alongside the data, the heatmap workflow is in heatmaps in R. If you are choosing between R and SPSS for the whole analysis, see SPSS vs R.
FAQ
How do I do cluster analysis in R?
Scale numeric variables with scale(), then either call kmeans(x, centers = k, nstart = 25) or build dist(x), pass it to hclust(), and cut the tree with cutree(). The numbered steps above give runnable code for both.
How do I choose the number of clusters?
For k-means, run kmeans() over a range of k, plot tot.withinss and look for where the curve flattens. For hierarchical clustering, inspect the dendrogram for large gaps in height. Both are judgement aids; report the rule you used.
What is the difference between kmeans() and hclust() in R?
kmeans() needs the number of clusters (or starting centres) up front and works on the data matrix; hclust() works on a dissimilarity object from dist(), returns a full tree, and you choose the number of clusters afterwards with cutree().
How do I add the cluster number back to my data frame?
Assign the membership vector: df$cluster = factor(km$cluster) for k-means or df$cluster = factor(groups) for a cut tree. Rows keep the same order as the input.
Sources (official documentation, checked 2026-10-29)
- R Project, kmeans: K-Means Clustering, R reference manual (stats).
- R Project, hclust: Hierarchical Clustering, R reference manual (stats).
- R Project, dist: Distance Matrix Computation, R reference manual (stats).
- R Project, cutree: Cut a Tree into Groups of Data, R reference manual (stats).
- R Project, scale: Scaling and Centering of Matrix-like Objects, R reference manual (base).
- CRAN, cluster: “Finding Groups in Data”: Cluster Analysis Extended Rousseeuw et al., package page.
- R Project, About R and CRAN mirrors.








