资讯动态

R语言主成分分析与因子分析:从原理到实操的降维指南

发布时间:2026/10/27 22:06:31 来源:尧图企业网站定制
做数据分析的人大概都有过这样的经历手头一张表二三十个变量相关性矩阵一画出来密密麻麻全是颜色想找出几个真正有信息量的维度靠肉眼根本看不出来。这时候主成分分析PCA和因子分析FA就成了绕不开的两把工具。我用R做这两类降维分析差不多有十来年了从最早对着prcomp的输出一脸茫然到后来能根据载荷矩阵反推变量间的隐藏结构中间踩过的坑比走过的路还多。这篇内容就是把这些年积累下来的实操经验摊开讲清楚——主成分分析和因子分析到底在做什么、R里怎么落地、参数怎么调、结果怎么读、哪些地方最容易翻车。不管你是刚接触多元统计的学生还是需要在实际项目里做降维的从业者下面这些内容都能直接拿去用。1. 先搞清楚主成分和因子分析到底在解决什么问题很多人把PCA和因子分析当成同一件事觉得都是降维随便挑一个跑就行。这个认知偏差是后面一系列误读的源头。我在早期项目里就犯过这个错拿因子分析的载荷矩阵去解释主成分得分结果怎么都对不上折腾了大半天才发现是方法选错了。1.1 两种方法的核心差异方差压缩 vs 潜变量建模主成分分析的本质是方差最大化。它把原始p个变量做线性组合生成新的正交变量主成分第一个主成分捕获最大方差第二个在与第一个正交的前提下捕获剩余最大方差依此类推。整个过程是纯几何操作不涉及任何概率模型假设。你可以把它理解成给数据换一套坐标系让信息尽量集中在前几个轴上。因子分析则不同它假设观测变量是由少数几个不可观测的潜变量公共因子加上各自的特有误差共同生成的。模型形式是 $X \Lambda F \epsilon$其中$\Lambda$是载荷矩阵$F$是公共因子$\epsilon$是特殊因子。因子分析关心的是变量之间的共同变异而不是总方差。这个差异直接决定了使用场景如果你只是想压缩维度、可视化、或者给后续模型降噪PCA更直接如果你怀疑数据背后存在某种潜在构念比如问卷里的满意度忠诚度这类无法直接测量的维度因子分析更合适。对比维度主成分分析因子分析核心目标方差最大化压缩解释变量间共同变异模型假设无概率模型潜变量线性模型输出重点主成分得分、方差贡献率载荷矩阵、共同度、因子得分旋转通常不旋转正交天然常配合旋转提升可解释性典型场景降维、可视化、去共线性量表结构验证、潜变量探索1.2 什么时候该用哪个三个判断信号实际项目里怎么选我总结出三个判断信号基本能覆盖大部分情况。信号一变量间相关性是否足够强。无论哪种方法前提都是变量之间存在足够的相关性。如果相关矩阵里大部分系数都在0.3以下做出来的主成分或因子基本没有解释力。我习惯先跑一个Bartlett球形检验和KMO检验KMO低于0.6基本就别往下做了说明数据不适合做降维。信号二你是否需要命名这些维度。如果分析目的是给维度起名字、解释其含义比如这个因子代表消费能力因子分析配合旋转更合适因为旋转后的载荷结构更清晰。如果只是要几个综合得分丢进回归模型PCA足够了。信号三样本量和变量数的比例。经验法则是样本量至少是变量数的5到10倍。因子分析对这个要求更严格因为要估计更多参数。样本量不足时PCA相对稳健一些但因子分析的解可能不稳定。提示不要因为因子分析听起来更高级就无脑选它。PCA在降维和去共线性上的表现往往更直接而且计算更稳定。方法选择应该由分析目标驱动而不是由方法的名气驱动。2. R里跑PCA从数据预处理到结果解读的完整链路R里做PCA的函数不少prcomp、princomp、FactoMineR::PCA各有特点。我日常最常用的是prcomp因为它基于奇异值分解SVD数值稳定性比princomp用的特征值分解更好尤其是在变量量纲差异大或者矩阵接近奇异的时候。2.1 预处理标准化这一步不能省PCA对变量的尺度极其敏感。举个直观的例子如果一列是收入单位元数值动辄上万另一列是满意度评分1到5不标准化的话收入这一列的方差会碾压其他所有变量第一主成分几乎完全由收入主导分析就失去意义了。标准做法是调用prcomp时设置scale. TRUE它对每列做z-score标准化。但这里有个细节很多人忽略标准化之后总方差等于变量个数p所以每个主成分的方差贡献率分母是p。如果你手动先标准化再设scale. FALSE结果一样但要确保标准化方式一致用样本标准差还是总体标准差否则贡献率会有细微偏差。# 推荐写法一步到位 pca_result - prcomp(data_matrix, center TRUE, scale. TRUE) # 查看方差贡献 summary(pca_result)summary输出的Importance of components表格里Proportion of Variance就是各主成分的方差贡献率Cumulative Proportion是累计贡献率。我通常看累计达到80%到85%需要几个主成分这个阈值不是死的 exploratory场景下70%也能接受关键看后续用途。2.2 保留几个主成分三种判据的实际取舍保留主成分个数是PCA里最需要判断力的环节。常见判据有三种我一般会交叉验证着看。Kaiser准则保留特征值大于1的主成分。这个准则在标准化数据上等价于保留方差贡献率超过1/p的主成分。它简单粗暴但在变量数很多时容易保留过多成分。我见过30个变量的数据集按这个准则保留了11个主成分实际前4个就够用了。碎石图拐点把特征值按降序画出来找曲线由陡变缓的拐点。这个方法主观性较强但配合Kaiser准则一起看比较靠谱。累计方差阈值直接设定一个累计贡献率门槛如80%。这是最实用的判据尤其在降维是为了后续建模服务时你关心的是保留多少信息够用而不是特征值是否大于1。# 碎石图 plot(pca_result, type lines, main Scree Plot) # 提取特征值 eigenvalues - pca_result$sdev^2实际项目中我的做法是先看累计方差达到80%需要几个再看碎石图拐点是否吻合最后结合业务可解释性微调。如果第5个主成分贡献率只有3%但恰好对应一个业务上很重要的变异方向保留它也是合理的——统计判据服务于业务判断不是反过来。2.3 载荷矩阵与得分怎么读才不跑偏pca_result$rotation是载荷矩阵变量在主成分上的系数pca_result$x是主成分得分样本在新坐标系下的坐标。读载荷矩阵时要注意载荷的符号没有绝对意义整体取反不改变解释只改变方向。所以看到某个主成分上所有载荷都是负的不用慌把它理解成这个方向的反向就行。解释主成分的常用方法是看每个主成分上绝对值最大的几个变量。比如第一主成分上收入教育年限职业声望载荷都很高且同号可以解释为社会经济地位综合指标。这里的关键是同号性和相对大小而不是绝对数值。# 查看前三个主成分的载荷 loadings - pca_result$rotation[, 1:3] round(loadings, 3) # 主成分得分 scores - pca_result$x[, 1:3]有个容易踩的坑prcomp默认center TRUE得分是中心化后的但如果你后续要把得分和原始数据合并记得得分矩阵的行顺序和原始数据一致只要没有删行就一致。另外predict(pca_result, newdata)可以把新样本投影到已有主成分空间这个在训练集/测试集拆分场景下很有用但要注意newdata的列顺序和训练时完全一致。3. 因子分析在R中的落地估计方法、旋转与因子数确定因子分析的R实现主要靠factanal基础包极大似然法和psych::fa支持多种估计方法。factanal够用但功能有限psych包更灵活我大部分时候用后者。3.1 估计方法的选择极大似然 vs 主轴因子psych::fa支持fm参数指定估计方法常用的有ml极大似然、pa主轴因子、minres最小残差。极大似然法有明确的统计检验似然比检验因子数是否充分但要求数据近似多元正态。主轴因子法不依赖分布假设更稳健适合偏态明显的数据。我的经验是样本量充足、数据接近正态时用ml能拿到模型拟合检验数据分布不明或样本量中等时用pa或minres结果通常更稳定。factanal只支持极大似然所以如果你需要其他方法直接上psych。library(psych) fa_result - fa(data_matrix, nfactors 3, fm pa, rotate varimax) print(fa_result, cut 0.3)cut 0.3表示只显示载荷绝对值大于0.3的项这是查看载荷矩阵的实用技巧能快速定位每个因子的主要贡献变量。3.2 旋转让因子结构变得可解释未旋转的因子解通常难以解释因为第一个因子往往承载了大量变量的共同变异。旋转的目的是让载荷矩阵呈现简单结构——每个变量尽量只在一个因子上有高载荷在其他因子上接近零。正交旋转如varimax保持因子间不相关适合你假设潜在维度彼此独立的情况。斜交旋转如promax、oblimin允许因子相关更符合社会科学中的现实——满意度和忠诚度这类构念很难完全独立。我一般先跑varimax看结构如果发现因子间相关明显psych::fa输出里的Phi矩阵再换promax。# 斜交旋转 fa_promax - fa(data_matrix, nfactors 3, fm pa, rotate promax) fa_promax$Phi # 查看因子间相关旋转不改变模型拟合优度也不改变共同度communality只改变载荷的分布方式。所以如果你发现旋转前后共同度变了那一定是哪里出错了。3.3 因子数确定平行分析比特征值准则靠谱确定因子个数是因子分析里最棘手的问题。Kaiser准则特征值大于1在因子分析里同样流行但它系统性高估因子数这个问题在变量数较多时尤其明显。我更推荐平行分析parallel analysis。它的逻辑是生成若干组随机数据维度与真实数据相同计算随机数据的特征值分布把真实数据的特征值与随机数据的平均特征值比较保留真实特征值更大的那些因子。psych::fa.parallel直接实现了这个功能。fa.parallel(data_matrix, fa fa, n.iter 100)输出会给出建议的因子数通常标注Suggested number of factors。我实测下来平行分析的建议比Kaiser准则保守更接近实际可解释的因子数。另一个辅助判据是看增加因子数后模型拟合如RMSEA、TLI是否显著改善但psych::fa的拟合指标不如结构方程模型软件全面所以平行分析仍是我首选。4. 实操中最容易翻车的几个地方前面讲的是标准流程但真实项目里出问题的地方往往不在流程本身而在一些边角细节上。这一节把我踩过的坑和见过的翻车案例整理出来都是文档里不会写的。4.1 缺失值处理不当导致结果完全失真PCA和因子分析对缺失值都没有原生支持。prcomp遇到NA会直接报错psych::fa默认也是。很多人图省事用均值填补这在缺失比例低比如低于5%且完全随机缺失时问题不大但如果缺失有系统性比如高收入群体更不愿意填收入均值填补会人为压缩方差扭曲相关结构。我的做法是缺失比例低于5%时用中位数填补比均值稳健5%到15%之间考虑多重插补mice包超过15%就要认真评估这个变量是否还值得保留。另外填补后一定要对比填补前后的相关矩阵如果相关系数变化超过0.1说明填补方式有问题。# 中位数填补示例 data_filled - data_matrix for (j in seq_len(ncol(data_filled))) { med - median(data_filled[, j], na.rm TRUE) data_filled[is.na(data_filled[, j]), j] - med }4.2 变量方向不一致让主成分解释彻底跑偏这个问题极其隐蔽。假设你在做一个消费者调研其中价格敏感度是越高越敏感而品牌偏好是越高越偏好如果这两个变量在业务逻辑上应该负相关但数据里因为量表方向设置问题呈现正相关主成分的符号和解释就会完全错乱。排查方法是看相关矩阵里是否存在理论上应该负相关却显示正相关的变量对。发现后对该变量取反用最大值加最小值减去原值或者直接乘以-1重新跑分析。这个步骤在问卷数据里尤其重要因为不同题目的计分方向经常不统一。4.3 样本量与变量数的隐性约束前面提过样本量至少是变量数的5到10倍但这里有个更细的约束因子分析中每个因子至少需要3到5个高载荷变量才能稳定识别。如果你有20个变量却想提取6个因子平均每个因子只有3个多变量解会很不稳定旋转后载荷可能在不同样本间大幅波动。判断方法是做交叉验证把样本随机分成两半各自做因子分析比较载荷矩阵的相似度。如果同一因子在两半样本里的高载荷变量集合差异很大说明因子数过多或样本量不足。psych::fa本身不做这个需要手动拆分数据跑两次对比。4.4 过度解读低载荷和交叉载荷载荷绝对值低于0.3的变量我一般不建议纳入因子解释。0.3到0.4之间的属于边缘载荷可以提及但不作为主要依据。交叉载荷一个变量在两个因子上载荷都超过0.4说明这个变量归属不清晰可能是题目设计有问题也可能是因子数不对。处理交叉载荷的常见做法是如果两个载荷差距明显比如0.65 vs 0.42归到高载荷因子如果接近0.5 vs 0.48考虑删除该变量或增加因子数。删除变量要谨慎因为可能改变整个因子结构删完必须重跑。5. 从结果到结论把统计输出翻译成业务语言跑出结果只是第一步真正体现功力的是怎么把载荷矩阵、方差贡献率这些统计输出翻译成别人能听懂的话。这一节聊聊我在实际汇报和报告撰写中的一些做法。5.1 主成分命名的实操技巧给主成分命名不是看哪个变量载荷最高就叫什么而是要找出一组语义上连贯的高载荷变量提炼它们的共同主题。比如第一主成分上月收入房产数量汽车品牌档次年度旅行次数载荷都高叫收入水平就窄了叫消费能力与生活方式更准确。命名时我习惯列一个表主成分编号、高载荷变量绝对值排序、载荷值、初步命名、备选命名。备选命名很重要因为初步命名往往偏窄和同事讨论后通常会调整。命名没有标准答案但必须能自圆其说且和后续分析目的挂钩。5.2 因子得分的使用边界psych::fa输出的scores是因子得分默认回归法估计。因子得分可以用作后续回归、聚类或分组的输入但要注意两点一是因子得分是估计值不是精确值存在估计误差尤其在因子数较多时二是不同估计方法回归法、Bartlett法、Anderson-Rubin法得到的得分不同回归法得分之间可能相关即使因子本身正交Bartlett法得分则严格正交。如果后续要把因子得分当自变量放进回归我倾向用Bartlett法psych::fa里通过score Bartlett指定因为它保证了得分与因子结构的对应关系更干净。但如果你只是做描述性分组回归法的得分分布更接近原始数据的变异结构也够用。5.3 报告里必须交代的几个数字写分析报告时有几个数字不交代会被内行质疑KMO值和Bartlett检验结果证明数据适合做降维、保留的成分/因子数及判据说明选择依据、累计方差贡献率PCA或模型拟合指标FA、旋转方法FA。这些是分析透明度的基本要求。另外载荷矩阵建议用表格呈现只保留绝对值大于0.3的项用空白或短横线表示低于阈值这样读者能快速抓住结构。全量载荷矩阵放附录正文放精简版。这个做法在学术报告和商业报告里都适用。6. 几个能直接复用的代码片段与参数备忘最后把日常高频使用的代码和参数整理成备忘方便直接抄。6.1 完整PCA流程模板# 1. 数据准备与检查 # 假设df是数据框全部为数值型变量 numeric_df - df[, sapply(df, is.numeric)] # 2. 相关性检验 cor_matrix - cor(numeric_df, use complete.obs) # KMO检验需要psych包 library(psych) KMO(cor_matrix) cortest.bartlett(cor_matrix, n nrow(numeric_df)) # 3. PCA pca_res - prcomp(numeric_df, center TRUE, scale. TRUE) # 4. 结果概览 summary(pca_res) eigenvalues - pca_res$sdev^2 # 5. 碎石图 plot(pca_res, type lines) # 6. 载荷与得分 loadings_mat - pca_res$rotation scores_mat - pca_res$x6.2 因子分析参数速查表参数常用取值说明nfactors由平行分析确定因子个数fmpa / ml / minres估计方法pa最稳健rotatevarimax / promax正交/斜交旋转scoresregression / Bartlett因子得分方法cut0.3打印载荷时的显示阈值6.3 常见报错与应对prcomp报infinite or missing values in x检查数据里是否有Inf或NA先清洗。factanal报unable to optimize from this starting value通常是因子数过多或数据共线性太强减少因子数或改用psych::fa的pa方法。fa.parallel跑得慢减少n.iter默认20设成50已经够用100以上没必要。注意所有降维分析的结果都依赖数据预处理的质量。标准化方式、缺失值处理、异常值处理这三步没做好后面调什么参数都是白搭。我见过太多人把时间花在纠结旋转方法上却忽略了原始数据里几个极端值把相关矩阵带偏了。这套流程我在不同规模的数据集上都跑过从几十个样本的小型问卷到上万条记录的运营数据核心逻辑不变变的只是参数微调和结果解读的侧重点。真正需要花时间的是理解数据本身的结构而不是记住函数怎么调用——函数查文档就会数据里的故事只有你自己能读出来。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