当前位置:   article > 正文

R语言有RStan的多维验证性因子分析(CFA)_r语言 cfa

r语言 cfa

最近我们被要求撰写关于RStan的研究报告,包括一些图形和统计输出。

如果您已经熟悉RStan,那么您需要组合的基本概念是具有相关随机斜率和异方差误差的标准多级模型。

我将R代码嵌入到演示中。所需的包是lavaanlme4RStan

我喜欢将大多数统计方法理解为回归模型。这样,很容易理解大量技术背后的主张。这是一种适用于SEM和IRT模型的方法。在这里,我将重点关注验证性因子分析(CFA),因此我将首先从一个易于适用于任何多级回归软件的模型开发CFA:

 

 

  1. dat.l <- tidyr::gather(dat, item, score, x1:x9)
  2. dat.l$item.no <- as.integer(gsub("x", "", dat.l$item))
  3. library(lme4)
  4. lmer(score ~ 0 + factor(item.no) + (1 | ID), dat.l, REML = FALSE)
  5. # Random effects:
  6. # Groups Name Std.Dev.
  7. # ID (Intercept) 0.5758
  8. # Residual 0.9694
  9. # Number of obs: 2709, groups: ID, 301

上面适用于ML而不是REML的模型与一维CFA相同,。 使用:

λ = α √ α 2 + σ 2= 0.5758 √ 0.5758 2 + 0.9694 2= 0.5107λ=αα2+σ2=0.57580.57582+0.96942=0.5107

请注意,在lavaan语法中,因子被标准化为使用的方差为1 std.lv = TRUE

  1. parameterEstimates(sem(
  2. "F1 =~ a * x1 + a * x2 + a * x3 + a * x4 + a * x5 + a * x6 + a * x7 + a * x8 + a * x9\n
  3. x5 ~~ f * x5\nx6 ~~ f * x6\nx7 ~~ f * x7\nx8 ~~ f * x8\nx9 ~~ f * x9",
  4. dat, std.lv = TRUE
  5. ), standardized = TRUE)[c(1:2, 10:11), c(1:5, 12)]
  6. # lhs op rhs label est std.all
  7. # 1 F1 =~ x1 a 0.576 0.511
  8. # 2 F1 =~ x2 a 0.576 0.511
  9. # 10 x1 ~~ x1 f 0.940 0.739
  10. # 11 x2 ~~ x2 f 0.940 0.739

让我们扩展模型以包括多个因素。为了包括多个因子,我们以长格式创建一个指标列,用于唯一标识项目所属的因子。

  1. dat.l$Fs <- ((dat.l$item.no - 1) %/% 3) + 1
  2. lmer(score ~ 0 + factor(item) + (0 + factor(Fs) | ID), dat.l, REML = FALSE)
  3. # Random effects:
  4. # Groups Name Std.Dev. Corr
  5. # ID factor(Fs)1 0.7465
  6. # factor(Fs)2 0.9630 0.41
  7. # factor(Fs)3 0.6729 0.38 0.30
  8. # Residual 0.7909

相应的lavaan模型是:

  1. parameterEstimates(sem(
  2. "F1 =~ a * x1 + a * x2 + a * x3\nF2 =~ b * x4 + b * x5 + b * x6\nF3 =~ c * x7 + c * x8 + c * x9\n
  3. x1 ~~ f * x1\nx2 ~~ f * x2\nx3 ~~ f * x3\nx4 ~~ f * x4\nx5 ~~ f * x5\n
  4. dat, std.lv = TRUE
  5. ), standardized = TRUE)[c(1:10, 22:24), c(1:5, 12)]
  6. # lhs op rhs label est std.all
  7. # 1 F1 =~ x1 a 0.746 0.686
  8. # 2 F1 =~ x2 a 0.746 0.686
  9. # 3 F1 =~ x3 a 0.746 0.686
  10. # 4 F2 =~ x4 b 0.963 0.773
  11. # 5 F2 =~ x5 b 0.963 0.773
  12. # 6 F2 =~ x6 b 0.963 0.773
  13. # 7 F3 =~ x7 c 0.673 0.648
  14. # 8 F3 =~ x8 c 0.673 0.648
  15. # 9 F3 =~ x9 c 0.673 0.648
  16. # 10 x1 ~~ x1 f 0.626 0.529
  17. # 22 F1 ~~ F2 0.407 0.407
  18. # 23 F1 ~~ F3 0.385 0.385
  19. # 24 F2 ~~ F3 0.301 0.301

