R中mixed(afex)与lmer(lme4)拟合混合效应模型系数差异问题
为什么afex::mixed和lme4::lmer的标准化模型系数存在差异?
你遇到的核心差异来自afex::mixed的默认中心化行为,和lme4::lmer的原始尺度拟合逻辑不同。先重现你的可复现代码(R 4.2.2):
library(lme4) library(afex) library(tidyverse) library(effectsize) # 处理数据 dset_test1 <- mtcars %>% mutate(car_id = row.names(mtcars)) %>% mutate(vs = as.factor(vs)) %>% mutate(am = as.factor(am)) increase_longitudinal <- mtcars %>% dplyr::select(am, wt) %>% mutate(car_id = row.names(mtcars)) %>% mutate(wt2 = (wt)*2) dset_test <- merge(dset_test1, increase_longitudinal, by='car_id') %>% pivot_longer(cols = c(wt, wt2), names_to = 'year', values_to = 'weight') %>% mutate(year = as.factor(year)) dset_test$year <- relevel(dset_test$year, "wt")
拟合模型后,标准化系数出现明显差异,尤其是交互项符号完全相反:
afex::mixed的标准化输出
Parameter | Std. Coef. | 95% CI ------------------------------------------ (Intercept) | -0.29 | [-0.40, -0.18] year1 | -0.81 | [-0.98, -0.63] weight | -1.12 | [-1.36, -0.88] hp | -0.39 | [-0.53, -0.25] year1:weight | -0.37 | [-0.45, -0.29]
lme4::lmer的标准化输出
Parameter | Std. Coef. | 95% CI -------------------------------------------- (Intercept) | -1.05 | [-1.29, -0.81] yearwt2 | 1.54 | [ 1.21, 1.86] weight | -1.42 | [-1.72, -1.12] hp | -0.40 | [-0.54, -0.26] yearwt2:weight | 0.71 | [ 0.56, 0.86]
核心原因解析
afex::mixed默认对连续变量中心化
afex的mixed()函数默认参数center = TRUE,会自动将所有连续预测变量(这里是weight和hp)中心化到均值,而lme4的lmer()直接使用原始尺度的变量拟合模型。中心化会彻底改变模型系数的含义:
- 原始尺度下,
yearwt2:weight交互项表示「当weight为0时,year从wt到wt2的mpg变化差异」——但你的数据里weight不可能为0,这个值没有实际意义; - 中心化后,
year1:weight交互项表示「当weight处于样本均值时,year从wt到wt2的mpg变化差异」,这是更具解释性的结果,但和原始尺度的系数自然不同,甚至符号反转。
- 原始尺度下,
标准化计算的基础不同
parameters::standardize_parameters()的标准化是基于模型拟合时的变量尺度:- 对于
mixed(),标准化在中心化后的变量上进行; - 对于
lmer(),标准化在原始变量上进行。
这直接导致了系数大小和符号的差异。
- 对于
验证:关闭afex的中心化
如果你让mixed()不做中心化,拟合结果会和lmer()完全一致:
# 关闭中心化的mixed模型 mix1_no_center <- mixed(mpg~year * weight + hp +(1 | car_id), data=dset_test, center = FALSE) parameters::standardize_parameters(mix1_no_center)
运行后你会发现,标准化系数和lmer1的输出完全匹配,包括交互项的符号。
总结
afex的中心化是为了让模型结果更具解释性(避免无意义的截距、减少多重共线性),但这和lmer的原始尺度拟合形成了差异。如果需要和lmer结果对齐,只需在mixed()中设置center = FALSE即可。
内容的提问来源于stack exchange,提问作者muddypaws
相关产品推荐
相关产品推荐

