mec vec alg ana sta
1 77 82 67 67 81
2 63 78 80 70 81
3 75 73 71 66 81
4 55 72 63 70 68
5 63 63 65 70 63
6 53 61 72 64 73
7 51 67 65 65 68
8 59 70 68 62 56
9 62 60 58 62 70
10 64 72 60 62 45
STAT 204 – Introduction to Statistical Data Analysis
13 Nov 2025
Today’s Focus:
Learning Goals: Master dimensionality reduction and understand variance structure in multivariate data
Consider a dataset with many variables:
Problems with high-dimensional data:
Question: Can we reduce dimensions while preserving information?
Real-world example: Suppose you measure students on:
Key insight: These scores are likely highly correlated!
Real-world example: Suppose you measure students on:
PCA finds new variables (principal components) that:
PCA creates new variables (components) as weighted combinations:
\[PC_1 = w_{11}X_1 + w_{12}X_2 + \cdots + w_{1p}X_p\]
\[PC_2 = w_{21}X_1 + w_{22}X_2 + \cdots + w_{2p}X_p\]
Key properties:
Result: Often the first few PCs capture most of the variance!
Dataset: 88 students taking 5 exams
mec vec alg ana sta
1 77 82 67 67 81
2 63 78 80 70 81
3 75 73 71 66 81
4 55 72 63 70 68
5 63 63 65 70 63
6 53 61 72 64 73
7 51 67 65 65 68
8 59 70 68 62 56
9 62 60 58 62 70
10 64 72 60 62 45
mec: Mechanics examvec: Vectors examalg: Algebra examana: Analysis examsta: Statistics examBefore PCA, let’s examine correlations:
mec vec alg ana sta
mec 1.0000000 0.5534052 0.5467511 0.4093920 0.3890993
vec 0.5534052 1.0000000 0.6096447 0.4850813 0.4364487
alg 0.5467511 0.6096447 1.0000000 0.7108059 0.6647357
ana 0.4093920 0.4850813 0.7108059 1.0000000 0.6071743
sta 0.3890993 0.4364487 0.6647357 0.6071743 1.0000000
Observations: All exams positively correlated - students who do well on one tend to do well on others!
PCA is based on eigendecomposition of the covariance matrix:
\[\Sigma = A\Lambda A'\]
where:
Key insight:
Two approaches for PCA:
1. Covariance matrix (\(\Sigma\)):
prcomp(data, scale = FALSE) uses covariance2. Correlation matrix (standardized):
prcomp(data, scale = TRUE) uses correlationFor test scores: We’ll use correlation since scores may have different scales!
[1] "sdev" "rotation" "center" "scale" "x"
Components of output:
sdev: Standard deviations of each PC (sqrt of eigenvalues)rotation: PC loadings (eigenvectors) - the weightscenter: Original variable meansscale: Original variable standard deviationsx: PC scores - the transformed dataLoadings show how original variables combine to create PCs:
PC1 PC2 PC3 PC4 PC5
mec -0.3996045 -0.6454583 0.62078249 -0.1457865 -0.1306722
vec -0.4314191 -0.4415053 -0.70500628 0.2981351 -0.1817479
alg -0.5032816 0.1290675 -0.03704901 -0.1085987 0.8466894
ana -0.4569938 0.3879057 -0.13618182 -0.6662561 -0.4221885
sta -0.4382444 0.4704545 0.31253342 0.6589164 -0.2340223
Interpretation of PC1 (first column):
mec vec alg ana sta
-0.6454583 -0.4415053 0.1290675 0.3879057 0.4704545
Interpretation of PC2:
As PC2 increases:
Meaning: PC2 contrasts mechanics/vectors performance against algebra/analysis/statistics performance - a math type dimension!
How much variance does each PC capture?
[1] 3.1809801 0.7395718 0.4449651 0.3878924 0.2465905
[1] 0.63619603 0.14791437 0.08899303 0.07757848 0.04931810
[1] 0.6361960 0.7841104 0.8731034 0.9506819 1.0000000
Key findings:
Scree plot shows variance by component:


“Elbow” appears around PC2-3 → suggests keeping 2-3 components
Another way to decide how many components to keep:
plot(1:5, cumsum(prop_var), type = "b",
xlab = "Number of Components",
ylab = "Cumulative Proportion of Variance",
main = "Cumulative Variance Explained",
pch = 19, col = "darkgreen", ylim = c(0, 1))
abline(h = 0.8, lty = 2, col = "red")
abline(h = 0.9, lty = 2, col = "orange")
text(3, 0.82, "80% threshold", col = "red")Rule of thumb: Keep enough PCs to explain 80-90% of variance
Scores are the actual PC values for each observation:
PC1 PC2 PC3 PC4 PC5
1 -4.285041 -0.67410225 0.1235891 0.79311084 -0.51438033
2 -4.541989 0.21331176 -0.2317797 0.55160634 0.59618974
3 -4.102690 -0.27557530 0.5304377 0.60968618 -0.02781595
4 -3.026846 0.14916207 -0.3702154 0.15958897 -0.43950477
5 -2.882081 0.04408014 0.2988861 -0.32257398 -0.14767795
6 -2.988775 0.68126196 0.2628756 0.29503310 0.54754485
7 -2.712178 0.35836879 -0.2052017 0.28351062 -0.03891465
8 -2.738431 -0.40679075 -0.2823520 -0.06940714 0.34696306
9 -2.360712 0.07851216 0.6488411 0.31562205 -0.52398228
10 -2.260005 -1.05560241 -0.3834319 -0.40401135 -0.20638713
These are the new coordinates in PC space:
Biplot shows both observations and variable loadings:
Reading the biplot:
Pair Work (5 minutes):
Looking at the biplot:
Hint:
Discuss with your partner, then we’ll share on Ed Discussion.
Several criteria exist:
1. Kaiser Criterion (Eigenvalue > 1)
2. Proportion of Variance
Several criteria exist:
3. Scree Plot Elbow
4. Context-specific
Let’s see the difference:
# PCA without scaling
pca_no_scale <- prcomp(scor, scale = FALSE)
# PCA with scaling
pca_scaled <- prcomp(scor, scale = TRUE)
# Compare variance explained
data.frame(
PC = 1:5,
Unscaled = round(pca_no_scale$sdev^2 / sum(pca_no_scale$sdev^2), 3),
Scaled = round(pca_scaled$sdev^2 / sum(pca_scaled$sdev^2), 3)
) PC Unscaled Scaled
1 1 0.619 0.636
2 2 0.182 0.148
3 3 0.093 0.089
4 4 0.076 0.078
5 5 0.029 0.049
Recommendation: Always use scale = TRUE unless variables already in same units!
We can approximate original data using fewer PCs:
# Original data (scaled)
X_scaled <- scale(scor)
# Use only first 2 PCs to reconstruct
PC_scores_2 <- pca_result$x[, 1:2]
loadings_2 <- pca_result$rotation[, 1:2]
X_reconstructed <- PC_scores_2 %*% t(loadings_2)
# Compare original vs reconstructed for student 1
rbind(
Original = X_scaled[1, ],
Reconstructed = X_reconstructed[1, ],
Difference = X_scaled[1, ] - X_reconstructed[1, ]
) mec vec alg ana sta
Original 2.17573873 2.3890787 1.543347 1.368669 2.2423565
Reconstructed 2.14742649 2.1462680 2.069577 1.696749 1.5607605
Difference 0.02831224 0.2428107 -0.526230 -0.328080 0.6815959
With 2 PCs, we capture most structure but lose some detail
Plot students in the reduced 2D space:
plot(pca_result$x[, 1], pca_result$x[, 2],
xlab = "PC1 (63.6% variance)",
ylab = "PC2 (14.8% variance)",
main = "Students in Principal Component Space",
pch = 19, col = "steelblue")
text(pca_result$x[, 1], pca_result$x[, 2],
labels = 1:nrow(scor), pos = 3, cex = 0.6)
abline(h = 0, v = 0, lty = 2, col = "gray")Now we can see student clustering patterns in 2D!
Individual Work (8 minutes):
# Built-in mtcars dataset: car specifications
data(mtcars)
head(mtcars)
# Your tasks:
# 1. Examine correlations between variables
cor(mtcars)
# 2. Perform PCA with scaling
pca_cars <- prcomp(mtcars, scale = TRUE)
# 3. How much variance do first 2 PCs explain?
# 4. Look at PC1 loadings - what does PC1 represent?
pca_cars$rotation[, 1]
# 5. Make a biplot
biplot(pca_cars, scale = 0)
# 6. Create scree plot and decide how many PCs to keep
# Questions to answer:
# - What does PC1 seem to measure? (hint: look at loadings)
# - How many PCs would you keep and why?
# - Which variables are most correlated with PC1?Post your findings on Ed Discussion!
Real application: Handwritten digit recognition
Each image = 784 pixels (28×28). Can we reduce this?
From your reference slides:
1. Dimensionality Reduction
2. Visualization
3. Dealing with Multicollinearity
4. Data Compression
5. Feature Engineering
Problem: Multicollinearity in predictors → unstable regression
Solution: Use PC scores as predictors instead!
# Regular regression (might have multicollinearity)
model_original <- lm(mpg ~ cyl + disp + hp + wt + qsec,
data = mtcars)
# Extract PC scores
pca_cars <- prcomp(mtcars[, -1], scale = TRUE)
pc_scores <- pca_cars$x[, 1:3] # Keep first 3 PCs
# Regression on PCs (no multicollinearity!)
model_pc <- lm(mtcars$mpg ~ pc_scores)
# PCs are uncorrelated by definition
cor(pc_scores)Benefits:
PCA assumes:
When PCA may not work well:
Remember: PCA is unsupervised - doesn’t use response variable!
Before running PCA:
During PCA:
After PCA:
# Step 1: Load and explore data
data(scor, package = "bootstrap")
summary(scor)
cor(scor)
# Step 2: Perform PCA
pca <- prcomp(scor, scale = TRUE)
# Step 3: Examine variance explained
summary(pca)
screeplot(pca, type = "lines")
# Step 4: Look at loadings
pca$rotation[, 1:3]
# Step 5: Visualize
biplot(pca, scale = 0)
# Step 6: Use PC scores if needed
pc_scores <- pca$x[, 1:2] # Keep first 2
head(pc_scores)
# Step 7: Extract variance proportions
pca_var <- pca$sdev^2
pve <- pca_var / sum(pca_var)
cumsum(pve)Your Turn: Comprehensive PCA Analysis
# Use the USArrests dataset
data(USArrests)
?USArrests # Read about the data
# Your tasks:
# 1. Explore the data
head(USArrests)
summary(USArrests)
pairs(USArrests) # Scatterplot matrix
# 2. Calculate and visualize correlations
# 3. Perform PCA (with scaling - why is this important here?)
# 4. Answer these questions:
# a) How many PCs would you retain and why?
# b) What does PC1 represent? Interpret the loadings.
# c) What does PC2 represent?
# d) Which states have highest PC1 scores? Lowest?
# e) Make a biplot - which variables are most correlated?
# 5. Create all relevant visualizations:
# - Scree plot
# - Cumulative variance plot
# - Biplot
# - PC1 vs PC2 scatter with state labels
# 6. Reconstruct data using only 2 PCs
# How much information did we lose?Most important: Understand your data and your goal before applying PCA!
PCA is related to many other techniques:
Factor Analysis
Correspondence Analysis
Singular Value Decomposition (SVD)
Multidimensional Scaling (MDS)
When to use PCA:
# Perform PCA
pca <- prcomp(data, scale = TRUE)
# Variance explained
summary(pca)
pca$sdev^2 # Eigenvalues
# Loadings
pca$rotation
# Scores
pca$x
# Visualizations
screeplot(pca, type = "lines")
biplot(pca, scale = 0)
# Variance proportions
prop_var <- pca$sdev^2 / sum(pca$sdev^2)
cumsum(prop_var)
# Correlation plot (before PCA)
library(corrplot)
corrplot(cor(data))For next class:
Office Hours: After class today
![]()
STAT 204 – Intro to Statistical Data Analysis