news 2026/10/5 3:34:54

R语言lavaan包结构方程模型实战指南:从潜变量到非递归模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
R语言lavaan包结构方程模型实战指南:从潜变量到非递归模型

做结构方程模型,十个人里有九个会提到 R 的lavaan包。剩下那个可能还在用 Mplus,但看到高昂的授权费之后大概率也会转回来。这个包的火爆不是没有道理:它能用一套接近 Mplus 的模型语法,把潜变量、复合变量、多组比较、嵌套数据、时间/空间结构、非递归模型全塞进同一个框架里。我这些年处理问卷数据、纵向追踪数据、多地区调研数据,绝大多数项目都是靠lavaan一个包扛完的。

这篇文章不是来抄文档的,而是把我实际踩过的坑和验证过的路径按场景拆开讲。你会看到每一类模型用什么代码、在哪一步最容易翻车、模型不收敛了先查什么。标题里那些术语听起来很多,实际上落到代码里就是=~、~、~~、:=这几条路径规则的组合。先把基础语法吃透,后面所有复杂模型都是搭积木。

1. 为什么是 lavaan:先搞懂它解决了什么问题

1.1 它的定位和能做的范围

lavaan的定位很明确:一个开源、免费、语法接近 Mplus 的结构方程建模工具。它支持的模型类型包括验证性因子分析(CFA)、完整结构方程模型(SEM)、潜在增长曲线模型、多组 SEM、多水平 SEM、以及带反馈回路的非递归模型。说直白一点,传统回归只能处理"因变量是观测变量"的情况,而 SEM 可以把测量误差、因子结构、间接效应、跨组不变性这些需求一次性纳入。

它最大的优势是模型语法足够简洁。比如定义一个潜变量,只要一行:

f1 =~ y1 + y2 + y3

这行代码表示"潜变量 f1 由观测变量 y1、y2、y3 反映"。加上回归路径y ~ x、协方差x ~~ y、参数标签a*x,几乎所有 SEM 模型都能拼出来。相比 Mplus,你不用单独写数据文件、变量列表、模型命令,所有东西都可以在 R 里用数据框一次性搞定。

1.2 什么场景优先选 lavaan,什么场景要慎重

优先选lavaan的场景是:经典结构方程模型、中介/调节效应分析、潜变量 CFA、多组比较、增长曲线模型。这些场景lavaan的表现已经非常稳定,而且社区资料丰富。

要慎重的场景是:复杂的多水平随机斜率模型、贝叶斯 SEM、潜变量交互效应、空间计量结构方程。这些不是lavaan的强项。比如潜变量交互,lavaan需要配合indProd包做乘积指标;复杂多水平模型我一般会转向 Mplus 或brms。判断标准很简单:如果你的模型只涉及"测量模型 + 结构路径",lavaan完全够用;如果模型里有大量跨层随机效应,别硬刚。

2. 潜变量模型:从 CFA 到完整 SEM 的落地细节

2.1 测量模型:先确认你的因子结构站得住

所有潜变量模型的第一步,都是先跑一个 CFA,确认观测指标和潜变量之间的关系没问题。我见过太多人直接跑完整 SEM,结果结构路径显著但测量模型一塌糊涂,最后整个模型不可解释。正确顺序是先做测量模型,再做结构模型。

先看一个标准的二阶潜变量 CFA 模型:

library(lavaan) cfa_model <- ' f1 =~ x1 + x2 + x3 + x4 f2 =~ x5 + x6 + x7 + x8 f3 =~ x9 + x10 + x11 + x12 ' fit_cfa <- cfa(cfa_model, data = mydata, estimator = "MLR") summary(fit_cfa, fit.measures = TRUE, standardized = TRUE)

这里有个细节:estimator = "MLR"是中庸选择。如果你的数据是李克特量表,变量最多五到七级,严格来说不满足多元正态。MLR 提供稳健标准误和卡方统计量,能抵抗一定程度的非正态。如果数据严重偏态,可以考虑把变量当有序类别处理,但那是另一个话题。

