R语言主成分分析可视化实战:用FactoMineR与factoextra打造专业级图表
1. 项目概述:当主成分分析遇上高颜值可视化
主成分分析(PCA)这玩意儿,但凡做过数据分析的朋友应该都不陌生。说白了,它就是一场“数据减肥”运动,把一堆彼此可能有关联的变量,压缩成几个互不相关的“主成分”,用更少的维度抓住原始数据里最主要的“信息量”。原理教科书上都有,但真到了自己动手做的时候,很多人卡住的点往往不是算法本身,而是最后那一步:怎么把分析结果清晰、美观、有说服力地展示出来?
你是不是也经历过这种尴尬:辛辛苦苦跑完了PCA,结果对着R基础绘图函数plot()生成的那张灰头土脸、点线模糊的图发愁?坐标轴标签挤成一团,样本点没有分类颜色,贡献率还得自己手动算、手动标……这种图拿给同事看尚需一番口舌解释,要是放在报告或论文里,实在是有点“拿不出手”。我们做分析,不就是为了洞察和沟通么?如果结果展示得磕碜,洞察力就打了折扣。
这就是为什么“R语言主成分分析可视化”这个主题常谈常新。今天要聊的,不是基础的prcomp()加plot(),而是一套能让你瞬间产出“颜值在线、信息完整”的专业级PCA可视化方案。核心在于两个R包:FactoMineR和factoextra。前者是进行各种因子分析(包括PCA)的瑞士军刀,功能强大且稳健;后者则是专为前者量身定制的“美学大师”,能让你用极简的代码,绘制出发表级质量的图形。我将结合一个完整的案例,从数据预处理、PCA计算、到多种图形解读,把每个细节掰开揉碎讲清楚,保证你读完就能上手复现。
2. 核心工具链:FactoMineR与factoextra深度解析
工欲善其事,必先利其器。在开始实战前,我们得先摸清楚手里这两把“利器”的脾气秉性。很多初学者直接照搬代码,却不知其所以然,一旦数据或需求稍有变化,就不知如何调整了。
2.1FactoMineR:不止于PCA的多元分析工厂
FactoMineR包的核心函数是PCA()。它和R自带的prcomp()或princomp()有什么不同?简单来说,prcomp()是基础统计函数,速度快,结果简洁,但需要你自己去计算和提取很多后续分析所需的指标。而FactoMineR::PCA()是一个更面向“分析”而非单纯“计算”的函数。
它为你自动计算并打包好了几乎所有你需要的东西:
- 各主成分的方差(特征值)及贡献率:这是解读主成分重要性的基础。
- 变量在主成分上的坐标(载荷,Loading):告诉你每个原始变量对各个主成分的贡献程度。
- 个体(样本)在主成分上的坐标(得分,Score):这是绘制样本散点图的基础。
- 变量与主成分之间的相关系数(cos2,代表表征质量):这个非常有用,它表示一个变量能被某个主成分解释的程度,值越接近1,说明该主成分对这个变量的代表性越好。
- 对缺失值的处理:
PCA()函数内置了处理缺失值的选项,这对于实际数据非常友好。
更重要的是,PCA()函数返回的结果是一个复杂的列表对象,里面包含了多个维度的结果数据,这些数据正是factoextra包绘图时直接调用的“原料”。你可以把它理解为一个“数据分析引擎”,不仅输出结果,还输出了丰富的元数据。
2.2factoextra:基于ggplot2的优雅可视化层
如果说FactoMineR生产了高质量的“数据原料”,那么factoextra就是一位顶级的“数据厨师”,擅长将这些原料烹制成色香味俱全的菜肴。这个包的核心价值在于:
- 语法统一且简洁:它提供了一系列以
fviz_开头的函数(如fviz_pca_ind,fviz_pca_var),你只需要传入PCA()函数的结果对象,就能生成对应的图形,无需手动提取坐标、计算贡献率。 - 默认美学出众:它基于强大的
ggplot2图形系统,默认的颜色、主题、字体都非常协调,直接输出就很有专业感。 - 信息集成度高:图形会自动在坐标轴上标注方差贡献率(如“Dim1 (58.3%)”),省去你手动计算和添加文本的麻烦。
- 高度可定制:由于底层是
ggplot2,你可以通过熟悉的+号语法,轻松添加图层、修改主题、调整颜色标度等,实现完全个性化的定制。
一个关键的心得:factoextra绘制的图形对象,本质上就是一个ggplot对象。这意味着你可以用所有ggplot2的知识去修饰它。比如,用labs()改标题,用theme_minimal()换主题,用scale_color_brewer()换配色方案。这给了你从“能用”到“好看”再到“独具风格”的无限可能。
3. 完整实战:从数据到高颜值分析报告
理论说再多不如动手做一遍。我们用一个经典的鸢尾花(iris)数据集来演示全过程。这个数据集包含150个样本,4个数值特征(花萼和花瓣的长宽),以及1个分类标签(鸢尾花品种:Setosa, Versicolor, Virginica)。我们的目标是:用PCA探索这4个特征如何区分3个品种,并制作一整套可视化图表。
3.1 数据准备与预处理
首先,加载必要的包并查看数据。记住,PCA通常针对数值变量,分类标签用于后续的样本着色和解读。
# 安装并加载包 # install.packages(c("FactoMineR", "factoextra", "ggplot2")) library(FactoMineR) library(factoextra) library(ggplot2) # 查看数据 data(iris) head(iris) summary(iris)关键预处理步骤:标准化。这是PCA分析前至关重要的一步。因为我们的4个特征(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width)量纲相同(都是厘米),但数值范围差异很大(花瓣长度比花萼宽度大得多)。如果不标准化,PCA会倾向于让方差大的特征(如Petal.Length)主导主成分,这可能会掩盖其他特征的真实贡献。
FactoMineR::PCA()函数通过scale.unit = TRUE参数(默认即为TRUE)来自动完成这一过程,即对每个变量进行中心化并缩放到单位方差(z-score标准化)。
# 进行PCA分析。注意,我们只使用前4列数值变量。 iris.pca <- PCA(iris[, 1:4], scale.unit = TRUE, graph = FALSE) # graph = FALSE 表示先不自动绘图,我们要用factoextra精细控制。运行后,iris.pca对象就包含了所有分析结果。我们可以先用summary()或print()快速浏览一下特征值(方差)。
3.2 核心结果解读:方差、贡献与累积贡献
PCA做完,第一件事是看每个主成分“携带”了多少信息。这通过特征值(Eigenvalue)或方差(Variance)来解释。通常,我们会关注前两个或前三个主成分。
# 提取特征值(方差) eig.val <- get_eigenvalue(iris.pca) print(eig.val)输出可能类似这样:
eigenvalue variance.percent cumulative.variance.percent Dim.1 2.918 72.962% 72.96% Dim.2 0.914 22.851% 95.81% Dim.3 0.147 3.668% 99.48% Dim.4 0.021 0.522% 100.00%解读:
- 第一主成分(Dim1):解释了总方差的约73.0%,是绝对的主力。这意味着仅用这一个维度,就能捕捉到原始4个特征中近四分之三的信息。
- 第二主成分(Dim2):解释了约22.9%的方差。前两个主成分加起来(累积贡献率)达到了95.8%,这意味着我们用一个二维平面(PC1 vs PC2)来展示数据,已经能保留超过95%的原始信息,信息损失极小。这是一个非常理想的结果,也决定了我们后续的可视化将重点放在PC1和PC2构成的平面上。
- 第三、四主成分贡献率很小,在实际分析中往往可以忽略。
可视化特征值/方差(碎石图): 碎石图能直观地帮助决定保留几个主成分。通常我们寻找“拐点”,即特征值下降趋势突然变缓的那个点之前的主成分都值得保留。
fviz_eig(iris.pca, addlabels = TRUE, ylim = c(0, 80))这张图会清晰地显示,从Dim1到Dim2有一个陡降,之后趋于平缓,再次印证保留前两个主成分是合理的。
3.3 颜值担当一:变量相关图与载荷图
接下来,我们要看原始的4个特征(变量)与主成分之间的关系。这能告诉我们每个主成分的“实际含义”。
# 绘制变量图 var.plot <- fviz_pca_var(iris.pca, col.var = "cos2", # 用cos2值着色,表示变量与主成分的相关性质量 gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE, # 避免文本标签重叠,非常重要! title = "Variables - PCA") print(var.plot)这张图蕴含了丰富信息:
- 箭头方向:表示变量在该二维平面上的投影方向。例如,
Petal.Length和Petal.Width的箭头指向非常接近且都指向PC1的正方向,说明它们高度相关,且都对PC1有很强的正向贡献。 - 箭头长度:代表变量在该平面上的表征质量。箭头越长,说明这个变量在前两个主成分构成的平面上被表达得越好(cos2值越高)。图中所有箭头都很长,说明4个变量在这个二维视图里都得到了很好的体现。
- 颜色深浅:由
col.var = "cos2"控制,颜色越暖(红),代表该变量在前两个主成分上的总cos2值越高,即被这两个维度解释得越好。 - 夹角:两个变量箭头之间的夹角余弦值,近似等于它们的相关系数。锐角表示正相关(如花瓣长和宽),钝角表示负相关,直角表示几乎不相关。
注意:
repel = TRUE参数在此类图中几乎是必选项。它能智能地调整文本标签的位置,防止重叠,让图变得清晰可读。如果标签还是重叠,可以尝试调整图形尺寸或字体大小。
我们还可以单独查看每个变量对各个主成分的贡献度条形图:
# 变量对PC1的贡献度 fviz_contrib(iris.pca, choice = "var", axes = 1) # 变量对PC2的贡献度 fviz_contrib(iris.pca, choice = "var", axes = 2)这些图能定量地告诉我们,例如,Petal.Length对第一主成分的贡献度超过了40%,是定义PC1的最重要变量。
3.4 颜值担当二:样本散点图与分组着色
这是最常用、最直观的图,用于观察样本(这里是150朵花)在降维空间中的分布情况。
# 基本样本散点图 ind.plot <- fviz_pca_ind(iris.pca, geom = "point", # 只显示点 title = "Individuals - PCA") print(ind.plot)但这张图上的点都是黑色的,我们看不出它们属于哪个品种。接下来就是展示factoextra强大之处的时候:利用分类标签进行着色和分面。
# 按品种着色,并添加浓度椭圆 ind.plot.group <- fviz_pca_ind(iris.pca, geom = "point", col.ind = iris$Species, # 按品种着色 palette = "jco", # 使用Journal of Clinical Oncology配色 addEllipses = TRUE, # 添加分组浓度椭圆 ellipse.type = "confidence", # 置信椭圆 legend.title = "Species", title = "PCA - Iris Dataset", repel = TRUE) # 为可能的标签防重叠 print(ind.plot.group)这张图立刻变得信息量巨大且美观:
- 清晰的分群:三个品种的样本点形成了三个明显分离的簇。Setosa(通常显示为蓝色)完全独立于其他两类,且沿PC1负方向分布。Versicolor和Virginica在PC2方向上有所区分。
- 浓度椭圆:
addEllipses = TRUE为每个组添加了一个椭圆,默认为95%的置信椭圆。它直观地展示了每个组样本点的分布范围和中心。椭圆重叠越小,说明组间区分度越高。这里Setosa的椭圆与其他两个完全分离,而Versicolor和Virginica的椭圆有少量重叠,说明这两个品种在某些特征上比较接近。 - 专业配色:
palette = "jco"提供了专业出版物常用的配色方案,瞬间提升图形档次。
更进一步,我们可以制作分面图,更清晰地观察每个组:
fviz_pca_ind(iris.pca, geom = "point", col.ind = iris$Species, palette = "jco", addEllipses = TRUE, ellipse.type = "confidence", legend.title = "Species", title = "PCA - Iris Dataset (Faceted)", repel = TRUE) + facet_wrap(~ iris$Species) # 使用ggplot2的分面功能3.5 颜值担当三:双标图
双标图是变量图和样本图的叠加,能在一张图上同时观察变量和样本的关系,是解读PCA结果的“神器”。
biplot <- fviz_pca_biplot(iris.pca, col.ind = iris$Species, palette = "jco", addEllipses = TRUE, ellipse.type = "confidence", col.var = "black", # 变量箭头设为黑色 alpha.var = "cos2", # 根据cos2设置箭头透明度 gradient.cols = NULL, legend.title = "Species", title = "PCA Biplot - Iris Dataset", repel = TRUE) print(biplot)如何解读双标图?
- 样本点与变量的相对位置:如果一个样本点落在某个变量箭头的正方向上,且距离原点较远,那么这个样本在该变量上的取值很可能高于平均水平。例如,大部分Virginica品种的花都落在
Petal.Length和Petal.Width箭头所指的方向上,说明Virginica的花瓣普遍较长较宽。 - 变量箭头之间的夹角:和变量图一样,反映相关性。
- 样本点的聚集:反映样本的相似性。
在双标图中,为了清晰,有时需要调整变量箭头的长度,避免箭头过长干扰样本点的观察。这可以通过fviz_pca_biplot()中的select.var参数或对结果进行缩放来实现,但通常默认设置已足够好。
4. 高级定制与美化技巧
默认图形已经很好,但如果你想投稿论文或者做一份精美的报告,可能还需要一些定制。因为fviz_*函数返回的是ggplot对象,所以一切ggplot2的魔法都适用。
4.1 自定义主题与标签
final_plot <- fviz_pca_biplot(iris.pca, col.ind = iris$Species, palette = c("#00AFBB", "#E7B800", "#FC4E07"), # 自定义颜色 addEllipses = TRUE, ellipse.level = 0.95, # 置信水平 col.var = "darkred", alpha.var = 0.6, label = "var", # 只显示变量标签,不显示样本标签(避免拥挤) legend.title = "Iris Species", repel = TRUE) + # 以下是ggplot2定制层 labs(title = "Principal Component Analysis of Iris Morphology", subtitle = "Visualizing separation of three iris species based on sepal and petal dimensions", caption = "Data: Fisher's Iris dataset | PCA performed using FactoMineR") + theme_minimal(base_size = 12) + # 更换为简约主题,增大基础字体 theme(legend.position = "bottom", # 图例放到底部 plot.title = element_text(hjust = 0.5, face = "bold"), # 标题居中加粗 plot.subtitle = element_text(hjust = 0.5, color = "grey40"), panel.grid.minor = element_blank()) # 去掉次要网格线 print(final_plot) # 保存为高清图片 ggsave("iris_pca_biplot_high_quality.png", final_plot, width = 10, height = 8, dpi = 300)4.2 处理更大规模的数据集
当样本量成千上万时,在散点图上绘制所有点会导致“墨水渍”效应,一片黑,什么也看不清。这时可以:
- 使用半透明色:
geom = "point", alpha.ind = 0.5让点半透明,重叠区域颜色会加深。 - 采样显示:先对数据进行随机采样再绘图,用于快速观察模式。
- 只显示椭圆和中心:
geom = c("point", "text")可以改为只显示组的中心点("point")和组标签("text"),或者仅显示椭圆。
# 示例:使用半透明点 fviz_pca_ind(large_data.pca, geom = "point", alpha.ind = 0.3, col.ind = "blue")5. 常见问题与排查实录
在实际操作中,你可能会遇到下面这些问题,这里是我的踩坑记录和解决方案。
问题1:运行PCA()或fviz_*函数时报错 “object ‘xxx’ not found”。
- 原因:最常见的原因是包没有正确加载,或者函数名拼写错误。
FactoMineR和factoextra的函数名区分大小写且常有下划线。 - 解决:确保已用
library()正确加载包。FactoMineR的主函数是PCA()(大写),而factoextra的绘图函数是fviz_pca_ind等。仔细检查拼写。
问题2:图形中的文本标签严重重叠,即使设置了repel = TRUE也没用。
- 原因:数据点或变量太多、太密集,或者图形输出区域太小。
- 解决:
- 增大图形输出的尺寸。在RStudio中,拖动绘图面板;使用
ggsave()时增加width和height参数。 - 调整
repel的力导参数(需直接操作ggplot2,较复杂)。一个更简单的方法是:在fviz_pca_var()或fviz_pca_ind()中设置label = "none"先不显示标签,然后用select.var或select.ind参数选择最重要的几个变量或样本进行标注。 - 对于变量图,可以尝试
fviz_pca_var(..., labelsize = 4)调小标签字体。
- 增大图形输出的尺寸。在RStudio中,拖动绘图面板;使用
问题3:我想用其他颜色方案,但不知道palette参数能填什么。
- 解决:
factoextra内置支持一些好看的调色板,如"npg","aaas","jco","lancet","ucscgb"等(这些都是ggsci包中的科学期刊配色)。你也可以直接传递一个颜色向量,如palette = c("#E69F00", "#56B4E9", "#009E73")。对于连续型变量着色(如cos2),则使用gradient.cols参数。
问题4:PCA结果中前两个主成分的累积贡献率很低(比如只有60%),我还能用二维图吗?
- 原因:这说明数据内在结构比较复杂,两个维度不足以概括大部分信息。
- 解决:二维图仍然可以看,但必须谨慎解读,并明确告知读者信息损失较大。你需要:
- 考虑绘制三维散点图(可以用
plotly包交互查看)。 - 在报告中同时展示第三、第四主成分的相关图表(如PC1 vs PC3, PC2 vs PC3)。
- 重点结合碎石图,说明选择观察某几个主成分的理由。
- 考虑绘制三维散点图(可以用
问题5:如何将新数据投影到已有的PCA空间上?
- 场景:你已用训练集数据建立了PCA模型,现在有一批新的测试集数据,想看看它们在现有PCA空间中的位置。
- 解决:
FactoMineR的PCA()函数主要用于一次性分析。对于这种预测场景,更标准的做法是使用stats::prcomp(),因为它有predict()方法。
# 假设 train_data 是训练集, test_data 是新数据(需与训练集同尺度) pca_model <- prcomp(train_data, center = TRUE, scale. = TRUE) train_scores <- pca_model$x # 训练集得分 test_scores <- predict(pca_model, newdata = test_data) # 新数据得分 # 然后你可以用ggplot2手动绘制,将train_scores和test_scores画在一起,用不同形状或颜色区分。主成分分析本身是一个强大的数学工具,而FactoMineR和factoextra这一组合,则让它从枯燥的数字表格,变成了直观、生动、具有说服力的视觉故事。这套流程不仅适用于鸢尾花数据,更可以无缝迁移到你的基因表达数据、客户消费数据、工业传感器数据等任何多维数据集上。核心在于理解每一步输出的含义,并熟练运用图形语法将你想强调的信息凸显出来。记住,好的可视化,是分析工作从“完成”到“出色”的关键一跃。