如何在Python的semopy.multigroup()中实现标量测量不变性?
如何在semopy中实现多组CFA的标量测量不变性
问题背景
我有一个包含21个项目的合并数据集,通过wave变量划分为15个双周调查波次。合并数据的CFA模型拟合效果良好,但需要验证不同波次间的纵向测量不变性。目前已通过semopy的multigroup()默认设置实现度量不变性(仅因子载荷跨组相等),但不知道如何实现标量测量不变性(因子载荷与观测变量截距均跨组相等),尝试修改模型语法和查询参数均未成功。
解决方案
semopy实现标量不变性有两种简洁方式:
方式1:直接指定invariance参数
multigroup()函数内置了invariance参数,可直接指定不变性级别:
'metrics':默认,仅约束因子载荷跨组相等(度量不变性)'scalar':约束因子载荷+观测变量截距跨组相等(标量不变性)
修改代码调用部分即可:
model_multi = multigroup(model_dict, df_pool, group='wave', invariance='scalar') print(model_multi.stats)
方式2:在模型语法中显式约束截距
如果需要更精细的控制(比如仅约束部分变量的截距),可以在模型语法中给每个观测变量的截距指定全局参数名,强制跨组相等:
# 原二阶CFA模型部分(因子载荷默认跨组相等) F1_effic =~ F1A5_2 + F1A10_2r + F3A18_1 F21_resent =~ F1A10_1 + F1A16_1r + F1A17_1 + F5A5_1 F22_affec =~ F1A9_1 + F1A15_1 F4_cosmo =~ F3A7_1 + F3A8_1 + F3A34_1 F5_consp =~ F1A17_2 + F5eA3_1 + F5eA4_1 + F5cA3_1 + F1A16_2 + F5A11_1r F6_envir =~ F2A11 + F2A12 + F3A10_1r F2_rebel =~ F21_resent + F22_affec # 约束每个观测变量的截距跨组相等 F1A5_2 ~ int_F1A5_2*1 F1A10_2r ~ int_F1A10_2r*1 F3A18_1 ~ int_F3A18_1*1 F1A10_1 ~ int_F1A10_1*1 F1A16_1r ~ int_F1A16_1r*1 F1A17_1 ~ int_F1A17_1*1 F5A5_1 ~ int_F5A5_1*1 F1A9_1 ~ int_F1A9_1*1 F1A15_1 ~ int_F1A15_1*1 F3A7_1 ~ int_F3A7_1*1 F3A8_1 ~ int_F3A8_1*1 F3A34_1 ~ int_F3A34_1*1 F1A17_2 ~ int_F1A17_2*1 F5eA3_1 ~ int_F5eA3_1*1 F5eA4_1 ~ int_F5eA4_1*1 F5cA3_1 ~ int_F5cA3_1*1 F1A16_2 ~ int_F1A16_2*1 F5A11_1r ~ int_F5A11_1r*1 F2A11 ~ int_F2A11*1 F2A12 ~ int_F2A12*1 F3A10_1r ~ int_F3A10_1r*1
每个int_xxx是全局参数名,确保对应观测变量的截距在所有组中取值一致。
验证不变性
运行模型后,通过model_multi.stats查看拟合指标(如CFI、RMSEA、TLI等),与度量不变性模型对比:
- 若CFI下降≤0.01,RMSEA上升≤0.015,通常认为标量不变性成立。
完整测试代码
import pandas as pd import numpy as np import semopy from semopy.multigroup import multigroup # Generate dataset np.random.seed(42) num_wave = 15 n_per_wave = 100 items = [ "F1A5_2", "F1A10_2r", "F3A18_1", "F1A10_1", "F1A16_1r", "F1A17_1", "F5A5_1", "F1A9_1", "F1A15_1", "F3A7_1", "F3A8_1", "F3A34_1", "F1A17_2", "F5eA3_1", "F5eA4_1", "F5cA3_1", "F1A16_2", "F5A11_1r", "F2A11", "F2A12", "F3A10_1r" ] df_pool = pd.DataFrame({ "wave": np.repeat(np.arange(1, num_wave + 1), n_per_wave) }) for item in items: df_pool[item] = np.random.normal(3, 1, len(df_pool)) # CFA Model with Second-Order-Factors model_dict = """ F1_effic =~ F1A5_2 + F1A10_2r + F3A18_1 F21_resent =~ F1A10_1 + F1A16_1r + F1A17_1 + F5A5_1 F22_affec =~ F1A9_1 + F1A15_1 F4_cosmo =~ F3A7_1 + F3A8_1 + F3A34_1 F5_consp =~ F1A17_2 + F5eA3_1 + F5eA4_1 + F5cA3_1 + F1A16_2 + F5A11_1r F6_envir =~ F2A11 + F2A12 + F3A10_1r F2_rebel =~ F21_resent + F22_affec """ # 实现标量不变性 model_multi = multigroup(model_dict, df_pool, group='wave', invariance='scalar') print(model_multi.stats)
内容的提问来源于stack exchange,提问作者ghost_trevor
相关产品推荐
相关产品推荐