跑完之后先看三样东西:

  • 每个标准化载荷是否大于 0.5,理想是 0.7 以上;
  • 修正指数(MI)里面有没有高得离谱的交叉载荷;
  • 拟合指数 CFI 是否大于 0.90,RMSEA 是否小于 0.08。

如果某个指标载荷特别低,比如 0.3,别急着删。先看这个题项的措辞和潜变量理论定义是否一致。删除指标必须有理论依据,不能光靠统计。另一件容易被忽略的事:潜变量必须设置尺度,要么固定某个指标载荷为 1,要么固定潜变量方差为 1。lavaan默认把第一个指标的载荷固定为 1,所以你在语法里不用特意写。

2.2 结构模型:加入路径与间接效应

测量模型通过之后,加上结构路径就变成了完整 SEM。最常见的设定是:外生潜变量f1影响内生潜变量f2,f2又影响f3,形成中介链条。代码长这样:

sem_model <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f3 =~ x7 + x8 + x9 f2 ~ a*f1 f3 ~ b*f2 + c*f1 indirect := a*b total := c + a*b ' fit_sem <- sem(sem_model, data = mydata, estimator = "MLR", se = "bootstrap", bootstrap = 1000)

:=是lavaan定义新参数的运算符。indirect := a*b表示间接效应是路径 a 和 b 的乘积。这里不要自己手动去乘标准误,直接用 bootstrap 会给出间接效应的置信区间。运行后看parameterEstimates(fit_sem, ci = TRUE)输出的置信区间是否包含 0。

踩过一个典型坑:直接设置se = "bootstrap"但忘记设置bootstrap次数,默认值只有 100,效果不稳定。建议至少 1000 次。另外,用 MLR 时 bootstrap 会计算比较慢,数据量大就晚上挂机跑。

3. 复合变量与测量模型变体:打包、二阶因子、形成性指标

3.1 复合变量到底指什么

"复合变量"这个术语在不同文章里含义不一样。常见有两种:一种是把多个观测变量按某种逻辑合并成一个总分或合成指数,比如把量表各题加总后的总分,这种是 observed composite;另一种是形成性测量模型里的复合构造,比如"社会经济地位"是由收入、教育、职业三个指标形成的构念,而不是由它们反映出来的潜变量。

很多人会混淆这两件事。确认清楚你要处理的是哪种复合变量,直接决定你在lavaan里怎么写模型。

如果你的复合变量只是一个保存好的总分(比如total_score <- rowSums(df[, items])),那么它就是一个普通观测变量。直接放进结构方程里作为 X、M、Y 都可以,但代价是测量误差被忽略了。如果你的复合变量是"形成性的",理论上lavaan原生语法不支持形成性测量模型,最常用的做法是把它作为带权重的外生变量,或者改用其他方法近似实现。

3.2 三种实操处理方式

第一种,最省事:把复合变量当观测变量。适用于量表总分、均值分、指数分,比如把三个题的平均值作为一个变量。代码里直接写y ~ composite_x,完事。缺点是这些指标原本的测量误差没有建模,容易造成参数估计有偏,但偏的方向通常是保守的,很多实际场景可接受。

第二种,用二阶因子模型:如果复合变量是多个潜变量的综合,比如"整体工作满意度"由"薪酬满意度"、"发展满意度"、"关系满意度"三个分维度构成,用二阶因子比直接加总更干净:

second_order <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f3 =~ x7 + x8 + x9 overall =~ f1 + f2 + f3 '

这相当于让一个高阶潜变量去解释三个一阶因子。这种做法保留了测量误差信息,也符合"整体构念是分维度之上的更高层级"的理论逻辑。

第三种,形成性指标的近似实现。如果你一定要在lavaan里做类似形成性复合变量的东西,一个可接受但不完美的办法是:把复合变量作为潜变量,指标载荷全部固定为 1,并让复合变量的方差自由估计:

