Computational Provenance & Reproducibility Record

RAISINS - R and AI Solutions for INferential Statistics · Online Statistical Analysis Platform for Agricultural Research

Computational Provenance & Reproducibility Record Cluster Analysis · 2.0.0 · DOI 10.5281/zenodo.21767142

Computational Provenance & Reproducibility Record

RAISINS · Cluster Analysis Module

This Computational Provenance Record documents the statistical computing environment, software dependencies, computational provenance, and bibliographic references associated with the RAISINS Cluster Analysis module. It is intended to support computational reproducibility and software transparency. Detailed statistical methodology, mathematical derivations, and user guidance are provided separately in the official module documentation.

Any issues or updates required please comment here

Go to the App from here

1 Module Metadata

Parameter Specification
Module Cluster Analysis
Module Version 2.0.0
DOI 10.5281/zenodo.21767142
Document Type Computational workflow
Statistical Engine R
R Version 4.5.2
Reproducibility Execution Environment: Posit Connect · GCR · renv-locked

2 Statistical Dependency Manifest

Package Version Repository Core Statistical Functions
stats 4.5.2 Base R dist(), hclust(), cutree(), cophenetic(), cor(), scale()
FactoMineR 2.16 CRAN PCA(), HCPC()
factoextra 2.1.0 CRAN fviz_nbclust(), hcut(), fviz_dend()
cluster 2.1.8.2 CRAN clusGap(), maxSE()
dendextend 1.19.1 CRAN dendlist(), untangle(), entanglement(), cor.dendlist()

3 Statistical Function Registry

Analytical Role Primary Function(s)
Variable scaling base::scale() and internal centering / min-max / unit-length / robust routines
Distance computation stats::dist()
Hierarchical clustering stats::hclust()
Cluster assignment stats::cutree()
Dendrogram fit diagnostic stats::cophenetic(), stats::cor() (cophenetic correlation)
Optimal cluster number factoextra::fviz_nbclust() (elbow, silhouette), cluster::clusGap() + cluster::maxSE() (gap statistic)
PCA (basis for HCPC) FactoMineR::PCA()
PCA eigenvalues & variance explained res.pca$eig
PCA variable contributions res.pca$var$contrib
PCA variable correlations with components res.pca$var$cor
Hierarchical Clustering on Principal Components FactoMineR::HCPC()
Cluster means (raw units) stats::aggregate() on the cutree()-based cluster assignment
Cluster means (standardized scale / “Clustering Summary”) dplyr::group_by() + summarise() on the PCA input data, grouped by the HCPC cluster assignment
Intra-/inter-cluster distances Custom aggregation of the pairwise distance matrix (stats::dist()) by the cutree()-based cluster assignment
Dendrogram plot factoextra::fviz_dend()
Dendrogram comparison (entanglement score) dendextend::dendlist(), dendextend::untangle(), dendextend::entanglement()
Linkage method agreement matrix dendextend::cor.dendlist(method = "cophenetic")

4 Default Methods & Parameters

Analysis Step / Parameter Default Method / Value
Variable
Scaling
Default method Z-score standardisation (mean 0, SD 1) applied to every selected clustering variable before analysis
Alternatives Centering only, min-max (0-1), unit-length, robust (median / IQR), or none, selectable per run
Rationale Distance-based clustering is dominated by variables with the largest numeric range; scaling puts all clustering variables on a comparable footing
Distance
Measure

(dist())
Default euclidean
Alternatives manhattan, maximum, canberra, minkowski
Linkage
Method

