install.packages("factoextra")Enhanced Cluster Analysis in R with factoextra’s eclust()
One function call runs the clustering, picks the number of clusters, and draws publication-ready plots
A practical guide to factoextra’s eclust() — the one-call wrapper that runs k-means or hierarchical clustering, picks the optimal number of clusters with the gap statistic, attaches silhouette information, and returns ggplot2 cluster, dendrogram and silhouette plots. With get_dist()/fviz_dist() for distance matrices, all on the built-in USArrests data.
eclust()— thefactoextrawrapper that runs a whole clustering analysis in one line: k-means or hierarchical, the gap statistic to choose k, silhouette info, and ggplot2 plots.get_dist()/fviz_dist()— compute and visualize a distance matrix (incl. correlation-based distances).- A complete, runnable example on the built-in USArrests data — k-means and hierarchical, end to end.
- When to reach for
eclust()(fast prototyping) vs. the step-by-step lessons (full control).
The one-line shortcut for cluster analysis
Standard clustering in R is a multi-step workflow: scale the data, compute a distance matrix, run kmeans() or hclust(), separately estimate the best number of clusters, then hand-build the plots. That is the right way to learn it — and our step-by-step lessons walk through every step — but when you just want a quick first look at the structure in your data, it is a lot of typing.
The factoextra package collapses that whole sequence into a single function, eclust() (“enhanced clustering”). One call:
- runs k-means, PAM, CLARA, FANNY (partitioning) or
hclust, AGNES, DIANA (hierarchical); - for partitioning, picks the number of clusters automatically with the gap statistic (no more guessing k);
- attaches silhouette information so you can judge cluster quality immediately;
- returns ggplot2 plots — cluster scatter, dendrogram, silhouette — ready for a report.
Think of eclust() as rapid prototyping: get a defensible clustering and a publication-grade figure in seconds, then drop down to the modular workflow when you need to control each decision.
Setup
Install factoextra once, then load it. It pulls in cluster and ggplot2, which do the heavy lifting.
library(factoextra)Prepare the data
We use the built-in USArrests data (violent-crime rates and urban population for the 50 US states). Clustering is distance-based, so always scale the variables first — otherwise Assault (hundreds) would dwarf Murder (single digits). scale() centers and standardizes every column:
data("USArrests")
df <- scale(USArrests)
head(df) Murder Assault UrbanPop Rape
Alabama 1.24256408 0.7828393 -0.5209066 -0.003416473
Alaska 0.50786248 1.1068225 -1.2117642 2.484202941
Arizona 0.07163341 1.4788032 0.9989801 1.042878388
Arkansas 0.23234938 0.2308680 -1.0735927 -0.184916602
California 0.27826823 1.2628144 1.7589234 2.067820292
Colorado 0.02571456 0.3988593 0.8608085 1.864967207
Compute and visualize the distance matrix
Before clustering, it helps to see the dissimilarities. get_dist() computes the distance matrix and — unlike base dist() — also supports correlation-based distances ("pearson", "kendall", "spearman"), which group observations by profile shape rather than magnitude. fviz_dist() then draws it as a heatmap:
# Correlation-based distance
res.dist <- get_dist(df, method = "pearson")
# Visualize the dissimilarity matrix
fviz_dist(res.dist, lab_size = 8)
Read it like this: red cells mark small distances (similar states), blue cells mark large distances. States that sit next to each other in red blocks along the diagonal are the natural clusters — a useful sanity check before you commit to a number of clusters.
Enhanced k-means in one call
Here is the payoff. A single eclust() call scales nothing further (we already scaled df), runs k-means, and computes the gap statistic to choose k automatically. nstart = 25 runs the algorithm from 25 random starts and keeps the best, which stabilizes the result:
res.km <- eclust(df, "kmeans", nstart = 25)
The call already returns a cluster plot (states projected onto the first two principal components, each cluster colour-coded with a shaded hull). The optimal k it settled on is stored on the result:
res.km$nbclust[1] 3
Because eclust() ran the gap statistic for you, you can plot the curve it used to decide. The chosen k is where the gap statistic is maximized (within the standard Tibs2001SEmax rule):
fviz_gap_stat(res.km$gap_stat)
Finally, check cluster quality with the silhouette plot — already attached to the result. Each bar is one state; a wide positive silhouette width means the state sits comfortably in its cluster, while a negative bar flags a likely mis-assignment:
fviz_silhouette(res.km) cluster size ave.sil.width
1 1 13 0.37
2 2 20 0.26
3 3 17 0.32

The printout reports the average silhouette width per cluster (and overall) — a quick, single-number read on how well-separated your clusters are.
Enhanced hierarchical clustering
Switch one argument to get hierarchical clustering instead. eclust(df, "hclust") computes the dendrogram, and eclust() again attaches silhouette and cluster information, so you draw all three plots straight from the result:
res.hc <- eclust(df, "hclust") # compute hierarchical clustering
fviz_dend(res.hc, rect = TRUE) # dendrogram with cluster rectangles
fviz_silhouette(res.hc) # silhouette plot cluster size ave.sil.width
1 1 19 0.26
2 2 19 0.28
3 3 12 0.43

fviz_cluster(res.hc) # cluster scatter plot
For hierarchical clustering you can also pass a correlation-based metric via hc_metric (e.g. hc_metric = "spearman") — something base hclust() won’t do without building the distance matrix yourself.
Choosing the number of clusters yourself
The automatic gap statistic is a sensible default, but you can override it. Pass k = to fix the number of clusters directly — handy when domain knowledge or a downstream constraint dictates it:
# Fix four clusters instead of letting the gap statistic decide
res.km4 <- eclust(df, "kmeans", k = 4, nstart = 25)The same k = argument works for every method ("pam", "clara", "hclust", "agnes", "diana", …).
When to use eclust() vs. the step-by-step approach
eclust() is a convenience wrapper, not a replacement for understanding the pipeline. Use it to move fast; use the modular lessons when you need control.
- Reach for
eclust()when you want a quick, defensible first clustering — exploratory analysis, a prototype, or a fast publication figure — and you’re happy with the gap statistic’s choice of k and sensible defaults. - Drop down to the step-by-step workflow when you need to control each decision: a specific distance metric, a particular linkage method, a different rule for choosing k (elbow, silhouette, NbClust’s 30-index vote), custom validation, or to understand what each step is doing. That is exactly what the lessons below teach.
Go deeper — the full lessons
This post is the shortcut. For the complete, controllable workflow each step lives in its own lesson:
- K-means clustering — the partitioning algorithm
eclust(df, "kmeans")runs under the hood. - Determining the optimal number of clusters — the elbow, silhouette and gap-statistic methods
eclust()automates. - Cluster validation statistics — silhouette, Dunn index and the must-know quality measures.
- Hierarchical clustering — distance, linkage and the dendrogram, step by step.
- Clustering in R — the series — the full curriculum.
Citation
@online{kassambara2026,
author = {Kassambara, Alboukadel},
title = {Enhanced {Cluster} {Analysis} in {R} with Factoextra’s
Eclust()},
date = {2026-06-24},
url = {https://www.datanovia.com/blog/cluster-analysis-in-r-eclust},
langid = {en}
}