composite_model <- ' comp =~ 1*x1 + 1*x2 + 1*x3 comp ~~ comp y ~ comp '

这种做法本质上是在估计一个“指标等权重加权和”的复合变量。它和真正的形成性测量模型还有距离,因为形成性指标之间不一定需要相关,而且指标对构念的方向是"指标 -> 构念",=~语法表达的是"构念 -> 指标"。所以如果你的模型特别强调形成性逻辑,建议换到 Mplus 或写 Stan 模型。在我自己处理过的项目里,审稿人对形成性模型的接受度其实不高,大家更习惯看到二阶因子模型。

3.3 指标打包的副作用

还有一种和复合变量相关的操作叫"指标打包"(parceling),就是把同一因子下的多个题目随机或按维度合并成 2-3 个总分,再用这些打包变量作为因子指标。打包能减少指标数量、提升模型拟合、缩小样本量需求,但代价是掩盖了题目层面的信息,容易让测量误差结构变得不合理。我的建议是:如果你的样本量足够(N > 300),不要打包;如果因子有 6 个以上题目且样本量紧张,可以按维度打包成 3 个左右,但要在论文里写明打包依据。

4. 分组与嵌套数据:多组 SEM 和多水平 SEM

4.1 多组 SEM:分组比较与测量不变性

当你手里的数据来自不同群体,比如不同性别、不同干预组、不同地区,你的问题通常不是"这个模型在所有群体里拟合如何",而是"这个模型的结构在不同群体之间是不是等价的"。多组 SEM 就是为此设计的。

基础语法很简单:

fit_mg <- sem(sem_model, data = mydata, group = "gender") summary(fit_mg, fit.measures = TRUE, standardized = TRUE)

lavaan会为每个组分别估计一套参数。但真正做跨组比较,要先做测量不变性检验。完整的测量不变性测试顺序是:形态等值(configural)-> 弱等值(metric,因子载荷相等)-> 强等值(scalar,截距相等)-> 严格等值(残差方差相等)。

老版本里可以直接用semTools::measurementInvariance一键跑完,但新版semTools更推荐自己用update逐步设置group.equal:

library(semTools) fit_config <- sem(cfa_model, data = mydata, group = "gender") fit_metric <- sem(cfa_model, data = mydata, group = "gender", group.equal = c("loadings")) fit_scalar <- sem(cfa_model, data = mydata, group = "gender", group.equal = c("loadings", "intercepts"))

然后比较 CFI 变化量,delta CFI小于 0.01 通常认为没有显著恶化。这一步在发问卷类论文时基本是必选项。我之前有一次犯了只报告拟合指数不报不变性检验的错误,审稿人直接点名要求补,从那以后我就默认多组数据先跑一遍不变性检验。

4.2 嵌套数据:用 cluster 参数处理组内相关

数据不是独立抽样的时候,比如一个班的学生、一个医院的病人、同一个社区的家庭,观测点之间并不独立。最简单的处理思路是用cluster参数做聚类稳健标准误:

fit_cluster <- sem(sem_model, data = mydata, cluster = "school") summary(fit_cluster, fit.measures = TRUE)

这个方式相当于告诉lavaan:虽然我没有为每个学校单独建模,但我在学校水平上考虑了相关性,修正标准误。适合你的模型重点是个体层面,只是不想忽略聚类影响。

如果聚类效应本身就是研究问题,比如你想看"学校氛围"对"学生满意度"的影响,并同时控制个体层面的变量,那就需要多水平 SEM。lavaan从 0.6 版本开始支持两水平模型,语法是在同一个模型里分别写level: 1和level: 2块:

ml_model <- ' level: 1 satisfaction ~ motivation + workload level: 2 school_climate =~ climate1 + climate2 + climate3 school_sat =~ satisfaction school_sat ~ school_climate ' fit_ml <- sem(ml_model, data = mydata, cluster = "school")

