Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
R clustering is an unsupervised method for grouping observations by similarity. A reliable analysis starts before kmeans(): define what rows and columns represent, select an appropriate distance measure, clean and scale the data, compare plausible algorithms, test candidate cluster counts, and assess stability. The resulting groups are analytical partitions—not automatically “natural” or causally meaningful categories.
What cluster analysis does
Cluster analysis groups observations without a predefined outcome variable. It assigns observations according to a chosen representation, distance or similarity measure, algorithm, and set of parameters.
Cluster labels are arbitrary: cluster 1 is not inherently better than cluster 2. Results can change when you change the features, scaling, transformations, distance metric, algorithm, initialization, missing-value treatment, or outlier handling.
Hard clustering assigns each observation to one group. Soft clustering reports probabilities or degrees of membership. Partitioning methods directly seek a chosen number of groups; hierarchical methods produce nested groupings; and density-based methods search for dense regions while potentially labeling sparse observations as noise.
#1 Best Overall
R includes kmeans(), dist(), hclust(), and cutree() in the stats package. The cluster package adds PAM, CLARA, Gower dissimilarities, and silhouette analysis.
Read the current R documentation for kmeans(), hclust(), dist(), and PAM for version-specific behavior.
Set up a reproducible R clustering workflow
Install the packages used by the examples:
install.packages(c("cluster", "factoextra", "dbscan", "mclust"))
Record your R and package versions when publishing results. Defaults and package behavior can change between versions. Use a seed whenever an algorithm uses random initialization.
Free tools Windows power users keep installed
One-click scans. No signup required.
set.seed(42)
Inspect and prepare the data
Suppose df contains one observation per row and candidate clustering features in columns. Audit the data first:
str(df)
summary(df)
colSums(is.na(df))
sapply(df, function(x) sum(!is.finite(x)))
Remove identifier columns unless the identifier encodes meaningful information. Do not convert factors to integer codes merely to make them numeric. Coding small, medium, and large as 1, 2, and 3 imposes a distance and ordering that may not be justified.
Dates, text, counts, proportions, binary variables, and categorical variables need different representations. Most basic distance and clustering functions do not solve missing-data problems automatically. Complete-case analysis is simple but may be biased when missingness is systematic; imputation should preserve the structure relevant to clustering and be sensitivity-tested.
Investigate extreme values rather than deleting them automatically. An outlier can pull a k-means centroid, but it may also be the observation most important to your application. Strongly right-skewed positive features may benefit from a transformation such as log1p().
Recommended Free Tools
Build a numeric feature matrix
x <- df[, c("feature_1", "feature_2", "feature_3")]
x <- x[complete.cases(x), , drop = FALSE]
x_scaled <- scale(x)
scale() centers columns and, by default, divides them by their standard deviations. This prevents a variable measured in large units from dominating Euclidean distance.
Scaling is not automatically correct. If all variables share a meaningful unit, or absolute magnitude is the question of interest, standardization may remove important information. The choice of scaling is part of the analytical question. See the R documentation for scale().
Choose a distance measure
Distance defines what “similar” means. Euclidean distance is common for numeric data and is sensitive to scale and large coordinate differences. Manhattan distance sums absolute differences and can be useful when individual large deviations should have less influence.
d_euclidean <- dist(x_scaled, method = "euclidean")
d_manhattan <- dist(x_scaled, method = "manhattan")
Correlation distance can emphasize the shape of a profile rather than its absolute level, but it needs careful interpretation. Binary data may require binary or Jaccard-type measures.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteFor mixed numeric, categorical, ordinal, and binary data, use Gower dissimilarity through cluster::daisy():
library(cluster)
d_gower <- daisy(df_mixed, metric = "gower")
Ordinary k-means operates on a numeric matrix and is not a direct solution for arbitrary mixed-type data. For mixed data, consider Gower distance with PAM or hierarchical clustering, or a method designed for mixed variables. The dist() documentation describes the available distance methods.
K-means clustering in R
K-means is a useful baseline when numeric observations are reasonably compact and similarly shaped. It partitions observations around arithmetic means by minimizing within-cluster squared Euclidean variation. It is fast and easy to explain, but it requires a chosen number of clusters and is sensitive to scaling, outliers, initialization, and non-spherical structure.
set.seed(42)
km <- kmeans(
x_scaled,
centers = 3,
nstart = 25,
iter.max = 100
)
km$cluster
km$centers
km$size
km$withinss
km$tot.withinss
km$betweenss
centers = 3 requests three groups. nstart runs the algorithm from multiple random starting configurations; using more starts reduces the chance of accepting a poor local solution. set.seed() makes the random result reproducible.
Because this example uses x_scaled, km$centers are standardized centers. They are useful for comparing feature profiles, but report summaries on the original scale for readers who need practical interpretation.
A lower within-cluster sum of squares does not by itself prove that the solution is better. It generally decreases as more clusters are requested. K-means is a poor match for elongated, nested, crescent-shaped, unequal-density, or heavily contaminated groups.
The algorithm argument supports methods including Hartigan–Wong, Lloyd, and MacQueen. Check the documentation for the R version used.
Choose the number of clusters
There is rarely a single objectively “true” number of clusters. Use multiple diagnostics, then consider stability, interpretability, sample size, and the decision the groups must support.
Elbow method
wss <- sapply(1:10, function(k) {
kmeans(x_scaled, centers = k, nstart = 25)$tot.withinss
})
plot(
1:10, wss,
type = "b",
xlab = "Number of clusters",
ylab = "Total within-cluster sum of squares"
)
Look for a bend where additional clusters produce diminishing improvement. The elbow is often ambiguous and is a heuristic, not proof.
Silhouette width
library(cluster)
sil <- silhouette(km$cluster, dist(x_scaled))
plot(sil)
mean(sil[, "sil_width"])
Silhouette width compares an observation’s cohesion with its assigned cluster against its separation from the nearest alternative. A higher average is generally better geometrically, but it does not establish domain usefulness or external validity. See the silhouette documentation.
Gap statistic and factoextra
library(factoextra)
fviz_nbclust(x_scaled, kmeans, method = "wss", k.max = 10)
fviz_nbclust(x_scaled, kmeans, method = "silhouette", k.max = 10)
set.seed(42)
gap <- clusGap(
x_scaled,
FUN = kmeans,
K.max = 10,
B = 50,
nstart = 25
)
fviz_gap_stat(gap)
WSS, silhouette, and gap statistics optimize different notions of structure, so disagreement is normal. Do not choose the most convenient result without reporting the disagreement. The fviz_nbclust() documentation covers these workflows.
Hierarchical clustering
Hierarchical clustering creates a tree of nested groupings. It is useful when you want to inspect several resolutions rather than commit immediately to one value of k.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →d <- dist(x_scaled, method = "euclidean")
hc <- hclust(d, method = "ward.D2")
plot(hc, labels = FALSE, hang = -1)
groups <- cutree(hc, k = 3)
table(groups)
Linkage matters. Single linkage can produce chaining; complete linkage tends to favor compact groups; average linkage is a compromise. Ward-style methods favor compact partitions and should be used with compatible distance assumptions. The dendrogram reflects the algorithm and distance measure; it is not automatically an evolutionary or causal tree.
Rank #4
library(factoextra)
fviz_dend(
hc,
k = 3,
rect = TRUE,
show_labels = FALSE
)
You can cut by a chosen number of groups or by dendrogram height, depending on what is meaningful for the application. See hclust() and factoextra::hcut().
PAM and k-medoids
Partitioning around medoids, or PAM, represents each cluster with an actual observation rather than an arithmetic mean. This makes representatives easier to inspect and allows distance objects such as Gower dissimilarities.
library(cluster)
pam_fit <- pam(
x_scaled,
k = 3,
metric = "euclidean"
)
pam_fit$clustering
pam_fit$medoids
pam_fit$silinfo$avg.width
PAM is often less affected by outliers than k-means because medoids are observed records, but it remains sensitive to feature selection, scaling, distance, and data composition. CLARA provides a sampling-based medoid approach for larger datasets, although sampling may miss small or rare groups. See the PAM documentation.
DBSCAN and HDBSCAN
Density-based methods are appropriate when groups may have irregular shapes, when noise matters, or when specifying k is undesirable. DBSCAN uses a neighborhood radius, eps, and a minimum number of neighbors, minPts.
library(dbscan)
db <- dbscan(
x_scaled,
eps = 0.8,
minPts = 5
)
table(db$cluster)
plot(db)
kNNdistplot(x_scaled, k = 5)
abline(h = 0.8, lty = 2)
In common dbscan output, a noise label identifies observations that do not belong to a discovered density-connected group. Confirm the exact output convention for the installed version.
eps is scale-dependent. A single global density threshold can fail when groups have different densities, and high-dimensional neighborhoods may become uninformative. Poor settings can classify most observations as noise. HDBSCAN can represent varying density more flexibly, but its membership and cluster-selection parameters still require interpretation. The dbscan package documentation covers DBSCAN, HDBSCAN, OPTICS, and related tools.
Gaussian mixture models
Gaussian mixture models treat observations as arising from a mixture of probability distributions. Unlike hard k-means labels, they can provide membership probabilities and uncertainty.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutelibrary(mclust)
mc <- Mclust(x_scaled)
summary(mc)
mc$classification
mc$uncertainty
plot(mc, what = "BIC")
plot(mc, what = "classification")
mclust compares covariance structures and component counts using model-based criteria such as BIC. Mixtures can represent overlapping or differently shaped groups more flexibly than spherical k-means, but they require stronger distributional assumptions and may have convergence or covariance problems. A mixture component is a statistical model component, not automatically a naturally occurring population. See the mclust documentation.
Best Value
Visualize and profile the clusters
Plot both the input data and the fitted result. A simple two-feature view is useful but incomplete:
plot(
x_scaled[, 1],
x_scaled[, 2],
col = km$cluster,
pch = 19,
xlab = "Feature 1",
ylab = "Feature 2"
)
PCA provides a compact visualization for many numeric features:
library(factoextra)
fviz_cluster(
km,
data = x_scaled,
geom = "point",
ellipse.type = "convex"
)
A PCA plot is a projection. It can hide separation in other dimensions, and PCA maximizes variance rather than practical relevance. Ellipses and convex hulls are visual aids, not proof of validity. Do not reduce dimensions solely to manufacture visible clusters.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Profile groups on the original scale:
profile_original <- aggregate(
x,
by = list(cluster = km$cluster),
FUN = mean
)
profile_original
table(km$cluster)
Useful reporting includes cluster sizes, original-scale means or medians, standardized profiles, categorical distributions, missingness patterns, representative observations or medoids, and uncertainty for probabilistic methods.
Test stability and sensitivity
One seed, one value of k, and one attractive plot are not enough evidence. Repeat k-means with different seeds and larger nstart. Resample observations and refit. Compare the resulting partitions with adjusted Rand index or another agreement measure.
Test sensitivity to:
- Scaling and transformations.
- Outlier treatment.
- Feature inclusion and highly correlated variables.
- Distance metric and linkage method.
- Candidate values of
k. - Rare or very small groups.
The fpc ecosystem provides interfaces for repeated clustering and stability workflows. “Robust” should be defined precisely: resistance to outliers, seed stability, bootstrap stability, or replication in new data are different claims.
A complete numeric baseline script
library(cluster)
library(factoextra)
# Select meaningful numeric features
features <- c("feature_1", "feature_2", "feature_3", "feature_4")
x <- df[, features, drop = FALSE]
# Simple complete finite-row baseline
keep <- complete.cases(x) &&
apply(x, 1, function(row) all(is.finite(row)))
x <- x[keep, , drop = FALSE]
# Decide transformations before scaling
# x$feature_1 <- log1p(x$feature_1)
x_scaled <- scale(x)
set.seed(42)
fviz_nbclust(x_scaled, kmeans, method = "wss", k.max = 10)
fviz_nbclust(x_scaled, kmeans, method = "silhouette", k.max = 10)
set.seed(42)
km <- kmeans(
x_scaled,
centers = 3,
nstart = 50,
iter.max = 100
)
table(km$cluster)
km$centers
d <- dist(x_scaled)
sil <- silhouette(km$cluster, d)
mean(sil[, "sil_width"])
fviz_silhouette(sil)
hc <- hclust(d, method = "ward.D2")
hc_groups <- cutree(hc, k = 3)
fviz_dend(hc, k = 3, rect = TRUE, show_labels = FALSE)
profile_original <- aggregate(
x,
by = list(cluster = km$cluster),
FUN = mean
)
profile_original
The keep expression is written for a simple numeric baseline. In production, handle missingness, imputation, and non-finite values explicitly rather than assuming complete cases are appropriate.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Which R clustering method should you use?
| Method | Use it when | Strengths | Weaknesses |
|---|---|---|---|
| K-means | Numeric data and compact, similarly shaped groups are plausible | Fast, simple, familiar | Requires k; sensitive to scale and outliers |
| Hierarchical | You want nested structure or a dendrogram | Shows multiple resolutions | Linkage-sensitive and potentially expensive |
| PAM | Actual representative records or custom distances matter | Interpretable medoids; often less affected by outliers | Requires k; slower than k-means |
| CLARA | You need medoid clustering on larger data | More scalable than PAM | Sampling can miss rare clusters |
| DBSCAN | Irregular shapes and noise are expected | Finds density-connected shapes; no preset k |
Sensitive to eps, density variation, and dimension |
| HDBSCAN | Density varies across groups | Represents a density hierarchy | Membership and parameters still need interpretation |
| Gaussian mixtures | Overlapping groups and probabilities matter | Soft assignments and model selection | Distributional assumptions and computational complexity |
There is no universally best algorithm. Choose the method whose assumptions match the data representation and analytical objective, then compare plausible alternatives.
Common mistakes and edge cases
- Mixed types: Do not feed factor codes into k-means as continuous measurements. Consider Gower distance with PAM or hierarchical clustering.
- Missing data: Complete cases can bias results. Use and sensitivity-test an appropriate imputation strategy.
- Outliers: Compare transformed, unfiltered, and robust alternatives; do not delete unusual observations automatically.
- Correlated features: Near-duplicate columns can overweight one construct. Remove, combine, or justify a reduction strategy.
- High dimensions: Distance concentration can make neighborhoods less informative. Use domain-informed feature selection or a justified representation.
- Imbalanced sizes: K-means may split large groups and absorb small ones. Inspect sizes and compare methods.
- Small samples: Tiny clusters may disappear under resampling. Avoid strong generalizations.
- Leakage: If clusters later enter a predictive model, exclude post-outcome information and reproduce preprocessing at deployment.
- New data: A partition may not remain valid when feature distributions drift. Define how new observations will be assigned and monitor the data.
Practical checklist
- Define exactly what an observation and feature represent.
- Remove identifiers and inspect missing, invalid, skewed, and extreme values.
- Decide whether scaling changes the question you want to answer.
- Choose a distance measure appropriate for the data types.
- Fit more than one plausible algorithm.
- Compare candidate cluster counts with multiple diagnostics.
- Test seeds, resamples, features, scaling, and outlier decisions.
- Profile groups on the original scale and report their sizes.
- Show uncertainty or borderline membership where available.
- Separate geometric separation from domain usefulness, causal claims, and external validation.
A clustering analysis can end with the conclusion that the data do not show clear or stable groups. That is a valid result. Internal metrics describe the geometry of a fitted partition; they do not prove business value, clinical usefulness, causality, or reproducibility in a new population.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

