Principal Component Analysis (PCA)
The engine for Data Purification. PCA audits vast fields of correlated data, reveal the hidden 'Skeleton' of variance by mathematically collapsing dozens of markers into a few high-fidelity components.
What is it?
Principal Component Analysis (PCA) is designed to reduce the dimensionality of high-dimensional datasets while retaining the maximum possible variance in the data.
The engine for Data Purification. PCA audits vast fields of correlated data, reveal the hidden 'Skeleton' of variance by mathematically collapsing dozens of markers into a few high-fidelity components.
Goals & Indications
- Complexity Neutralization: Collapse redundant, overlapping variables into a lean set of orthogonal (independent) components.
- Variance Shielding: Capture the maximum amount of 'Information Signal' while discarding random measurement noise.
- Feature Architecture Discovery: Identify the underlying 'Archetypes' that drive global behavior in complex clinical or genomic grids.
Core Idea Diagram
Claims tested
How it works
- Standardize features to mean=0 and variance=1 to prevent scale bias.
- Construct the covariance or correlation matrix across all features.
- Solve for eigenvalues and eigenvectors to find principal components.
- Project the raw high-dimensional points onto the primary eigenvector axes.
Assumptions
Important Note
PCA is primarily an exploratory descriptive technique, not hypothesis testing. Bartlett's test of sphericity tests H₀: correlation matrix = identity. KMO measures sampling adequacy (>0.6 acceptable).
Worked Example
| Component | Eigenvalue | % Var Explained | Cumulative % |
|---|---|---|---|
| PC1 | 1.75 | 87.5% | 87.5% |
| PC2 | 0.25 | 12.5% | 100.0% |
Eigenvector & Variance Projection Laboratory
Slide the feature correlation. Observe how the data points collapse along the primary PC1 eigenvector axis as correlation increases, meaning PC1 explains more variance.
Hypotheses
Pragmatic null and alternative hypotheses defined in mathematical notation.
H₀: Variables are uncorrelated (R = I, identity matrix); PCA would not reduce dimensionality effectively
Hₐ: Variables are sufficiently correlated to allow meaningful dimension reduction
PCA is primarily an exploratory descriptive technique, not hypothesis testing. Bartlett's test of sphericity tests H₀: correlation matrix = identity. KMO measures sampling adequacy (>0.6 acceptable).
Assumptions
The core mathematical criteria needed to ensure that statistical testing remains unbiased and valid.
Diagnostics
Checking residual plots and indices to examine model deviations and ensure standard error integrity.
- Kaiser-Meyer-Olkin (KMO) Measure of Sampling Adequacy (> 0.6)
- Bartlett's Test of Sphericity (p < 0.05)
- Scree plot and Eigenvalues (> 1 criterion) for component retention
- Parallel analysis for determining number of components
- Total variance explained by retained components (>60% recommended)
- Component loadings matrix with clear interpretation
- Communalities (h²) for each variable (>0.3 acceptable)
- Component correlation matrix if oblique rotation used
Applied Minds
Review concrete study examples, data layout guidelines, and copy executable syntax scripts.
Mental Health Symptom Dimensions from Multi-Scale Assessment
Research question: Can we reduce 15 mental health symptom measures (anxiety, depression, stress subscales) to fewer underlying dimensions? Design: Cross-sectional survey (N=320 adults, community sample). Variables: 15 symptom subscales from PHQ-9, GAD-7, PSS-10 measuring depression, anxiety, and stress. Goal: Identify latent symptom dimensions for use in predictive models.
# Principal Components Analysis (PCA): Mental Health Symptom Reduction
# Reducing 15 symptom measures to fewer dimensions
library(psych) # For PCA, KMO, parallel analysis
library(corrplot) # Correlation matrix visualization
library(FactoMineR) # Comprehensive PCA
library(factoextra) # PCA visualization
library(dplyr)
# Simulate realistic mental health symptom data
set.seed(2025)
n <- 320
# Generate 3 underlying factors
factor1_internalizing <- rnorm(n) # Depression-anxiety
factor2_stress <- rnorm(n) # Stress-tension
factor3_fear <- rnorm(n) # Fear-panic
# Create 15 observed variables as linear combinations + noise
data <- data.frame(
# Depression symptoms (load on factor 1)
dep_mood = 0.85*factor1_internalizing + rnorm(n, 0, 0.3),
dep_anhedonia = 0.80*factor1_internalizing + rnorm(n, 0, 0.35),
dep_fatigue = 0.75*factor1_internalizing + 0.3*factor2_stress + rnorm(n, 0, 0.3),
dep_worthless = 0.82*factor1_internalizing + rnorm(n, 0, 0.32),
dep_concentration = 0.70*factor1_internalizing + 0.25*factor2_stress + rnorm(n, 0, 0.35),
# Anxiety symptoms (load on factors 1 and 3)
anx_worry = 0.78*factor1_internalizing + 0.25*factor3_fear + rnorm(n, 0, 0.3),
anx_restless = 0.72*factor1_internalizing + 0.30*factor2_stress + rnorm(n, 0, 0.35),
anx_tense = 0.68*factor1_internalizing + 0.35*factor2_stress + rnorm(n, 0, 0.32),
anx_panic = 0.40*factor1_internalizing + 0.75*factor3_fear + rnorm(n, 0, 0.3),
anx_fear = 0.35*factor1_internalizing + 0.80*factor3_fear + rnorm(n, 0, 0.28),
# Stress symptoms (load on factor 2)
stress_overwhelm = 0.30*factor1_internalizing + 0.82*factor2_stress + rnorm(n, 0, 0.3),
stress_control = 0.25*factor1_internalizing + 0.78*factor2_stress + rnorm(n, 0, 0.32),
stress_irritable = 0.40*factor1_internalizing + 0.70*factor2_stress + rnorm(n, 0, 0.35),
stress_pressure = 0.20*factor1_internalizing + 0.80*factor2_stress + rnorm(n, 0, 0.30),
stress_coping = 0.28*factor1_internalizing + 0.75*factor2_stress + rnorm(n, 0, 0.33)
)
# Standardize to 0-100 scale (simulating normalized scores)
data <- as.data.frame(scale(data) * 15 + 50)
data[data < 0] <- 0
data[data > 100] <- 100
# === STEP 1: Check Assumptions ===
cat("=== Data Summary ===\n")
cat("Sample size:", nrow(data), "\n")
cat("Number of variables:", ncol(data), "\n")
cat("N/p ratio:", round(nrow(data)/ncol(data), 1), "\n\n")
# Check for missing data
cat("Missing data:", sum(is.na(data)), "values\n\n")
# Descriptive statistics
summary(data)
# 1. Check correlations (need adequate correlations)
cor_matrix <- cor(data)
cat("=== Correlation Matrix Summary ===\n")
cat("Range of correlations:", round(min(cor_matrix[cor_matrix!=1]), 2),
"to", round(max(cor_matrix[cor_matrix!=1]), 2), "\n\n")
# Visualize correlation matrix
corrplot(cor_matrix, method="color", type="upper",
tl.cex=0.7, tl.col="black",
title="Correlation Matrix: Mental Health Symptoms",
mar=c(0,0,2,0))
# 2. KMO - Sampling Adequacy
kmo_result <- KMO(data)
cat("=== Kaiser-Meyer-Olkin(KMO) ===\n")
cat("Overall MSA:", round(kmo_result$MSA, 3), "\n")
if (kmo_result$MSA > 0.9) {
cat("Interpretation: Marvelous - excellent for PCA\n\n")
} else if (kmo_result$MSA > 0.8) {
cat("Interpretation: Meritorious - very good for PCA\n\n")
} else if (kmo_result$MSA > 0.7) {
cat("Interpretation: Middling - acceptable for PCA\n\n")
} else if (kmo_result$MSA > 0.6) {
cat("Interpretation: Mediocre - acceptable but not ideal\n\n")
} else {
cat("Interpretation: Unacceptable - PCA not recommended\n\n")
}
cat("Individual MSA per variable:\n")
print(round(kmo_result$MSAi, 2))
# 3. Bartlett's Test of Sphericity
bartlett_result <- cortest.bartlett(cor_matrix, n=nrow(data))
cat("\n=== Bartlett's Test of Sphericity ===\n")
cat("Chi-square:", round(bartlett_result$chisq, 2), "\n")
cat("df:", bartlett_result$df, "\n")
cat("p-value:", format(bartlett_result$p.value, scientific=TRUE), "\n")
if (bartlett_result$p.value < 0.05) {
cat("Interpretation: Significant(p < .05) - correlations adequate for PCA\n\n")
} else {
cat("Interpretation: Non-significant - variables may be too independent\n\n")
}
# 4. Check for outliers (Mahalanobis distance)
maha_dist <- mahalanobis(data, colMeans(data), cov(data))
outlier_cutoff <- qchisq(0.999, df=ncol(data))
outliers <- which(maha_dist > outlier_cutoff)
cat("Multivariate outliers(p < .001):", length(outliers), "cases\n\n")
# === STEP 2: Determine Number of Components ===
# Method 1: Scree plot
pca_initial <- prcomp(data, center=TRUE, scale.=TRUE)
screeplot(pca_initial, type="lines",
main="Scree Plot: Eigenvalues by Component",
xlab="Component Number",
ylab="Eigenvalue(Variance)")
abline(h=1, col="red", lty=2) # Kaiser criterion line
# Extract eigenvalues
eigenvalues <- pca_initial$sdev^2
cat("=== Eigenvalues(Kaiser Criterion: λ > 1) ===\n")
print(round(eigenvalues, 2))
cat("\nComponents with eigenvalue > 1:", sum(eigenvalues > 1), "\n\n")
# Method 2: Variance explained
var_explained <- eigenvalues / sum(eigenvalues) * 100
cum_var <- cumsum(var_explained)
cat("=== Variance Explained ===\n")
var_table <- data.frame(
Component = 1:length(eigenvalues),
Eigenvalue = round(eigenvalues, 2),
Variance_Pct = round(var_explained, 1),
Cumulative_Pct = round(cum_var, 1)
)
print(var_table[1:6,]) # First 6 components
# Method 3: Parallel Analysis (BEST METHOD)
parallel <- fa.parallel(data, fa="pc", n.iter=1000,
main="Parallel Analysis: Actual vs Simulated Data")
cat("\n=== Parallel Analysis ===\n")
cat("Suggested number of components:", parallel$ncomp, "\n\n")
# Decision: Retain 3 components based on parallel analysis
n_components <- 3
cat("DECISION: Retaining", n_components, "components\n")
cat("Total variance explained:", round(cum_var[n_components], 1), "%\n\n")
# === STEP 3: Run PCA with Optimal Number of Components ===
pca_result <- principal(data, nfactors=n_components,
rotate="varimax", # Orthogonal rotation
scores=TRUE)
cat("=== PCA Results ===\n")
print(pca_result)
# Component loadings
cat("\n=== Component Loadings(Varimax Rotation) ===\n")
loadings_matrix <- as.data.frame(unclass(pca_result$loadings))
print(round(loadings_matrix, 2))
# Communalities (variance explained per variable)
cat("\n=== Communalities(h²) ===\n")
cat("Proportion of variance in each variable explained by components\n")
print(round(pca_result$communality, 2))
cat("\nVariables with low communality(<0.3):",
sum(pca_result$communality < 0.3), "\n\n")
# === STEP 4: Interpret Components ===
cat("=== Component Interpretation ===\n\n")
cat("PC1(Internalizing): Loads high on depression and general anxiety\n")
cat("PC2(Stress): Loads high on stress and tension symptoms\n")
cat("PC3(Fear): Loads high on panic and fear symptoms\n\n")
# === STEP 5: Visualizations ===
# Biplot (variables and observations)
biplot(pca_initial, scale=0, cex=0.6,
main="PCA Biplot: Variables and Observations")
# Component loadings plot
library(factoextra)
fviz_pca_var(pca_initial, col.var="contrib",
gradient.cols=c("#00AFBB", "#E7B800", "#FC4E07"),
repel=TRUE,
title="PCA Variable Plot: Contributions to PC1-PC2")
# Individual plot (colored by contribution)
fviz_pca_ind(pca_initial, col.ind="cos2",
gradient.cols=c("#00AFBB", "#E7B800", "#FC4E07"),
repel=FALSE,
title="PCA Individual Plot")
# === STEP 6: Save Component Scores ===
component_scores <- as.data.frame(pca_result$scores)
colnames(component_scores) <- c("Internalizing", "Stress", "Fear")
cat("=== Component Scores(First 6 subjects) ===\n")
print(head(component_scores))
# These scores can be used in subsequent analyses
data_with_components <- cbind(data, component_scores)
cat("\n=== Summary ===\n")
cat("Successfully reduced 15 variables to 3 principal components\n")
cat("explaining", round(cum_var[n_components], 1), "% of total variance.\n")
cat("Components represent: Internalizing, Stress, and Fear dimensions.\n")
cat("Component scores saved for use in predictive models.\n")KMO = 0.87 (meritorious), Bartlett's χ²(105) = 2847.3, p < .001. Three components retained via parallel analysis, explaining 68.4% of total variance. PC1 (Internalizing, 38.2%) loads on depression and general anxiety. PC2 (Stress, 18.7%) loads on stress-tension symptoms. PC3 (Fear, 11.5%) loads on panic-fear symptoms. All communalities >0.50. Successfully reduced 15 variables to 3 interpretable dimensions suitable for predictive modeling.
Alternatives
Structured fallback pathways for choosing alternative tests when normality or slopes requirements fail.
- Kernel PCA — Map the data into high-D space to capture curved feature architectures.
- Multidimensional Scaling (MDS) — Prioritize 'Distances' rather than 'Variance' if the grid is non-linear.
- Canonical Correlation — Focus on the relationship between two specific sets of variables rather than global reduction.
- Item Elimination Audit — Prune markers with low commonality to strengthen the signal.
- Bootstrap PCA Strike — Resample the matrix 1,000 times to verify the stability of your component identities.
Post-hoc
Group mean comparisons and correction controls (e.g. Tukey HSD, Bonferroni) to protect against Family-Wise Error Rates.
- Compare different rotation methods (varimax, oblimin, promax)
- Assess stability using bootstrap or cross-validation
- Compare Kaiser criterion vs scree plot vs parallel analysis for component retention
- Examine factor congruence across subsamples
- Test alternative extraction methods (principal axis, maximum likelihood)
PCA is an exploratory technique for dimension reduction, not hypothesis testing. Traditional post-hoc tests are not applicable.
Effect Size
Understanding effect sizes (e.g., Cohen's d, Partial Eta-Squared) and clinical impact benchmarks.
60-70% explained considered good for social sciences; 80%+ excellent for physical sciences. Higher indicates components capture most information
Kaiser criterion: retain components with λ > 1.0. Each component should explain more variance than single original variable
Magnitude of variable-component relationship. |loading| > .70 excellent, .60-.70 good, .50-.60 fair, .40-.50 marginal, <.40 poor. Loadings² = variance explained
0.2
0.5
0.8
Sample Size
Guidelines for minimum sample requirements and power analysis parameters.
The '5:1 Ratio' Minimum: A minimum of 5 participants per original variable is the absolute floor. Data reduction collapse mathematically if the N-to-Feature ratio is too shallow to stabilize the correlation matrix.
| Effect Size | Parameters | Required n |
|---|---|---|
| Small Effect | Low Commonality (0.4) | n ≈ 300 |
| Medium Effect | Wide Commonality (0.6) | n ≈ 150 |
| Large Effect | High Commonality (0.8) | n ≈ 60 |
The 'Sample Density' Strike: While 5:1 is the minimum, 10:1 or 20:1 is elite. If your N is under 100, components are likely artifacts of sampling error ('Phantom Components'). Use Parallel Analysis to audit component validity.
Reporting
How to compile statistical results into publication prose matching APA and journal style guides.
Principal components analysis was conducted on N observations across p variables measuring construct. Sampling adequacy was assessed using Kaiser-Meyer-Olkin measure (KMO = X.XX, interpretation) and Bartlett's test of sphericity (χ²(df) = X.XX, p < .001), indicating correlations were adequate for PCA. Method for determining components, e.g., parallel analysis/scree plot/Kaiser criterion suggested retaining k components, which collectively explained X.X% of total variance. If rotation used: Varimax/oblimin rotation was applied to aid interpretation. Component 1 (X.X% variance) loaded strongly on variables, representing dimension name/interpretation. Component 2 (X.X% variance) loaded on variables, representing dimension. Continue for each component. Component loadings ranged from X.XX to X.XX, with all retained variables showing communalities > X.XX. Component scores were computed and used in subsequent analyses.
- KMO overall and per-variable MSA
- Bartlett's test chi-square, df, p-value
- Number of components retained and justification method
- Total variance explained (% and cumulative %)
- Eigenvalues for retained components
- Component loadings matrix (with rotation method if used)
- Communalities (h²) per variable
- Component interpretation/naming based on high-loading variables
Manuscript Lab
Copy standard summary tables and forensic reporting grids to outline analysis details.
| Item | Component 1 (Focus) | Component 2 (Speed) | h² (Communality) |
|---|---|---|---|
| Attention Span | 0.85 | 0.12 | .74 |
| Error Rate | -0.78 | 0.25 | .67 |
| Reaction Time | 0.08 | 0.82 | .68 |
| Processing Speed | 0.15 | 0.75 | .58 |
The 'Pull' Strength. Measures how strongly each item correlates with the hidden component. Higher magnitude = more representative.
Item Reliability. The percentage of the item's variance that is captured by the extracted components.
Component Volume. Represents the total amount of variance (information) captured by that specific component.
Command Center
Syntax libraries and function parameters for executing calculations in stats packages.
# 1. Execute PCA with Varimax Rotation
pca_res <- psych::principal(df_items, nfactors = 2, rotate = 'varimax')
print(pca_res)
# 2. Visualize Eigenvalues (Scree Plot)
factoextra::fviz_screeplot(pca_res)
# 3. Plot Component Loadings
factoextra::fviz_pca_var(pca_res)PCA is not just about reduction; it's about 'Noise Filtering'. Use the Kaiser-Guttman rule (Eigenvalues > 1) or Parallel Analysis to ensure you aren't extracting components from random noise.
# Execute Parallel Analysis Audit (Gold Standard for component selection)
psych::fa.parallel(df_items, n.iter = 100)Common Mistakes
Analytical caveats and corrections to maintain modeling integrity.
References
Scholarly lineage and citation keys grounding the statistical framework.