## # A tibble: 4 × 2
## site n_plants
## <chr> <int>
## 1 DG 25
## 2 HD 12
## 3 LEH 25
## 4 TJH 25
An introduction to multivariate data, distance, and ordination
Note
Gotelli & Ellison, A Primer of Ecological Statistics, Ch. 12 — The Analysis of Multivariate Data — is the core reference for this lecture.
Darlingtonia californica (cobra lily)

height, mouth_diam, tube_diam, keel_diam, wing1_length, wing2_length, wingspreahoodmass_g, tubemass_g, wingmass_g## # A tibble: 4 × 2
## site n_plants
## <chr> <int>
## 1 DG 25
## 2 HD 12
## 3 LEH 25
## 4 TJH 25
Pitcher structure showing the measured features

## # A tibble: 6 × 7
## site CHA TRU VAI LOC GAR ABL
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 0 3 0 0 0 0
## 2 2 0 5 4 3 0 0
## 3 14 3 4 4 5 0 0
## 4 15 2 3 3 5 1 0
## 5 28 0 1 1 1 5 5
## 6 29 0 0 0 0 5 5
📥 darlingtonia.csv 📥 DoubsSpe.csv 📥 DoubsEnv.csv

## # A tibble: 1 × 3
## sd_height sd_wingmass ratio
## <dbl> <dbl> <dbl>
## 1 101. 0.102 986.

dist() returns one number for every pair of objects: an n × n dissimilarity matrix.| Metric | Formula idea | Data it suits | Range |
|---|---|---|---|
| Euclidean | straight-line distance | continuous, standardized, few zeros | 0 → ∞ |
| Manhattan | sum of absolute differences | continuous, less outlier-sensitive | 0 → ∞ |
| Bray–Curtis | shared abundance / total abundance | species abundance counts | 0 → 1 |
| Jaccard | shared species / total species | presence–absence | 0 → 1 |
# same data, three metrics, first pair
round(c(
euclidean = vegdist(doubs_mat,
method = "euclidean")[1],
manhattan = vegdist(doubs_mat,
method = "manhattan")[1],
bray = vegdist(doubs_mat,
method = "bray")[1],
jaccard = vegdist(doubs_mat > 0,
method = "jaccard")[1]), 3)
## euclidean manhattan bray jaccard
## 5.385 9.000 0.600 0.667Important
The metric is a modelling decision, not a default. It encodes what you mean by “different”.

Reducing 2 variables to 1 principal axis: the new axis points along the direction of greatest spread.
| Method | Starts from | Distance implied | How it solves | Where in this course |
|---|---|---|---|---|
| PCA | raw / standardized variables | Euclidean only | eigen-decomposition | Week 14 |
| PCoA | any dissimilarity matrix | whatever you chose | eigen-decomposition | named only |
| CA / DCA | species count table | chi-square | eigen-decomposition | named only |
| NMDS | any dissimilarity matrix | whatever you chose | iterative, rank-based | Week 15 |
| Cluster | any dissimilarity matrix | whatever you chose | agglomerative joining | Week 15 |
## # A tibble: 4 × 2
## pair r
## <chr> <dbl>
## 1 height ~ tubemass_g 0.843
## 2 wing1_length ~ wing2_length 0.836
## 3 hoodmass_g ~ wingmass_g 0.803
## 4 wing1_length ~ wingmass_g 0.764

## # A tibble: 6 × 4
## PC Eigenvalue Percent Cumulative
## <chr> <dbl> <dbl> <dbl>
## 1 PC1 4.99 49.9 49.9
## 2 PC2 1.77 17.7 67.5
## 3 PC3 1.53 15.3 82.8
## 4 PC4 0.573 5.7 88.5
## 5 PC5 0.352 3.5 92
## 6 PC6 0.261 2.6 94.6

## PC1 PC2 PC3
## height -0.278 -0.449 0.198
## mouth_diam -0.369 -0.110 0.214
## tube_diam 0.040 -0.602 -0.390
## keel_diam 0.202 -0.491 -0.328
## wing1_length -0.375 0.171 -0.280
## wing2_length -0.342 0.131 -0.415
## wingsprea -0.239 0.156 -0.549
## hoodmass_g -0.385 -0.057 0.185
## tubemass_g -0.355 -0.320 0.263
## wingmass_g -0.393 0.080 -0.007
tube_diam and keel_diam stand apart from the rest → tube girth.wingsprea and wing2_length dominate → a wing axis.# PC1 loadings are all negative here,
# so a HIGH PC1 score = a SMALL plant
round(pca_result$rotation[1:4, 1], 3)
## height mouth_diam tube_diam keel_diam
## -0.278 -0.369 0.040 0.202
# flipping is legal and changes nothing
flip <- -pca_result$x[, 1]
round(c(var_original = var(pca_result$x[, 1]),
var_flipped = var(flip)), 3)
## var_original var_flipped
## 4.987 4.987Always check the sign before you write a sentence such as “site X has higher PC1”. Say what it means biologically, not just which way the number went.