注意,这个两级模型不是完全功能完备的多水平 SEM,随机斜率等复杂设定在lavaan里很容易遇到识别问题。如果你只需要随机截距、组间路径,lavaan能胜任;一旦需要每个学校自己有一条斜率,赶紧转 Mplus,不要浪费时间调参。

4.3 分组与嵌套的选择逻辑

分组数据和多水平数据的共同点是"非独立",区别在于你处理的是组间参数差异还是组间方差。多组 SEM 比较的是参数在不同组之间是否相等;多水平 SEM 是假设参数跨组相同,但对组内相关性进行建模,并估计组间方差和组间效应。实际操作时,如果你的组数很少(比如只有男、女两组),用多组 SEM;如果组数很多(比如几十上百个学校),用多水平 SEM。反过来把几十个学校的虚拟变量全放进模型里做"多组",会爆炸。

5. 时间与空间数据:纵向 SEM、增长模型与空间变量的处理

5.1 纵向数据:交叉滞后与潜在增长曲线

时间维度的数据在 SEM 里有两种常见处理路径。第一种是交叉滞后面板模型(CLPM),用来评估两个变量在不同时间点的相互预测关系。比如你在 T1、T2 两个时间点都测了焦虑和失眠,想看看是焦虑先影响失眠,还是失眠先影响焦虑。

clpm_model <- ' anxiety2 ~ anxiety1 + insomnia1 insomnia2 ~ insomnia1 + anxiety1 anxiety1 ~~ insomnia1 anxiety2 ~~ insomnia2 anxiety1 ~ 1 insomnia1 ~ 1 ' fit_clpm <- sem(clpm_model, data = longitudinal_data, estimator = "MLR")

这里的关键是让anxiety2和insomnia2的残差相关,因为同一时间点的共同未测混淆因素确实存在。如果不写anxiety2 ~~ insomnia2,这个相关会被强行固定为 0,通常是不合理的。CLPM 的局限是它把个体间差异和个体内变化混在一起,所以现在很多研究改用随机截距交叉滞后面板模型(RI-CLPM),lavaan也可以写,但那是另一个进阶话题。

第二种是潜在增长曲线模型(LGM)。如果研究重点是"变化趋势",比如四波追踪数据里压力水平是怎么变化的,LGM 更合适:

lgm_model <- ' i =~ 1*t1 + 1*t2 + 1*t3 + 1*t4 s =~ 0*t1 + 1*t2 + 2*t3 + 3*t4 i ~~ i s ~~ s i ~~ s ' fit_lgm <- growth(lgm_model, data = longitudinal_data) summary(fit_lgm, fit.measures = TRUE, standardized = TRUE)

i是截距因子,代表初始水平;s是斜率因子,代表变化速度。你把时间载荷设成 0、1、2、3,意思是每波测量间隔等距。如果你的追踪时间间隔不等,比如 0、1、4、12 个月,就把载荷改成实际间隔。这里的常见错误是把第一波载荷固定为 0,第二波以后却用1*的等距假设,结果模型拟合很差还找不到原因。先检查时间编码是不是和数据实际间隔一致。

5.2 纵向中介:横断面结果与纵向验证的差异

现在很多研究都会先做横断面分析,发现 X 和 Y 相关,X 和 M 相关,M 和 Y 相关,然后就说"支持中介效应"。这种结论最容易被质疑,因为横断面数据无法排除反向因果和混杂因素。更靠谱的做法是设计纵向中介:T1 测 X,T2 测 M,T3 测 Y,然后用 SEM 估计 X -> M -> Y 的路径。

long_med <- ' M2 ~ a*X1 Y3 ~ b*M2 + c*X1 ab := a*b ' fit_lm <- sem(long_med, data = longitudinal_data, se = "bootstrap", bootstrap = 1000)

这种设计让变量在时间上有了先后顺序,虽然仍不能证实因果,但比横断面证据强得多。我在实际项目中很少直接用 T1 的 M 和 T1 的 Y 去做中介,因为那本质上还是一次横断面分析,只是加了自回归。合理设置是 X、M、Y 来自三个不同时间点,中间至少隔一段有意义的时间窗口。

