如何基于psych包的主成分分析结果使用ggplot2绘制双标图(Biplot)
psych::principal() Results with ggplot2/ggfortify Hey there! I totally get the frustration—ggfortify::autoplot() works great for base R PCA outputs like prcomp() or princomp(), but it doesn't have built-in support for the principal objects from the psych package. Let's walk through two solid solutions to get your biplot up and running.
Why Your Original Code Fails
The principal function from psych returns an object with a different structure than base R's PCA functions. ggfortify doesn't know how to extract scores, loadings, and variance explained from it automatically, hence the error or empty plot you're seeing.
Solution 1: Manual Biplot with ggplot2 (Full Control)
This method lets you build the biplot from scratch, giving you complete control over every element. We'll extract sample scores and variable loadings directly from the principal object, then plot them with ggplot2.
Step-by-Step Code
# Load required packages library(psych) library(ggplot2) # Load data and run PCA data("Thurstone") pca1 <- principal(Thurstone, nfactors = 2, rotate = "varimax") # Extract sample scores (each row is a sample's position on PC1/PC2) sample_scores <- as.data.frame(pca1$scores) # Extract variable loadings (each row is a variable's loading on PC1/PC2) var_loadings <- as.data.frame(unclass(pca1$loadings)) var_loadings$variable <- rownames(var_loadings) # Add variable names for labels # Build the biplot ggplot() + # Plot sample points (alpha makes them semi-transparent for readability) geom_point(data = sample_scores, aes(x = PC1, y = PC2), alpha = 0.6) + # Plot arrows for variables (scaled up by 5 to make them visible) geom_segment( data = var_loadings, aes(x = 0, y = 0, xend = PC1 * 5, yend = PC2 * 5), arrow = arrow(length = unit(0.2, "cm")), color = "darkred" ) + # Add variable labels (scaled slightly further out than arrows) geom_text( data = var_loadings, aes(x = PC1 * 5.5, y = PC2 * 5.5), label = var_loadings$variable, color = "darkred", fontface = "bold" ) + # Label axes with variance explained labs( x = paste0("PC1 (", round(pca1$Vaccounted[2], 2) * 100, "%)"), y = paste0("PC2 (", round(pca1$Vaccounted[3], 2) * 100, "%)"), title = "Biplot of Thurstone Data (PCA via psych::principal)" ) + # Clean up the theme theme_minimal()
You can adjust the scaling factor (the *5 and *5.5) to make arrows/labels more or less prominent depending on your data.
Solution 2: Convert to prcomp Class for ggfortify
If you prefer using ggfortify's built-in biplot functionality, you can convert the principal object to a prcomp-style object that autoplot() recognizes.
Step-by-Step Code
# Load required packages library(psych) library(ggfortify) # Load data and run PCA data("Thurstone") pca1 <- principal(Thurstone, nfactors = 2, rotate = "varimax") # Convert the principal object to a prcomp-compatible structure pca_prcomp <- list( x = pca1$scores, # Sample scores rotation = unclass(pca1$loadings), # Variable loadings sdev = sqrt(pca1$values), # Standard deviations of PCs center = pca1$center, # Centering values used in PCA scale = pca1$scale # Scaling values used in PCA ) class(pca_prcomp) <- "prcomp" # Assign the prcomp class # Now use autoplot as you originally tried! autoplot( pca_prcomp, loadings = TRUE, # Show variable loadings loadings.label = TRUE, # Show labels for loadings loadings.label.size = 3, # Adjust label size title = "Biplot via ggfortify (Converted to prcomp)" )
This will give you a clean biplot with minimal code, leveraging ggfortify's default styling.
Either of these methods should get you the biplot you're looking for. The manual ggplot2 approach is great if you want to customize colors, themes, or layout, while the conversion method is quick if you prefer ggfortify's out-of-the-box functionality.
内容的提问来源于stack exchange,提问作者spindoctor