我们看到CFA中的因子载荷是多级的随机斜率标准偏差。并且,因子间相关矩阵匹配来自多级的随机斜率相关。

 在lavaan,模型语法将是:

  1. # Drop the error variance constraints
  2. "F1 =~ a * X1 + a * X2 + a * X3\nF2 =~ b * X4 + b * X5 + b * X6\nF3 =~c * X7 + c * X8 + c * X9"

最后的变化是我们需要允许项目加载量按项目而不是因子来变化。一旦我们这样做,我们就不能再使用多级回归软件来适应模型。 

贝叶斯软件可以适合这样的复杂模型。我们必须为这个等式的不同组成部分指定先验。 

 

在Stan语法中,所需的数据是:

  1. data {
  2. real g_alpha; // for inverse gamma
  3. real g_beta; // for inverse gamma
  4. int<lower = 0> Nf; // scalar, number of factors
  5. vector[N] response; // vector, long form of item responses
  6. // all remaining entries are data in long form
  7. // with consecutive integers beginning at 1 acting as unique identifiers
  8. int<lower = 1, upper = Ni> items[N];
  9. int<lower = 1, upper = Nf> factors[N];
  10. }

估计的参数是:

  1. parameters {
  2. vector<lower = 0>[Ni] item_vars; // item vars heteroskedastic
  3. vector<lower = 0>[Ni] alphas; // loadings
  4. vector[Ni] betas; // item intercepts, default uniform prior
  5. }

我们需要一些转换参数来获得均值和方差。 

  1. transformed parameters {
  2. vector[N] yhat;
  3. vector[N] item_sds_i;
  4. for (i in 1:N) {
  5. yhat[i] = alphas[items[i]] * thetas[persons[i], factors[i]] + betas[items[i]];
  6. item_sds_i[i] = sqrt(item_vars[items[i]]);
  7. }
  8. }

  1. model {
  2. matrix[Nf, Nf] A0;
  3. L ~ lkj_corr_cholesky(Nf);
  4. A0 = diag_pre_multiply(A, L);
  5. thetas ~ multi_normal_cholesky(rep_vector(0, Nf), A0);
  6. response ~ normal(yhat, item_sds_i);
  7. }

最后,我们可以计算标准化载荷和因子间相关矩阵R:

  1. generated quantities {
  2. vector<lower = 0>[Ni] loadings_std; // obtain loadings_std
  3. matrix[Nf, Nf] R;
  4. }
  5. }

我们可以做一些修改:

  • 我们可以在建模之前标准化项目响应,以提高计算稳定性
  • 然后在项目截取之前应用法线

然后运行模型的语法是:

  1. # 拟合模型
  2. cfa.mm <- stan_model(stanc_ret = stanc(file = "bayes_script/cfa.stan")) # Compile Stan code

什么是负荷?

  1. # mean se_mean sd 2.5% 50% 97.5% n_eff Rhat
  2. # alphas[1] 0.889 0.003 0.078 0.733 0.890 1.041 790 1.002
  3. # alphas[4] 0.991 0.002 0.056 0.885 0.988 1.101 1263 1.002
  4. # alphas[5] 1.102 0.002 0.062 0.980 1.102 1.224 1056 1.001
  5. # alphas[9] 0.692 0.003 0.075 0.548 0.692 0.846 799 1.005
  6. # loadings_std[1] 0.751 0.002 0.052 0.643 0.752 0.848 601 1.003
  7. # loadings_std[4] 0.848 0.001 0.023 0.801 0.849 0.890 1275 1.003
  8. # loadings_std[5] 0.851 0.001 0.023 0.803 0.852 0.891 1176 1.001
  9. # loadings_std[9] 0.672 0.003 0.059 0.552 0.673 0.786 556 1.007
  10. # 为了进行比较,lavaan负载为
  11. parameterEstimates(cfa.lav.fit, standardized = TRUE)[1:9, c(1:5, 11)]
  12. # lhs op rhs est se std.all
  13. # 1 F1 =~ x1 0.900 0.081 0.772
  14. # 4 F2 =~ x4 0.990 0.057 0.852
  15. # 5 F2 =~ x5 1.102 0.063 0.855
  16. # 9 F3 =~ x9 0.670 0.065 0.665