5.3 空间数据:lavaan 不是空间计量包,但可以这样处理

先说结论:lavaan没有内置空间权重矩阵、空间滞后项、空间误差项这些功能。但"空间数据"不等于一定要用空间计量模型。根据你的研究问题,有三种路线可以把空间数据放进 SEM 框架。

第一种,把空间单元作为分组变量做多组 SEM。比如你想比较东、中、西部三个区域,模型结构是否一致,直接用group = "region"跑多组 SEM,再测不变性。这个方法最稳,也最容易解释。

第二种,如果空间自相关是干扰因素,用cluster = "region"或者更细的网格 ID。这等同于说"同一个区域的样本可能彼此相似,我不估计空间效应,但我修正标准误"。成本最低,适合你的问题里空间不是主角的情况。

第三种,如果空间效应是主角,比如你要检验"邻域社会经济水平"是否通过"社区参与"影响"居民幸福感",可以在lavaan之外先把空间滞后变量算出来,再放进模型当观测变量。

library(spdep) coords <- cbind(data$lon, data$lat) nb <- knn2nb(knearneigh(coords, k = 4)) lw <- nb2listw(nb) data$neighbor_ses <- lag.listw(lw, data$ses)

然后跑一个常规 SEM:

sem_model_sp <- ' participation ~ ses + neighbor_ses wellbeing ~ participation + ses + neighbor_ses '

这种方法假设空间效应只会通过构造的空间滞后变量进入方程,不会处理空间误差项,属于"准空间 SEM"。如果你要做完整的空间误差结构,建议去看spatialreg、INLA或者brms,而不是硬塞给lavaan。

空间数据处理里最容易被骂的是权重矩阵的选择。k = 4意思是用最近 4 个邻居定义邻接关系,换 k 值结果可能会差很多。哲学上,最好预先根据地理理论选权重,不要反复调 k 调到显著为止。我自己的经验是,空间分析部分只要涉及空间权重矩阵,一定要做至少两种权重矩阵的敏感性分析,比如 k=4 和距离衰减阈值。

6. 非递归模型:当因果方向不再单向

6.1 什么是非递归模型

前面讲的 SEM 都是递归模型,意思是路径没有反馈回路,变量之间的影响是单向的。但现实里很多关系天然是双向的:员工士气影响绩效,绩效反过来影响士气;同伴之间的行为互相影响;企业与行业环境之间存在反馈。这种模型术语上叫"非递归模型"。

非递归模型的路径图上至少有一个双向箭头表示的反馈回路,比如y1 -> y2和y2 -> y1同时存在。这里最大的问题是识别:如果一个方程里包含内生变量,而你又没有给每个内生变量找到足够的外生工具变量,模型会欠识别,估计出来的参数没有任何意义。

6.2 用 lavaan 实现一个可识别的非递归模型

要在lavaan里写非递归模型,语法和普通 SEM 没有太大区别:

nonrecursive_model <- ' y1 ~ b12*y2 + x1 y2 ~ b21*y1 + x2 y1 ~~ 0*y2 ' fit_nr <- sem(nonrecursive_model, data = mydata) summary(fit_nr, fit.measures = TRUE, standardized = TRUE)

这个模型能识别,依赖两个条件:

  • x1 只出现在 y1 的方程里,x2 只出现在 y2 的方程里,它们是各自的排他性工具变量;
  • y1 和 y2 的残差协方差被固定为 0,避免残差层面的相关掩盖真实反馈关系。

如果行业内理论认为残差相关性一定要估计,那么你还得多加工具变量或路径约束,否则模型就变成欠识别。不要尝试写出y1 ~ y2; y2 ~ y1然后什么都没有的模型,lavaan会给你报错,因为这种循环路径在没有外部约束时没法唯一估计。

6.3 非递归模型的稳定性问题

即使识别没问题,非递归模型还要考虑稳定条件。简单说,反馈回路里的路径系数乘积不能超过 1:如果b12 * b21接近 1 或大于 1,系统的反馈就会发散,模型估计会特别不稳定。这就像两个人互相喊话,每喊一次音量放大,最后爆音。所以跑非递归模型时,把参数估计结果拿出来,自己算一下b12 * b21。如果结果大于 0.8,就要警惕,可能模型设定有问题,或者这些变量本质上应该用联立方程以外的框架处理。

实测下来,非递归模型在lavaan里的收敛速度比普通模型慢很多。如果出现警告iteration limit reached,先别急着调迭代次数。优先检查是不是欠识别,再检查起始值是否合理。可以在语法里给路径一个合理的初值,比如b12*0.3,这往往能让迭代稳定下来。

7. 样本量估算与横断面/纵向中介效应设计

7.1 SEM 样本量的基础规则

很多人在跑 SEM 前第一句问的就是"我该收多少问卷"。这个问题没有统一答案,但有几个经验法则可以帮你缩小范围。

  • 经典经验法则是 N:q 比例,即样本量至少是自由参数数量的 5 到 20 倍。一个包含 12 个指标、3 个因子的 CFA 大约有 30 个自由参数,最少要 150,舒服一点要 300 以上。
  • 有关潜变量模型,每个因子至少要有 3 个指标,否则模型识别困难。
  • 如果你用的是 MLR 或 bootstrap,样本量尽量不低于 200,因为小样本下稳健标准误和置信区间表现都不好。

最稳妥的方法不是猜,而是做蒙特卡洛模拟。simsem包可以根据你设定的模型、效应量、样本量生成模拟数据,然后计算功效。大致流程是:定义模型语法、设定参数值、设定样本量、跑 500 次模拟,看目标参数在 95% 区间里不包含 0 的比例。这个比例就是功效。虽然开发成本高一些,但写论文时有这一张图,审稿人基本不会在样本量上问太多。

7.2 纵向中介的样本量怎么估

纵向中介比横断面中介需要更多样本,因为你要估计 3 个时间点的变量关系,还要考虑序列相关带来的信息稀释。我一般会先做一个简化版功效估算:假设 X1 对 M2 的标准化回归系数是 0.3,M2 对 Y3 的标准化回归系数是 0.3,那么间接效应大约是 0.09。用蒙特卡洛模拟结果显示,要在这个水平下达到 80% 功效,样本量通常需要 200 到 300。如果你的预期效应更小,比如 0.2 再乘 0.2,那样本量很可能要冲到 500 以上。

不要相信某些横断面研究的"最小样本量公式"能直接套到纵向中介上,因为纵向数据的自相关会让你的有效信息量缩水。实际操作中,我会分两步走:先跑一个早期数据的小样本模型,得到每条路径的粗略效应量;再基于这个效应量做正式样本量计算。比凭空设定参数靠谱得多。

7.3 横断面看影响因素的常见误读

热搜里那句"横断面看影响因素 + 纵向结构方程模型检验中介效应"其实概括了一条标准的进阶路径:横断面分析用来筛选变量、确定路径方向;纵向数据用来验证时间顺序。但横断面 SEM 最容易出现的问题是因果方向不可辩。比如你发现工作压力与离职意愿显著相关,你可以说"压力影响离职意愿",也可以说"想离职的人更倾向于报告压力大"。横断面数据里这两条路径的拟合程度可能一样好。

一种补充手段是跑替代模型比较。比如把路径方向反过来,对比两个模型的 AIC 或 BIC;但这只能说明哪个模型和数据更匹配,不能证明因果。纵向设计才是把这种争议压下去的武器。真正写结论时,横断面只说"相关/关联",纵向模型可以说"预测",但不要轻易说"因果"。

8. 常见报错、排查与经验清单

8.1 模型不收敛:先查这六个地方

lavaan不收敛几乎是每个新手都会遇到的事。我排查的顺序如下:

  • 检查模型识别:有无哪个潜变量只有 1 到 2 个指标。两个指标勉强可以,一个指标基本无法识别。给每个因子至少 3 个指标是最保险的。
  • 检查样本量是否过小。N 不到 100 时模型奇异很常见。如果数据本身有限,可以考虑使用贝叶斯 SEM。
  • 检查量纲差异。变量之间数值差异巨大,比如一个变量在 0-1 之间,另一个变量在 0-10000 之间,模型迭代会痛苦。对观测变量做标准化处理通常能解决。
  • 检查起始值。可以在语法里手动给路径一个合理标签和初始值,比如b1*0.3。lavaan会自动用这些数值做迭代起点。
  • 检查是否是 Heywood case。所谓 Heywood case 就是潜变量方差或残差方差出现负的估计,说明模型设定可能有问题,比如指标过度冗余、存在奇异值或样本量太小。输出里看到负的方差值就要警惕。
  • 检查数据是否存在缺失模式。如果使用列表删除导致样本量骤降,换missing = "FIML"全信息极大似然估计,能有效利用所有信息。

8.2 拟合指数不达标:不是所有修改都合理

模型能收敛,但 CFI 只有 0.85,RMSEA 0.09,很多人第一反应是看修正指数,然后疯狂加相关路径,直到拟合指数冲到 0.95。这种做法最大的问题是你可能把原本理论上独立的残差全部拉通了,模型变成一个"数据驱动模型",难以复制。

我的做法是:

  • 先看理论基础:预先设定哪些残差可能相关(比如同一子量表里的项、同一时间点的变量),把它们写进模型。不要事后看着 MI 去添加,那些事后再加的必须在论文里说明是探索性修改。
  • 如果一个载荷特别低的题目拖累整个拟合,考虑删除,但需要用理论解释。量表题项不是越多越好,冗余题目反而会造成局部依赖。
  • 如果模型整体拟合不好,比较一下是测量模型部分不好还是结构部分不好。你可以先单独跑每个因子的 CFA,确认测量模型过关,再整合成完整 SEM。不要一上来就全模型乱调。

8.3 缺失数据与稳健估计的实际配置

处理缺失数据时,lavaan默认是列表删除,但问卷数据用列表删除很容易丢掉 20% 甚至更多样本。设置成 FIML 很简单:

fit <- sem(model, data = mydata, missing = "FIML", estimator = "MLR")

FIML 的适用前提是数据至少是"随机缺失"(MAR),如果完全随机缺失当然更好。MAR 的意思是:缺失概率只和已观测到的变量有关,和缺失值本身无关。这个假设没法完全验证,但可以通过检查"高分组人群是否系统性少填某个题"来侧面判断。如果发现缺失和数据本身有关,那无论什么方法都救不了,要先解决数据采集问题。

8.4 建立自己的模型体检清单

每次拟合完lavaan模型,我都会按下面这个清单快速扫一遍:

  • 拟合是否成功,有无估计标准误为 NA 的参数;
  • 所有方差是否为正;
  • 标准化载荷是否没有大于 1;
  • CFI/TLI、RMSEA、SRMR 是否符合预期;
  • 实际样本量是否足够;
  • 结果是否对起始值稳健;
  • 核心路径置信区间是否包含 0;
  • 多组模型是否做过测量不变性检验。

这套清单能挡住 80% 的低级错误。我自己有个印象很深的案例:一个模型看起来拟合完美,CFI 0.99,RMSEA 0.01,结果发现标准化载荷有一个是 1.8,潜变量方差几乎为 0。这种"完美拟合"实际上是模型退化,完全不可信。所以体检不能只看拟合指数,一定要看参数具体值。

经验补充:小技巧与工具搭配

最后分享一个让我少走很多弯路的经验:lavaan的模型语法和结果输出,可以配合semPlot包画路径图。路径图不是论文里的装饰品,它能帮你直观看到模型里每个参数是什么方向、有没有画反箭头。做复杂模型时,我习惯先画图,再对着图写代码。尤其是非递归模型,没有图非常容易把y1 ~ y2和y2 ~ y1写混。

还有一个安排:把变量命名和模型语法定义写在一个 R 脚本顶部,加注释说明每个变量代表什么、来自哪道题。这个习惯帮我解决过无数次"三个月后回来看代码看不懂"的问题。lavaan虽然代码简洁,但模型复杂以后,标签的含义很快就会模糊。给所有参数起有意义的名字,而不是a1、b2,后面做敏感性分析和改模型会省力很多。

至于更复杂的模型,比如带随机斜率的交叉滞后模型、多水平非递归模型、贝叶斯 SEM,lavaan的能力边界已经很明确。遇到这种需求,我会先评估:是转 Mplus,还是改用brms写贝叶斯模型。lavaan是日常 SEM 的瑞士军刀,但一个成熟的数据分析师手里不应该只有一把刀。知道什么时候换工具,比学会所有lavaan技巧更重要。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 3:34:50

JS反混淆工具实测:从字符串阵列到控制流平坦化还原指南

先看一段代码。你打开一个 JS 文件&#xff0c;第一屏长这样&#xff1a;var _0x4b3c [\x68\x65\x6c\x6c\x6f, \x77\x6f\x72\x6c\x64, \x74\x65\x73\x74, \x20]; (function(_0x1a2b, _0x3c4d) {var _0x5e6f function(_0x7a8b) {while (--_0x7a8b) {_0x1a2b[push](_0x1a2b[shi…

作者头像 李华
网站建设 2026/10/5 3:34:12

Java Web图书管理系统开发指南:从建库到部署全流程详解

简介&#xff1a;适合高校软件专业学生与 Java Web 初学者的图书管理系统毕业设计文档&#xff0c;面向互联网应用开发场景&#xff0c;重点解决学校图书管理中读者信息、图书入库与借还流程繁琐等问题。包内为 1 份 docx 设计文稿&#xff0c;共 2.34MB&#xff0c;内容完整呈…

作者头像 李华
网站建设 2026/10/5 3:34:03

nvm系统盘路径详解:Windows下nvm安装配置与常见报错排查指南

最近一段时间&#xff0c;我在好几个技术群里都看到有人反复搜同一个问题——“nvm系统盘路径”。顺着这个词翻下去&#xff0c;后面还跟着一串相关搜索&#xff1a;“nvm could not be found or does not exist. exiting. no installations recognized”、“nvm安装及全局配置…

作者头像 李华
网站建设 2026/10/5 3:34:03

Java Web图书管理系统实战:从Servlet到SSM分层架构与事务处理全解析

简介&#xff1a;基于Java Web的图书管理系统的设计与实现.docx是一份面向高校计算机相关专业学生及Java Web初学者的毕业设计/课程设计参考文档&#xff0c;针对学校图书管理中的读者信息、图书流通、借还登记等场景&#xff0c;给出完整解决方案。资源包仅1个docx文档&#x…

作者头像 李华
网站建设 2026/10/5 3:33:44

基于时间序列的旅游数据预测平台:Prophet模型与Flask可视化实战

1. 项目概述1.1 这个项目到底是做什么的很多计算机专业的朋友在做毕业设计的时候&#xff0c;都会在选题上纠结很久——既要能体现技术含量&#xff0c;又要有完整的业务逻辑&#xff0c;还得保证自己能在期限内做完。有些经典题目比如“图书管理系统”“学生选课系统”确实容易…

作者头像 李华
网站建设 2026/10/5 3:33:44

深入解析AI编程工具插件机制:从plugin.json到TypeScript SDK与CLI

1. 从“plugins”这个词说起&#xff1a;它到底在解决什么问题如果你最近在折腾 Cursor、Codex CLI、Zcode CLI 这类工具&#xff0c;大概率会在某个时刻撞上plugins这个词。它可能出现在一个报错里&#xff0c;比如failed to load plugins web boot: 2 entries did not activa…

作者头像 李华