了解 lavaan 中的自由度

Understanding degrees of freedom in lavaan

lavaan 提供了跨组约束参数的机会。假设我的数据中有两组。假设以下模型:

library(RCurl)
library(lavaan)
x <- getURL("https://gist.githubusercontent.com/aronlindberg/dfa0115f1d80b84ebd48b3ed52f9c5ac/raw/3abf0f280a948d6273a61a75415796cc103f20e7/growth_data.csv")
growth_data <- read.csv(text = x)

model_regressions <- ' i =~ 1*t1 + 1*t2 + 1*t3 + 1*t4 + 1*t5 + 1*t6 + 1*t7 + 1*t8 + 1*t9 + 1*t10 + 1*t11 + 1*t12 + 1*t13+ 1*t14 + 1*t15 + 1*t16 + 1*t17 + 1*t18 + 1*t19 + 1*t20
s =~ 0*t1 + 1*t2 + 2*t3 + 3*t4 + 4*t5 + 5*t6 + 6*t7 + 7*t8 + 8*t9 + 9*t10 + 10*t11 + 11*t12 + 12*t13 + 13*t14 + 14*t15 + 15*t16 + 16*t17 + 17*t18 + 18*t19 + 19*t20

# fixing error-variances
t8 ~~ 0.01*t8
t17 ~~ 0.01*t17
t18 ~~ 0.01*t18
# regressions
s ~ h_index
i ~ h_index'

fit_UNconstrained <- growth(model_regressions, data=growth_data, group = "type")

然后使用以下方法我可以限制两组的截距:

fit_constrained_intercepts <- growth(model_regressions, data=growth_data, group = "type", group.equal = c("intercepts"))

但是,当我将此模型与无约束模型进行比较时,自由度与 Chi2 的差异为零 (0)。这怎么可能?

此外,当我约束其他参数时,例如方差,例如:

fit_constrained_variances <- growth(model_regressions, data=growth_data, group = "type", group.equal = c("lv.variances"))

...并将受约束模型与不受约束模型进行比较,自由度的差异为 2,而不是我对约束单个参数所期望的 1:

fitMeasures(fit_UNconstrained, "df")
fitMeasures(fit_constrained_intercepts, "df")
fitMeasures(fit_constrained_variances, "df")

因此,我的问题是:约束各种参数(尤其是截距和方差)如何影响 lavaan 中的自由度?

我认为问题可能出在如何确定自由度上。回归模型的自由度比系数(也称为 "regressors")小一个,而不是参数。当您限制截距时,您并没有改变模型中 coefficients/regressors 的数量。

为什么限制截距不会改变自由度?

这是因为您正在对增长曲线建模:当您在 lavaan 中使用 growth() 函数时,所有截距都自动约束为零! 这就是为什么当您将“无约束”模型与您限制截距的模型进行比较时得到相同输出的原因 - 这些模型实际上 相同的。

要进一步探索这一点,请尝试使用 sem() 而不是 growth() 来 运行 您的模型拟合。我们将使用 sem() 只是为了更好地了解自由度如何变化,因为它不会自动强制执行任何约束。我们再来看看自由度:

> fitMeasures(fit_UNconstrained, "df")
 df 
416 
> fitMeasures(fit_constrained_intercepts, "df")
 df 
434

请注意,我们通过固定截距获得了 18 个自由度。我会将其分解如下:

您的模型有 20 个观测变量 (t1:t20),因此我们可能认为通过固定每个观测变量的截距,我们获得了 20 个自由度。但是,我们实际上将每个潜在变量中的所有截距限制为相同(在这种情况下,您有两个潜在变量,is)。我们不再像以前那样拟合 20 个截距,而是拟合 2 个截距(每个潜在变量一个),从而获得 18 个自由度的净增益。

为什么约束方差会使 df 改变 2?

在你的问题中你提到:

“...自由度的差异是 2,而不是我期望的约束单个参数的 1...”

不幸的是,这不太正确。在 SEM 模型中,自由度不取决于我们约束的参数“类型”的数量,而是取决于模型中“自由参数”的总数。

当你使用lv.variances时,你实际上是在约束潜在变量的方差。如上所述,你有 两个 潜在变量,is,所以你限制了一个参数每个,导致你获得两个自由度。

SEM 自由度,进一步解释:

让我们拟合一个小型SEM,然后手动计算自由度。由于您正在为增长曲线建模,我们将使用您自己的增长模型的简化版本。我们将使用三个时间点而不是二十个。

model_regressions <- ' i =~ 1*t1 + 1*t2 + 1*t3
s =~ 0*t1 + 1*t2 + 2*t3'

fit_UNconstrained <- growth(model_regressions, data=growth_data, group = "type")
summary(fit_UNconstrained) # note the use of "summary()" here

我们可以直接用这个公式计算自由度:

自由度=(独特观察的数量)-(自由参数的数量)

1.我们先计算唯一观察值的数量:

对于您的增长模型,每个组中唯一观察值的数量公式为k(k +1)/2 + k,其中 k 是您观察到的变量的数量。这是因为您对观察到的变量具有 k(k+1)/2 协方差,并且 k 观察到均值。在本例中,您有 3 个观测变量,因此每组中有 3(3+1)/2 + 3 = 9 个独特的观测值。你也有两组,所以我们实际上总共有 (9 * 2) = 18 个观察值。

2. 现在进入自由参数。我们正在拟合(每组):

  • 所有观察变量的 2 个截距(可以看作每个潜在变量的 1 个截距)
  • 观察变量的 3 个方差
  • 潜在变量的 2 个方差
  • 1 个潜在变量之间的协方差

这给了我们 8 个自由参数,但是同样,你有两组,所以 (8 * 2) 总共给了我们 16 个自由参数。

使用上述公式,18 - 16 = 2 个自由度。让我们看看 lavaan 是否同意:

> fit_UNconstrained
lavaan 0.6-3 ended normally after 64 iterations

  Optimization method                           NLMINB
  Number of free parameters                         16

  Number of observations per group         
  Exploration                                       87
  Exploitation                                     125

  Estimator                                         ML
  Model Fit Test Statistic                      62.079
  Degrees of freedom                                 2
  P-value (Chi-square)                           0.000

瞧!我希望这能让你更清楚。请记住,如果您选择使用 s ~ h_index 等修复回归,这也会改变您的自由度。通常,您应该使用 summary() 来查看您正在估计多少个自由参数,并且您可以使用 inspect(..., "sampstat") 来查看您有多少独特的观察结果。

我建议尝试一些更简单的 SEM 结构,以更好地了解它们的工作原理。祝你好运,建模愉快!