Skip to content

Instantly share code, notes, and snippets.

@mingjiphd
Created January 28, 2026 02:26
Show Gist options
  • Select an option

  • Save mingjiphd/b1bdb29e026c726b6a3c496c2525a175 to your computer and use it in GitHub Desktop.

Select an option

Save mingjiphd/b1bdb29e026c726b6a3c496c2525a175 to your computer and use it in GitHub Desktop.
Machine Learning using R How to Implement Multidimentional Scaling
This R script is a step by step demonstration showing how to implement MDS (both metric and non-metric MDS) using R. The R functions used are: cmdscale (Base R), mds (smacof) and isoMDS(MASS).
Click here to view a step by step demo: https://youtu.be/SkVAzb1IuOU?si=6tTkUsvgu_5vnO4I
#############################################################################################
# Machine Learning using R How to Implement Multidimsional Scaling #
#############################################################################################
#### Multidimensional Scaling (MDS)
## visualizes similarities/dissimilarities between objects
## by placing them in low-dimensional space (usually 2D/3D)
## where distances reflect original relationships
#### Input: Pairwise dissimilarity matrix (interval, ordinal, or nominal data)
#### Output: Point coordinates + goodness-of-fit measures
#### Two main types
## Metric MDS (cmdscale, smacof interval)
## Preserves actual distances; assumes Euclidean structure
## Non-metric/Ordinal MDS (isoMDS):
## Preserves rank order only; more flexible for rank/perceptual data
##### Stress value measures fit quality: <0.05=Excellent, <0.10=Good, <0.20=Fair, >0.20=Poor
#### cmdscale eigenvalues indicate variance explained per dimension (large positive = good fit)
#### Shepard diagram shows monotonic regression (observed vs. fitted distances) for ordinal MDS validation
# Load required libraries
library(stats) # for cmdscale (base R MDS)
library(smacof) # for SMACOF MDS
# Set seed for reproducibility
set.seed(1192026)
## PART 1: Interval Data for MDS
# Generate synthetic interval dissimilarity data for 10 objects
n <- 10
diss_matrix <- matrix(runif(n*(n-1)/2, 1, 10), nrow = n, ncol = n)
diss_matrix <- as.dist(diss_matrix)
diag(diss_matrix) <- 0
# Base R MDS using cmdscale (metric/interval MDS)
mds_base <- cmdscale(diss_matrix, k = 2, eig = TRUE)
# SMACOF interval MDS
mds_smacof <- mds(diss_matrix, ndim = 2, type = "interval")
# Comparison
par(mfrow = c(1, 2))
plot(mds_base$points, main = "Base R cmdscale (Interval)",
xlab = "Dim 1", ylab = "Dim 2", pch = 16)
plot(mds_smacof$conf, main = "SMACOF (Interval)",
xlab = "Dim 1", ylab = "Dim 2", pch = 16)
# Stress values comparison
cat("Base R eigenvalues:", round(mds_base$eig[1:2], 3), "\n")
cat("SMACOF stress:", round(mds_smacof$stress, 3), "\n")
## PART 2: Ordinal Data MDS
# Load required library
library(MASS)
# Set seed for reproducibility
set.seed(123)
## Generate Ordinal Dissimilarity Data for MDS
n_objects <- 12 # Number of objects to compare
max_rank <- 7 # Ordinal scale: 1-7 (like Likert ratings)
# Create symmetric dissimilarity matrix with ordinal ranks (1-7)
# Upper triangle filled with random ordinal values
ordinal_matrix <- matrix(0, n_objects, n_objects)
upper_tri <- upper.tri(ordinal_matrix)
# Fill upper triangle with ordinal ranks (1-7)
ordinal_matrix[upper_tri] <- sample(1:max_rank, sum(upper_tri), replace = TRUE)
ordinal_matrix <- ordinal_matrix + t(ordinal_matrix) # Make symmetric
diag(ordinal_matrix) <- 0 # Zero diagonal
# Convert to dist object
ordinal_diss <- as.dist(ordinal_matrix)
# Display first few dissimilarities
cat("Sample ordinal dissimilarities (ranks 1-7):\n")
print(round(ordinal_diss[1:6], 1))
## Perform Ordinal MDS using isoMDS
ordinal_mds <- isoMDS(ordinal_diss, k = 2, maxit = 2000)
## Results and Visualization
par(mfrow = c(1, 2))
# Plot MDS configuration
par(mfrow = c(1, 2))
# 1. MDS Configuration Plot
plot(ordinal_mds$points,
main = "Ordinal MDS Configuration (isoMDS)",
xlab = "Dimension 1", ylab = "Dimension 2",
pch = 16, col = "darkred", cex = 1.3)
# 2. Shepard Diagram (CORRECTED)
shepard_plot <- Shepard(ordinal_diss, ordinal_mds$points)
plot(shepard_plot, pch = 16, col = "blue",
main = "Shepard Diagram",
xlab = "Original Ordinal Distances",
ylab = "Fitted Distances")
abline(0, 1, col = "red", lwd = 2)
lines(shepard_plot$x, shepard_plot$yf, col = "darkgreen", lwd = 2)
# Stress results
cat("\n=== ORDINAL MDS RESULTS ===\n")
cat("Stress (ordinal):", round(ordinal_mds$stress, 4), "\n")
cat("Stress %:", round(ordinal_mds$stress * 100, 2), "%\n")
Click here to view a step by step demo: https://youtu.be/SkVAzb1IuOU?si=6tTkUsvgu_5vnO4I
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment