R语言主成分分析PCA实战:从数据准备到factoextra可视化避坑指南
简介这份PDF学习笔记面向R语言数据分析初学者与需要掌握降维技术的科研人员系统讲解主成分分析PCA的原理与factoextra包可视化实践。内容从PCA正交变换、方差贡献率排序等基础概念切入逐步过渡到prcomp()函数建模、变量与样本得分图绘制、置信椭圆分组展示以及基于累积方差百分比确定主成分保留数量等关键环节帮助读者理解如何用PCA探索高维数据结构、识别变量相关模式并为后续建模做预处理。资源包为1个PDF文件大小约134.09MB图文并茂地呈现了完整的分析流程与可视化结果。目前已有1549人学习适合希望快速上手R语言PCA分析、对照代码与图形理解降维逻辑的读者参考。1. 主成分分析为什么总在“降维之后”翻车很多人第一次跑 R 语言主成分分析PCA都是被同一类需求推着走的手头有几十列甚至上百列数值变量样本量却只有几十个画散点图看不出结构做聚类又不知道拿哪几列当输入。PCA 看起来是标准答案——把高维数据压到两三个主成分上再画个图好像结构就出来了。但真正上手之后翻车点往往不在prcomp()那一行而在前后两端前面是数据里混进了不该进的列、量纲没统一、缺失值没处理后面是载荷图、贡献度图、双标图各画各的最后没人能说清这两个主成分到底代表什么。这篇笔记锁定的就是这条链路用 R 做 PCA再用 factoextra 把结果可视化到能直接放进分析报告的程度。它适合两类人一类是刚接触多元统计、需要一套能照着敲的流程的新手另一类是用过 PCA 但每次都在“解释主成分含义”这一步卡住的熟手。下面按“数据准备 → 计算 → 可视化 → 排错 → 进阶”的顺序推每一步都落到具体函数和参数上不绕概念。2. 从原始表到可分析的数值矩阵PCA 输入到底怎么准备PCA 在数学上只认一件事一个数值矩阵行是样本列是变量不能有缺失不能有非数值列。听起来简单但实际数据表里常见的坑是第一列是样本编号中间夹着分组标签后面还有一列备注。直接丢给prcomp()要么报错要么把编号当成一个变量算进去主成分方向直接被带偏。2.1 选列、去缺失、统一量纲的三步处理我一般会先把数据读进来然后显式地只保留数值型变量。下面这段代码用一个模拟的基因表达矩阵演示实际换成自己的数据时把列名替换掉即可。# 读入数据第一列假设是样本名 raw - read.csv(expr_data.csv, row.names 1, check.names FALSE) # 只保留数值列去掉分组标签、备注等非数值列 num_cols - sapply(raw, is.numeric) dat - raw[, num_cols] # 检查缺失值PCA 对 NA 零容忍 if (any(is.na(dat))) { # 方案一按行删除样本少时慎用 dat - na.omit(dat) # 方案二用列均值填补适合缺失比例低于 5% 的情况 # dat[] - lapply(dat, function(x) ifelse(is.na(x), mean(x, na.rm TRUE), x)) } # 检查零方差列方差为 0 的变量对主成分没有贡献还会导致缩放报错 zero_var - sapply(dat, function(x) var(x) 0) if (any(zero_var)) { dat - dat[, !zero_var] } # 标准化PCA 默认对中心化敏感对量纲更敏感 dat_scaled - scale(dat, center TRUE, scale TRUE)这段代码里三个判断点值得说清楚。第一is.numeric过滤是必须的因为prcomp()遇到字符列会直接报 “non-numeric argument”而很多人以为是数据格式问题其实是选列没做。第二缺失值处理没有万能解样本量小于 50 时按行删除可能直接删掉一半样本这时候均值填补更稳但要在报告里注明。第三scale()的scale TRUE做的是除以标准差不是简单除以最大值这一步决定了后面载荷能不能横向比较。2.2 标准化与否一个被低估的选型分叉PCA 之前要不要标准化取决于变量的量纲是否一致。如果所有列都是同一类测量比如都是表达量、都是浓度量纲相同可以只中心化不缩放如果列里既有身高厘米又有体重千克不标准化的话体重的方差会主导第一主成分图看起来“有结构”其实只是量纲大的变量在说话。判断方法很直接算一下各列的标准差如果最大值和最小值差一个数量级以上就标准化。下面这行可以快速看# 查看各列标准差判断是否需要 scale round(apply(dat, 2, sd), 2)如果输出里出现 0.01 和 200 这种跨度别犹豫scale TRUE。反过来如果所有列标准差都在同一量级标准化反而会放大噪声变量的影响这时候用scale FALSE更贴近原始结构。这个分叉没有标准答案但选错了后面所有图都白画。3. 用 prcomp 跑通 PCA中心化、缩放与主成分个数数据准备好之后计算本身只有一行但这一行里的参数决定了后面能解释什么。R 里做 PCA 有两个常用函数prcomp()和princomp()。前者用奇异值分解数值稳定性更好也是 factoextra 默认支持的接口后者用特征值分解对样本量小于变量数的情况容易出问题。所以下面统一用prcomp()。3.1 prcomp 的核心参数与返回值结构# 运行 PCAcenter 和 scale 已在数据准备阶段处理这里显式声明 pca_res - prcomp(dat_scaled, center FALSE, scale. FALSE) # 查看主成分的标准差即特征值的平方根 pca_res$sdev # 查看方差贡献比例 var_explained - (pca_res$sdev^2) / sum(pca_res$sdev^2) round(var_explained * 100, 2) # 查看载荷矩阵变量与主成分的相关系数 head(pca_res$rotation[, 1:3]) # 查看样本得分每个样本在主成分上的坐标 head(pca_res$x[, 1:3])这里有个容易混淆的点prcomp()的center和scale.参数如果设为TRUE函数内部会再做一次中心化和缩放。如果前面已经用scale()处理过这里就设FALSE否则等于缩放两次结果虽然方向不变但方差贡献比例会变解释时容易对不上。我一般习惯在prcomp()里直接写center TRUE, scale. TRUE把标准化和 PCA 一步做完少一次中间变量。返回值里最需要关注的是sdev、rotation和x。sdev的平方就是每个主成分的方差除以总和就是贡献率rotation是载荷矩阵行是原始变量列是主成分数值表示该变量在该主成分上的权重x是样本得分也就是把原始数据投影到主成分空间后的坐标后面画散点图用的就是它。3.2 保留几个主成分三种判断依据的取舍主成分个数不是越多越好也不是固定取两个。常见做法有三种累计贡献率超过 80%、特征值大于 1Kaiser 准则、看碎石图的拐点。三种方法结果不一致时我一般以累计贡献率为主碎石图辅助。# 方法一累计贡献率 cum_var - cumsum(var_explained) which(cum_var 0.8)[1] # 第一个达到 80% 的主成分序号 # 方法二特征值大于 1 eig - pca_res$sdev^2 sum(eig 1) # 方法三碎石图拐点用 factoextra 画 library(factoextra) fviz_eig(pca_res, addlabels TRUE, ylim c(0, 50))fviz_eig()画出来的碎石图里拐点通常出现在贡献率下降明显变缓的位置。如果前两个主成分贡献率加起来不到 50%说明数据本身维度分散强行用二维图解释会丢太多信息这时候要么增加主成分个数要么回头检查变量选择是否合理。这一步的判断直接决定后面双标图能不能用别跳过。4. factoextra 可视化把载荷、得分和贡献度画成能读的图factoextra 的价值在于它把 PCA 结果里最常看的几张图封装成了统一接口不用自己拼ggplot2图层。但封装带来便利的同时也隐藏了参数不搞清楚每个图对应哪个矩阵很容易画出“好看但没信息”的图。4.1 变量图、样本图与双标图的对应关系# 变量图展示原始变量在主成分平面上的方向 fviz_pca_var(pca_res, col.var contrib, # 按贡献度着色 gradient.cols c(#00AFBB, #E7B800, #FC4E07), repel TRUE) # 避免标签重叠 # 样本图展示样本在主成分平面上的分布 fviz_pca_ind(pca_res, col.ind cos2, # 按质量着色 gradient.cols c(#00AFBB, #E7B800, #FC4E07), repel TRUE) # 双标图变量和样本叠加 fviz_pca_biplot(pca_res, col.var red, col.ind steelblue, repel TRUE, label var)这三张图对应三个不同的矩阵变量图用的是rotation样本图用的是x双标图是两者叠加。col.var contrib表示按变量对主成分的贡献度着色贡献度越高的变量颜色越暖col.ind cos2表示按样本在平面上的质量着色cos2 越接近 1说明该样本在这个平面上表示得越充分。repel TRUE是实用参数不加的话标签会叠成一团。双标图有个常见误用把变量箭头和样本点画在同一张图上然后直接说“样本 A 靠近变量 B所以 A 的 B 值高”。这个推断只在箭头长度接近 1 且样本 cos2 较高时成立否则箭头方向会被压缩读出来的关系是失真的。稳妥做法是双标图只看整体趋势具体关系回到变量图和样本图分别确认。4.2 贡献度图与 cos2 图判断变量和样本质量的量化依据# 变量对前两个主成分的贡献度 fviz_contrib(pca_res, choice var, axes 1:2, top 10) # 样本对前两个主成分的贡献度 fviz_contrib(pca_res, choice ind, axes 1:2, top 10) # 变量的 cos2 图衡量变量在平面上的表示质量 fviz_cos2(pca_res, choice var, axes 1:2)fviz_contrib()里的axes 1:2表示同时看第一和第二主成分top 10只显示贡献最高的 10 个变量。贡献度的计算方式是变量在某个主成分上的载荷平方除以该主成分的特征值再乘以 100。如果某个变量在两个主成分上的贡献都低于阈值通常看是否低于平均贡献即 1/变量数说明它在这张图上基本没起作用可以考虑从解释里剔除。fviz_cos2()画的是变量在指定主成分平面上的 cos2 值cos2 越高变量越靠近相关圆方向越可信。如果某个变量的 cos2 很低它的箭头即使看起来指向某个方向也不要在报告里下结论。这两张图配合使用能避免“只看双标图就下结论”的常见错误。5. PCA 实操避坑从报错到图读错的 5 个排查点PCA 的坑大多不在计算本身而在数据状态和结果解释上。下面这 5 条是我自己踩过或者帮别人排查时反复遇到的按“现象 → 原因 → 解决”写清楚。5.1 报错 “non-numeric argument” 或结果里混入编号列现象运行prcomp()直接报错或者结果里第一主成分被样本编号主导。原因数据框里保留了字符列或数值型编号列prcomp()不会自动跳过。解决用sapply(dat, is.numeric)过滤或者显式用列名选择比如dat[, c(var1,var2,var3)]。编号列即使转成数值也不应该进入 PCA因为它没有生物学或物理意义。5.2 第一主成分贡献率异常高但图上看不出结构现象第一主成分贡献率超过 90%但样本散点图挤成一团。原因某个变量量纲远大于其他变量且没有标准化。解决检查各列标准差如果跨度超过一个数量级在prcomp()里设scale. TRUE或者提前用scale()处理。标准化之后贡献率会重新分配图上的结构才反映变量间的相关性而不是量纲差异。5.3 双标图箭头方向与单变量图不一致现象双标图里变量 A 指向右上但单独画变量图时 A 指向左下。原因双标图默认对变量和样本做了不同的缩放箭头长度被压缩方向在视觉上可能反转。解决以fviz_pca_var()单独画的变量图为准双标图只用于看样本和变量的整体相对位置。如果必须在双标图里读方向把label var和repel TRUE加上并确认箭头长度接近相关圆半径。5.4 样本量小于变量数时结果不稳定现象每次重新运行或稍微改动数据主成分方向变化很大。原因样本量 n 小于变量数 p 时协方差矩阵秩不足PCA 的解不唯一。解决先做变量筛选把方差接近 0 或高度相关的变量去掉或者改用正则化方法。常见做法是先用findCorrelation()去掉相关系数大于 0.9 的变量再跑 PCA。如果样本实在少考虑 PLS 或稀疏 PCA但那是另一个话题。5.5 缺失值填补后贡献率虚高现象用均值填补缺失值后某个主成分贡献率明显高于填补前。原因均值填补会人为降低变量方差同时引入人为的相关性导致主成分结构被扭曲。解决缺失比例低于 5% 时可以均值填补但要在报告中注明高于 5% 时考虑多重插补或者直接按行删除并说明样本损失。不要用 0 填补除非 0 有明确物理意义。6. 进阶用 fviz_pca_biplot 的分组参数做组间比较单组数据的 PCA 只能看整体结构真正有解释力的是分组比较。factoextra 的fviz_pca_biplot()支持按分组变量着色还能加置信椭圆这一步能把“样本有没有分开”变成可量化的视觉判断。# 假设分组信息存在 raw 的第一列且样本顺序与 dat 一致 group - raw$group fviz_pca_biplot(pca_res, col.ind group, # 按分组着色 palette c(#2E9FDF, #FC4E07, #00AFBB), addEllipses TRUE, # 加置信椭圆 ellipse.level 0.95, # 95% 置信水平 col.var grey40, # 变量箭头统一灰色 repel TRUE, label var, title PCA 分组双标图)这段代码里addEllipses TRUE和ellipse.level 0.95是关键。椭圆基于每组样本的协方差矩阵计算95% 水平表示该组样本在此平面上的分布范围。如果两组椭圆明显分离说明分组变量与主成分结构相关如果椭圆大面积重叠即使样本点看起来有分开趋势也不能下“组间差异显著”的结论。椭圆是视觉辅助不是统计检验真要检验组间差异需要做 PERMANOVA 或 adonis2那是另一套流程。另一个进阶技巧是结合fviz_pca_ind()的habillage参数把分组信息直接映射到样本点形状和颜色上同时用addEllipses TRUE看组间重叠程度。如果分组超过三组颜色区分度会下降这时候改用分面facet分别画每组比挤在一张图上更清楚。最后说一个我自己的习惯每次跑完 PCA先不看图先把summary(pca_res)打印出来确认前三个主成分的累计贡献率、各变量的载荷符号和大小。图是给人看的数字是给自己核对的。如果数字对不上直觉图再好看也别急着写结论。希望帮到你。本文还有配套的精品资源点击获取