对于因子间相关性:

  1. probs = c(.025, .5, .975), digits_summary = 3)
  2. # mean se_mean sd 2.5% 50% 97.5% n_eff Rhat
  3. # R[1,2] 0.435 0.001 0.065 0.303 0.437 0.557 2019 0.999
  4. # R[1,3] 0.451 0.003 0.081 0.289 0.450 0.607 733 1.005
  5. # R[2,3] 0.271 0.001 0.071 0.130 0.272 0.406 2599 1.000
  6. # lavaan:
  7. # lhs op rhs est se std.all
  8. # 22 F1 ~~ F2 0.459 0.064 0.459
  9. # 23 F1 ~~ F3 0.471 0.073 0.471
  10. # 24 F2 ~~ F3 0.283 0.069 0.283

  1. # mean se_mean sd 2.5% 50% 97.5% n_eff Rhat
  2. # item_vars[3] 0.829 0.003 0.095 0.652 0.828 1.026 1292 1.000
  3. # item_vars[4] 0.383 0.001 0.049 0.292 0.381 0.481 1552 1.002
  4. # item_vars[5] 0.459 0.001 0.059 0.351 0.456 0.581 1577 1.001
  5. # item_vars[9] 0.575 0.004 0.085 0.410 0.575 0.739 532 1.008
  6. #
  7. parameterEstimates(cfa.lav.fit, standardized = TRUE)[10:18, 1:5]
  8. # lhs op rhs est se
  9. # 12 x3 ~~ x3 0.844 0.091
  10. # 13 x4 ~~ x4 0.371 0.048
  11. # 14 x5 ~~ x5 0.446 0.058
  12. # 18 x9 ~~ x9 0.566 0.071

  1. # mean se_mean sd 2.5% 50% 97.5% n_eff Rhat
  2. # betas[2] 6.087 0.001 0.068 5.954 6.089 6.219 2540 1.001
  3. # betas[3] 2.248 0.001 0.066 2.122 2.248 2.381 1980 1.002
  4. # betas[6] 2.182 0.003 0.063 2.058 2.182 2.302 625 1.008
  5. # betas[7] 4.185 0.002 0.066 4.054 4.186 4.315 1791 1.001
  6. # From lavaan:
  7. parameterEstimates(cfa.lav.fit, standardized = TRUE)[25:33, 1:5]
  8. # lhs op rhs est se
  9. # 26 x2 ~1 6.088 0.068
  10. # 27 x3 ~1 2.250 0.065
  11. # 30 x6 ~1 2.186 0.063
  12. # 31 x7 ~1 4.186 0.063

所以我们能够复制lavaan的结果。从这里,您可以以有趣的方式扩展模型以获得其他结果。


例如,如果要对因子进行回归,可以使用相关矩阵的后验和solve()函数来得出回归中因子的系数。在这里,我在因子2和3上回归因子1:

  1. R <- extract(cfa.stan.fit, c("R[1, 2]", "R[1, 3]", "R[2, 3]"))
  2. R <- cbind(R$`R[1,2]`, R$`R[1,3]`, R$`R[2,3]`)
  3. coefs <- matrix(NA, nrow(R), ncol(R) - 1)
  4. for (i in 1:nrow(R)) {
  5. m <- matrix(c(1, R[i, 3], R[i, 3], 1), 2, 2)
  6. coefs[i, ] <- solve(m, R[i, 1:2])
  7. }; rm(i, m)
  8. t(apply(coefs, 2, function (x) {
  9. c(estimate = mean(x), sd = sd(x), quantile(x, c(.025, .25, .5, .75, .975)))
  10. }))
  11. # estimate sd 2.5% 25% 50% 75% 97.5%
  12. # [1,] 0.3362981 0.07248634 0.1918812 0.2877936 0.3387682 0.3875141 0.4725508
  13. # [2,] 0.3605951 0.08466494 0.1996710 0.3027047 0.3594806 0.4164141 0.5308578

非常感谢您阅读本文,有任何问题请在下面留言!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/725658
推荐阅读
相关标签
  

闽ICP备14008679号