(hclust())
Default complete
Alternatives average, single, ward.D2, mcquitty, median, centroid
Number of
Clusters (k)
Initial value Pre-filled from the elbow-method suggestion below; user-adjustable, must satisfy 2 ≤ k < n
Elbow method factoextra::fviz_nbclust(Xs, FUNcluster = kmeans, method = "wss") on the scaled data; suggested k is taken at the point of maximum decrease in the WSS curve (which.min(diff(wss)) + 1). Used as a fast heuristic even though the reported clustering itself is hierarchical, not k-means
Silhouette method factoextra::fviz_nbclust(X, FUN = hcut, method = "silhouette"); suggested k maximises the average silhouette width. Note: hcut() uses its own internal default linkage/distance (Ward / Euclidean) independent of the linkage and distance the user selected elsewhere in the module
Gap statistic cluster::clusGap(Xs, FUN = hcut, nstart = 25, K.max = 10, B = 50) with cluster::maxSE(..., method = "firstSEmax"); suggested k is the smallest k within one standard error of the maximum gap. Visualised via factoextra::fviz_gap_stat()
Dendrogram
Fit
Cophenetic correlation cor(original distance, cophenetic(hc)); values closer to 1 indicate the dendrogram faithfully represents the original distance structure
PCA
Diagnostics
Eigenvalues & variance explained res.pca$eig - eigenvalue, percentage of variance, and cumulative percentage of variance explained, one row per principal component
Variable contributions res.pca$var$contrib - percentage contribution of each clustering variable to each principal component (columns sum to 100% per component)
Variable correlations res.pca$var$cor - correlation of each clustering variable with each principal component, range -1 to +1
HCPC
(HCPC())
Basis FactoMineR::PCA() is run on the scaled data first; FactoMineR::HCPC() then clusters in principal-component space, consolidating via Ward linkage plus a k-means pass. This is independent of the linkage/distance chosen for the main Analysis Results tab
Cluster quality Total / Within / Between sum-of-squares computed in PCA space; Between/Total ratio reported as a separation indicator
Top variables per cluster res.hcpc$desc.var$quanti - one row per (cluster, variable) pair, columns: v.test, Mean in category, Overall mean, sd in category, Overall sd, p.value, and n (number of observations in that cluster). Ranked by absolute v.test; larger magnitude indicates the variable more strongly characterises that cluster relative to the overall mean
Cluster-wise
Means
Raw units aggregate(X, by = list(cluster = clusters), FUN = mean), grouped by the cutree()-based cluster assignment - not the HCPC assignment used for the rows above
Standardized scale ("Clustering Summary") Mean of each PCA input variable per HCPC cluster, computed on the same scaled data PCA was run on; since the data are z-scored, positive values are above the overall (zero) average and negative values are below it
Intra-/Inter-Cluster
Distances
Intra-cluster Mean pairwise distance among all members of the same cluster (upper triangle of that cluster's distance submatrix), using the cutree()-based assignment; only computed when distance is euclidean/manhattan and linkage is complete/average/single/ward.D2
Inter-cluster Mean pairwise distance between every pair of distinct clusters' members; one row per cluster pair
Dendrogram
Plot

(fviz_dend())
Rendering factoextra::fviz_dend() draws the cluster dendrogram with branches and tip labels colour-coded by cluster assignment (k colours), optionally with rectangles drawn around each cluster
Cluster Comparisons
(Tanglegram)
Alignment Two dendrograms - built from independently selectable linkage/distance pairs - are aligned with dendextend::untangle(method = "step1side") to minimise crossing before comparison
Agreement metric dendextend::entanglement(); 0 = the two dendrograms align perfectly, 1 = maximal tangling
Linkage Method
Correlation Matrix
Comparison dendextend::cor.dendlist(method = "cophenetic") across Single / Complete / Average / Centroid / Median / Ward linkage on one distance metric

5 R Code for Key Analytical Steps

The code blocks below demonstrate the exact computation behind each reported result using the USArrests dataset (Murder, Assault, UrbanPop, Rape; 50 U.S. states) built into the datasets package - the same dataset shipped as this module’s own demo data.

5.1 Scaling, Distance, and Hierarchical Clustering

data(USArrests)
X  <- USArrests                       # Murder, Assault, UrbanPop, Rape (all numeric)
Xs <- scale(X)                        # z-score standardisation (RAISINS default)

d  <- dist(Xs, method = "euclidean")  # default distance
hc <- hclust(d, method = "complete")  # default linkage

k  <- 4
clusters <- cutree(hc, k = k)         # cluster membership per observation

# dendrogram fit
coph <- cophenetic(hc)
cor(d, coph)                          # cophenetic correlation

5.2 Plotting the Dendrogram

library(factoextra)

fviz_dend(hc, k = k, cex = 0.7,
          k_colors = "jco",           # cluster colour palette
          rect = TRUE, rect_fill = TRUE,
          color_labels_by_k = TRUE,
          main = "Cluster Dendrogram", xlab = "Objects", ylab = "Height")

5.3 Choosing the Number of Clusters (k)

library(factoextra)
library(cluster)

# Elbow method - WSS by k (kmeans proxy)
elbow <- fviz_nbclust(Xs, FUNcluster = kmeans, method = "wss")
wss   <- elbow$data$y
suggested_k_elbow <- which.min(diff(wss)) + 1

# Silhouette method - hcut() uses its own internal Ward/Euclidean default
sil <- fviz_nbclust(Xs, FUN = hcut, method = "silhouette")
suggested_k_silhouette <- sil$data$clusters[which.max(sil$data$y)]

# Gap statistic
gap <- clusGap(Xs, FUN = hcut, nstart = 25, K.max = 10, B = 50)
suggested_k_gap <- maxSE(gap$Tab[, "gap"], gap$Tab[, "SE.sim"], method = "firstSEmax")

5.4 Plotting the Optimal-k Methods

library(factoextra)
library(ggplot2)

# Elbow method
fviz_nbclust(Xs, FUNcluster = kmeans, method = "wss") +
  geom_vline(xintercept = suggested_k_elbow, linetype = "dashed", color = "steelblue", linewidth = 0.8) +
  labs(title = "Elbow Method")

# Silhouette method
fviz_nbclust(Xs, FUN = hcut, method = "silhouette") +
  labs(title = "Average Silhouette Method")

# Gap statistic
fviz_gap_stat(gap) +
  labs(title = "Gap Statistic Method")

5.5 HCPC (Hierarchical Clustering on Principal Components)

library(FactoMineR)

res.pca  <- PCA(Xs, graph = FALSE)          # PCA on the scaled data
res.hcpc <- HCPC(res.pca, nb.clust = k, graph = FALSE)  # Ward + k-means consolidation

res.hcpc$data.clust$clust                   # cluster membership
res.hcpc$desc.var$quanti                    # top variables per cluster - v.test, Mean/sd in category,
                                             # Overall mean/sd, p.value, and n (observations per cluster)

# cluster quality: Total / Within / Between sum-of-squares (PCA space)
total_ss    <- sum(scale(res.pca$ind$coord, scale = FALSE)^2)
between_ss  <- sum(sapply(split(as.data.frame(res.pca$ind$coord), res.hcpc$data.clust$clust),
                          function(g) nrow(g) * sum((colMeans(g))^2)))
within_ss   <- total_ss - between_ss
cluster_seperation_ss <- between_ss / total_ss                       # Between/Total ratio (separation indicator)

5.6 PCA Diagnostics, Cluster Means, and Intra-/Inter-Cluster Distances

# PCA eigenvalues, variable contributions, and variable correlations with components
res.pca$eig                                  # eigenvalue / % variance / cumulative %
res.pca$var$contrib                          # % contribution of each variable per component
res.pca$var$cor                              # correlation of each variable with each component

# Cluster-wise means - raw units (uses the cutree()-based clusters, not HCPC)
cluster_means <- aggregate(X, by = list(cluster = clusters), FUN = mean)

# Cluster-wise means - standardized scale ("Clustering Summary", uses HCPC clusters)
hcpc_cluster <- res.hcpc$data.clust$clust
tab_means <- aggregate(as.data.frame(Xs), by = list(cluster = hcpc_cluster), FUN = mean)

# Intra-/inter-cluster distances (uses the cutree()-based clusters + distance matrix)
dmat        <- as.matrix(dist(Xs, method = "euclidean"))
cluster_ids <- sort(unique(clusters))

intra <- sapply(cluster_ids, function(cl) {
  idx <- which(clusters == cl)
  m   <- dmat[idx, idx]
  mean(m[upper.tri(m)])                      # mean pairwise distance within the cluster
})
names(intra) <- cluster_ids

inter <- combn(cluster_ids, 2, function(pair) {
  mean(dmat[clusters == pair[1], clusters == pair[2]])   # mean pairwise distance between the pair
})
names(inter) <- combn(cluster_ids, 2, paste, collapse = "-")

5.7 Cluster Comparisons (Tanglegram + Linkage Correlation)

library(dendextend)

hc1 <- hclust(dist(Xs, method = "euclidean"), method = "average")
hc2 <- hclust(dist(Xs, method = "euclidean"), method = "ward.D2")

dl <- dendlist(as.dendrogram(hc1), as.dendrogram(hc2))
names(dl) <- c("average", "ward.D2")
dl <- untangle(dl, method = "step1side")
entanglement(dl)                             # 0 = identical, 1 = maximal tangling

# Plot the tanglegram (k = number of clusters highlighted on each side)
k_highlight <- 4
tanglegram(dl, k_labels = k_highlight, k_branches = k_highlight,
           main_left = names(dl)[1], main_right = names(dl)[2],
           margin_inner = 10, lwd = 2)

# Linkage method correlation matrix (cophenetic agreement across 6 linkage methods)
methods <- c("single", "complete", "average", "centroid", "median", "ward.D2")
dends   <- lapply(methods, function(m) as.dendrogram(hclust(dist(Xs), method = m)))
cor.dendlist(do.call(dendlist, dends), method = "cophenetic")

Explore the entire Cluster Analysis module in preview mode using our demo datasets. To submit suggestions or report a workflow issue, please use the discussion section below, or visit the official RAISINS website.

6 RAISINS Native Statistical Framework

RAISINS uses R for all its statistical computations. Every package used to generate major results is listed and demonstrated with examples, so results can be reproduced independently. These results are then organized and formatted on the RAISINS website along with visualisation to make them easier to use and interpret. RAISINS also has its own custom-built statistical tools for managing workflows, validating results, and generating reports. Details of these are not fully covered here, they’re shared with outside researchers only on request, and are subject to licensing terms.

7 Package References

R Core Team. (2025). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/

Le, S., Josse, J., & Husson, F. (2025). FactoMineR: Multivariate Exploratory Data Analysis and Data Mining (R package version 2.16). https://doi.org/10.32614/CRAN.package.FactoMineR

Kassambara, A., & Mundt, F. (2020). factoextra: Extract and Visualize the Results of Multivariate Data Analyses (R package version 2.1.0). https://doi.org/10.32614/CRAN.package.factoextra

Maechler, M., Rousseeuw, P., Struyf, A., Hubert, M., & Hornik, K. (2025). cluster: “Finding Groups in Data”: Cluster Analysis Extended Rousseeuw et al. (R package version 2.1.8.2). https://doi.org/10.32614/CRAN.package.cluster

Galili, T. (2015). dendextend: an R package for visualizing, adjusting, and comparing trees of hierarchical clustering (R package version 1.19.1). https://doi.org/10.32614/CRAN.package.dendextend

Allaire, J. J., Xie, Y., Dervieux, C., McPherson, J., Luraschi, J., Ushey, K., Atkins, A., Wickham, H., Cheng, J., Chang, W., & Iannone, R. (2026). rmarkdown: Dynamic Documents for R (R package version 2.31). https://github.com/rstudio/rmarkdown

Feedback & Discussion