如何在ggplot中添加PCA载荷?生成载荷后添加遇报错
PCA载荷数据框添加到ggplot的问题解决
问题背景
我用以下代码生成了PCA载荷数据框:
PCAloadings <- data.frame(Variables = rownames(pca_res_t$rotation), pca_res_t$rotation)
但无法将其通过geom_segment添加到已有的PCA散点图中,尝试两种写法均报错,具体细节如下:
原有ggplot散点图代码
ggplot(data=sep_total_raw_data, aes(x=pc1t, y=pc2t))+ geom_point(alpha=0.8, size=1,aes(colour=Data_Type, shape=Data_Type))+ xlab("PC1 (53.83%)")+ ylab("PC2 (26.3%)")+ guides(colour=guide_legend(title="Data_Type"))+ geom_mark_hull(concavity=5, expand=0, radius=0, aes(fill=Data_Type))+ theme(panel.grid = element_blank(), panel.border = element_rect(fill = "transparent"))+ geom_text(aes(label=Code, fontface="bold", colour=Data_Type))
尝试的代码及报错
尝试1
+ geom_segment(data = PCALoadings, aes(x=0,xend=xvar, y=0, yend=yvar), arrow = arrow(length = unit(0.025,"npc"),type = "open"),lwd=1)
报错:无法识别xvar和yvar
尝试2
+ geom_segment(data = PCALoadings, aes(x=0,xend=(pc1t*2), y=0, yend=(pc2t*2)), arrow = arrow(length = unit(1/2,"picas")), colour="black")
报错信息:
Error in `geom_segment()`: ! Problem while computing aesthetics. ℹ Error occurred in the 4th layer. Caused by error in `check_aesthetics()`: ! Aesthetics must be either length 1 or the same as the data (5) ✖ Fix the following mappings: `xend` and `yend` Run `rlang::last_trace()` to see where the error occurred.
可复现代码(用iris数据集模拟)
ggplot(data=iris, aes(x=Petal.Length, y=Petal.Width))+ geom_point(alpha=0.8, size=1,aes(colour=Species, shape=Species))+ xlab("Petal Length")+ ylab("Petal Width")+ guides(colour=guide_legend(title="Species"))+ geom_mark_hull(concavity=5, expand=0, radius=0, aes(fill=Species))+ theme(panel.grid = element_blank(), panel.border = element_rect(fill = "transparent"))+geom_text(aes(label=Species, fontface="bold", colour=Species))
解决方案
核心问题分析
- 尝试1的问题:
xvar和yvar不是PCAloadings数据框的实际列名,需替换为pca_res_t$rotation输出的真实列名(通常是PC1、PC2)。 - 尝试2的问题:
pc1t是主数据集sep_total_raw_data的列,而geom_segment指定了data=PCALoadings,因此无法找到该列;同时载荷值通常较小,直接映射会导致箭头显示不明显,需先缩放匹配散点图坐标范围。
修正后的代码步骤
- 确认载荷数据框列名,对载荷进行缩放:
# 计算缩放因子,匹配散点图的坐标范围 scale_factor <- max(abs(sep_total_raw_data$pc1t), abs(sep_total_raw_data$pc2t)) / max(abs(PCAloadings$PC1), abs(PCAloadings$PC2)) * 0.8 PCAloadings$PC1_scaled <- PCAloadings$PC1 * scale_factor PCAloadings$PC2_scaled <- PCAloadings$PC2 * scale_factor
- 在ggplot中添加载荷箭头:
ggplot(data=sep_total_raw_data, aes(x=pc1t, y=pc2t))+ geom_point(alpha=0.8, size=1,aes(colour=Data_Type, shape=Data_Type))+ xlab("PC1 (53.83%)")+ ylab("PC2 (26.3%)")+ guides(colour=guide_legend(title="Data_Type"))+ geom_mark_hull(concavity=5, expand=0, radius=0, aes(fill=Data_Type))+ theme(panel.grid = element_blank(), panel.border = element_rect(fill = "transparent"))+ geom_text(aes(label=Code, fontface="bold", colour=Data_Type))+ # 添加载荷箭头 geom_segment(data = PCAloadings, aes(x=0, xend=PC1_scaled, y=0, yend=PC2_scaled), arrow = arrow(length = unit(0.025, "npc"), type = "open"), lwd=1, colour="black")+ # 可选:添加载荷变量标签 geom_text(data = PCAloadings, aes(x=PC1_scaled * 1.1, y=PC2_scaled * 1.1, label=Variables), colour="black", fontface="bold")
针对iris模拟数据的完整示例
# 对iris做PCA分析 iris_pca <- prcomp(iris[,1:4], scale.=TRUE) # 生成载荷数据框 iris_loadings <- data.frame(Variables = rownames(iris_pca$rotation), iris_pca$rotation) # 生成PCA得分数据 iris_scores <- as.data.frame(iris_pca$x) iris_scores$Species <- iris$Species # 缩放载荷 scale_factor <- max(abs(iris_scores$PC1), abs(iris_scores$PC2)) / max(abs(iris_loadings$PC1), abs(iris_loadings$PC2)) * 0.8 iris_loadings$PC1_scaled <- iris_loadings$PC1 * scale_factor iris_loadings$PC2_scaled <- iris_loadings$PC2 * scale_factor # 绘制带载荷箭头的PCA图 ggplot(data=iris_scores, aes(x=PC1, y=PC2))+ geom_point(alpha=0.8, size=1,aes(colour=Species, shape=Species))+ xlab(paste0("PC1 (", round(iris_pca$sdev[1]^2/sum(iris_pca$sdev^2)*100,2),"%)"))+ ylab(paste0("PC2 (", round(iris_pca$sdev[2]^2/sum(iris_pca$sdev^2)*100,2),"%)"))+ guides(colour=guide_legend(title="Species"))+ geom_mark_hull(concavity=5, expand=0, radius=0, aes(fill=Species))+ theme(panel.grid = element_blank(), panel.border = element_rect(fill = "transparent"))+ geom_text(aes(label=Species, fontface="bold", colour=Species))+ geom_segment(data = iris_loadings, aes(x=0, xend=PC1_scaled, y=0, yend=PC2_scaled), arrow = arrow(length = unit(0.025, "npc"), type = "open"), lwd=1, colour="black")+ geom_text(data = iris_loadings, aes(x=PC1_scaled * 1.1, y=PC2_scaled * 1.1, label=Variables), colour="black", fontface="bold")
内容的提问来源于stack exchange,提问作者stakrawolf
相关产品推荐
相关产品推荐

