☰
R语言主成分分析与因子分析:从原理到实操的降维指南
2026/10/27 22:06:10 网站建设 项目流程

做数据分析的人大概都有过这样的经历:手头一张表,二三十个变量,相关性矩阵一画出来密密麻麻全是颜色,想找出几个真正有信息量的维度,靠肉眼根本看不出来。这时候主成分分析(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$x

6.2 因子分析参数速查表

参数常用取值说明
nfactors由平行分析确定因子个数
fm"pa" / "ml" / "minres"估计方法,pa最稳健
rotate"varimax" / "promax"正交/斜交旋转
scores"regression" / "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以上没必要)。

注意:所有降维分析的结果都依赖数据预处理的质量。标准化方式、缺失值处理、异常值处理这三步没做好,后面调什么参数都是白搭。我见过太多人把时间花在纠结旋转方法上,却忽略了原始数据里几个极端值把相关矩阵带偏了。

这套流程我在不同规模的数据集上都跑过,从几十个样本的小型问卷到上万条记录的运营数据,核心逻辑不变,变的只是参数微调和结果解读的侧重点。真正需要花时间的是理解数据本身的结构,而不是记住函数怎么调用——函数查文档就会,数据里的故事只有你自己能读出来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询