keel_diam (0.202) and tube_diam (0.04) sit apart.
tube_diam (-0.6) and keel_diam (-0.49) dominate, with height also loading. A plant can be tall and thin-tubed, or short and fat-tubed, at any overall size.wingsprea (-0.55) and wing2_length (-0.42) dominate. How far the trap’s forked appendages spread, independent of size and tube girth.pca_result$x holds them, one row per plant.## # A tibble: 6 × 5
## plant_id site PC1 PC2 PC3
## <int> <chr> <dbl> <dbl> <dbl>
## 1 1 TJH -1.92 0.08 1.53
## 2 2 TJH 3.35 1.53 0.75
## 3 3 TJH 0.92 -0.03 0.25
## 4 4 TJH -0.98 0.24 -0.24
## 5 5 TJH 1.15 -1.02 1.54
## 6 6 TJH -1.37 -0.61 0.85



Note
Week 15 takes this apart properly: the algorithm, Shepard diagrams, choosing k, and fitting environmental vectors.
Warning
PCA was run on all 87 plants at once, ignoring site. The components are therefore not independent of the grouping you then test. Treat these p-values as exploratory.
## site emmean SE df lower.CL upper.CL .group
## DG -1.024 0.383 83 -1.786 -0.262 a
## LEH -0.659 0.383 83 -1.421 0.103 ab
## TJH 0.423 0.383 83 -0.339 1.185 b
## HD 2.626 0.553 83 1.526 3.726 c
##
## Confidence level used: 0.95
## P value adjustment: tukey method for comparing a family of 4 estimates
## significance level used: alpha = 0.05
## NOTE: If two or more means share the same grouping symbol,
## then we cannot show them to be different.
## But we also did not show them to be the same.
Important
This is the sign trap in action. “HD has the highest PC1” and “HD has the smallest plants” are the same sentence. Always translate before you write.
adonis2(darl_scaled ~ site,
data = darlingtonia,
method = "euclidean")
## Permutation test for adonis under reduced model
## Permutation: free
## Number of permutations: 999
##
## adonis2(formula = darl_scaled ~ site, data = darlingtonia, method = "euclidean")
## Df SumOfSqs R2 F Pr(>F)
## Model 3 213.7 0.24849 9.1483 0.001 ***
## Residual 83 646.3 0.75151
## Total 86 860.0 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1R2 is the fraction of total dissimilarity attributable to site — read it like an ANOVA’s \(\eta^2\).betadisper() tells them apart.disp <- betadisper(
vegdist(darl_scaled, method = "euclidean"),
darlingtonia$site)
anova(disp)
## Analysis of Variance Table
##
## Response: Distances
## Df Sum Sq Mean Sq F value Pr(>F)
## Groups 3 11.629 3.8762 2.743 0.04828 *
## Residuals 83 117.290 1.4131
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1Note
Week 15 develops PERMANOVA and ANOSIM in full on the Doubs data.
| Your data | Your question | Use |
|---|---|---|
| Continuous traits, correlated, few zeros | What are the main axes of variation? | PCA (week 14) |
| Species counts, many zeros | How do communities arrange along a gradient? | NMDS (week 15) |
| Any dissimilarity matrix | Which objects group together? | Cluster analysis (week 15) |
| Any dissimilarity matrix | Do my groups differ? | PERMANOVA / ANOSIM (week 15) |
| Continuous, multivariate normal | Do groups differ, parametrically? | MANOVA |
| Categorical variables | Same questions, categorical data | CA / MCA |
KMO() gives a sampling-adequacy score; ours is 0.76 (> 0.6 acceptable, > 0.8 good).“Ten morphological and biomass variables measured on 87 Darlingtonia californica plants from four sites were standardized to zero mean and unit variance and subjected to principal component analysis (
prcomp(), R 4.6.2). Components with eigenvalues > 1 were retained. Site differences were tested with PERMANOVA on Euclidean distances (vegan::adonis2(), 999 permutations), with homogeneity of multivariate dispersion checked usingbetadisper().”
prcomp() is actually solving — eigenvalues, eigenvectors, and PCA in full.