R语言PCA可视化实战:用ggplot2为鸢尾花数据绘制精美置信椭圆
鸢尾花数据集作为统计学和机器学习领域的经典案例,常被用于演示分类算法和降维技术。主成分分析(PCA)能有效提取数据关键特征,而置信椭圆则直观展示不同类别数据的分布范围。本文将手把手教你如何用R语言的ggplot2包,为鸢尾花PCA结果添加专业级置信椭圆。
1. 环境准备与数据加载
在开始之前,确保已安装必要的R包。如果尚未安装,可以通过以下命令获取:
install.packages(c("ggplot2", "dplyr"))加载所需库并查看数据概览:
library(ggplot2) library(dplyr) head(iris)鸢尾花数据集包含150个样本,每个样本有4个特征(萼片长度、萼片宽度、花瓣长度、花瓣宽度)和1个分类标签(setosa、versicolor、virginica)。我们将使用前4个数值型变量进行PCA分析。
2. 主成分分析实现
R语言提供了多个PCA函数,最常用的是prcomp()和princomp()。两者计算原理相似,但输出格式略有不同。这里我们使用prcomp():
# 执行PCA分析 pca_result <- prcomp(iris[, 1:4], scale. = TRUE) # 查看PCA结果摘要 summary(pca_result)提示:
scale.=TRUE参数会对数据进行标准化处理,消除不同特征量纲的影响,这在变量单位不一致时尤为重要。
PCA结果中,sdev表示各主成分的标准差,rotation是特征向量(载荷矩阵),x则是转换后的主成分得分。我们可以提取前两个主成分用于可视化:
# 创建包含主成分得分和原始分类的数据框 pca_data <- data.frame( PC1 = pca_result$x[, 1], PC2 = pca_result$x[, 2], Species = iris$Species )3. 基础PCA可视化
在添加置信椭圆前,先绘制基本的PCA散点图:
# 计算各主成分的方差贡献率 var_exp <- pca_result$sdev^2 / sum(pca_result$sdev^2) ggplot(pca_data, aes(x = PC1, y = PC2, color = Species)) + geom_point(size = 3) + labs( x = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), y = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)"), title = "鸢尾花数据集PCA分析" ) + theme_minimal()这段代码会生成一个彩色散点图,不同颜色的点代表不同鸢尾花品种。x轴和y轴标签自动包含了各主成分解释的方差百分比。
4. 置信椭圆绘制详解
ggplot2的stat_ellipse()函数可以方便地添加置信椭圆。该函数有几个关键参数需要理解:
type:指定椭圆计算的统计假设
"norm":基于多元正态分布(默认)"t":基于多元t分布(更保守)
level:置信水平,默认为0.95(即95%置信区间)
geom:指定椭圆的表现形式
"path":仅绘制椭圆轮廓"polygon":填充椭圆区域
4.1 基本置信椭圆实现
为每个品种添加95%置信椭圆(填充效果):
ggplot(pca_data, aes(x = PC1, y = PC2, color = Species)) + stat_ellipse( aes(fill = Species), type = "norm", geom = "polygon", alpha = 0.2, level = 0.95 ) + geom_point(size = 3) + labs( x = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), y = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)") ) + theme_minimal()4.2 椭圆样式自定义
通过调整参数,可以创建不同风格的置信椭圆:
ggplot(pca_data, aes(x = PC1, y = PC2, color = Species)) + stat_ellipse( aes(fill = Species), type = "t", # 使用t分布假设 geom = "polygon", alpha = 0.1, level = 0.99, # 99%置信区间 linetype = 2, # 虚线边框 size = 0.5 # 边框线粗细 ) + geom_point(size = 3, alpha = 0.8) + scale_fill_brewer(palette = "Set1") + scale_color_brewer(palette = "Set1") + labs( x = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), y = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)"), title = "鸢尾花PCA分析(99%置信区间)" ) + theme_bw()5. 高级美化技巧
5.1 分面显示
当类别较多或重叠严重时,可以使用分面(facet)功能:
ggplot(pca_data, aes(x = PC1, y = PC2, color = Species)) + stat_ellipse( aes(fill = Species), type = "norm", geom = "polygon", alpha = 0.2 ) + geom_point(size = 2) + facet_wrap(~Species) + labs( x = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), y = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)") ) + theme_minimal() + theme(legend.position = "none") # 移除图例5.2 添加密度等高线
结合geom_density_2d()可以进一步增强可视化效果:
ggplot(pca_data, aes(x = PC1, y = PC2, color = Species)) + stat_ellipse( aes(fill = Species), type = "norm", geom = "polygon", alpha = 0.1 ) + geom_density_2d(alpha = 0.5, size = 0.5) + geom_point(size = 2, alpha = 0.7) + labs( x = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), y = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)") ) + theme_minimal()5.3 保存高质量图片
使用ggsave()保存适合发表的图片:
final_plot <- ggplot(pca_data, aes(x = PC1, y = PC2, color = Species)) + stat_ellipse( aes(fill = Species), type = "norm", geom = "polygon", alpha = 0.2 ) + geom_point(size = 3) + labs( x = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), y = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)") ) + theme_minimal() ggsave("iris_pca_ellipse.png", final_plot, width = 8, height = 6, dpi = 300)6. 实际应用中的注意事项
数据标准化:PCA对变量的尺度敏感,确保使用
scale.=TRUE或提前标准化数据置信水平选择:
- 科研论文常用95%置信水平
- 更严格的场景可使用99%
- 探索性分析可降低至90%
分布假设选择:
- 数据接近正态分布时使用
type="norm" - 存在离群值时考虑
type="t"
- 数据接近正态分布时使用
类别重叠解读:
- 椭圆重叠度高表明类别区分度低
- 完全分离的椭圆表示类别特征差异明显
高维数据扩展:
- 对于更高维数据,可考虑绘制PC1-PC3等组合
- 使用3D散点图展示多主成分关系
# 示例:3D PCA绘图(需要rgl包) library(rgl) plot3d( x = pca_data$PC1, y = pca_data$PC2, z = pca_result$x[, 3], col = as.numeric(pca_data$Species), size = 5, xlab = paste0("PC1 (", round(var_exp[1] * 100, 1), "%)"), ylab = paste0("PC2 (", round(var_exp[2] * 100, 1), "%)"), zlab = paste0("PC3 (", round(var_exp[3] * 100, 1), "%)") ) legend3d("topright", legend = levels(pca_data$Species), pch = 16, col = 1:3, cex = 1)