{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreiho4ysv4443fthborvfgaaxqujzgifbqhgra7buws3ckxowlarwee",
"uri": "at://did:plc:wwyqal4cnqhuwyacdj7rqq3n/app.bsky.feed.post/3mjlhidogwpe2"
},
"path": "/t/power-calculations-in-longitudinal-mixed-effects-from-two-measurements-to-three-measurements/28699#post_10",
"publishedAt": "2026-04-15T16:35:48.000Z",
"site": "https://discourse.datamethods.org",
"textContent": "Thank you, both.\n\nWere these the models you had in mind?\n\n\n library(nlme)\n library(lme4)\n library(emmeans)\n library(ggplot2)\n library(dplyr)\n\n ── 1. Data\n\n url_raw ← “https://github.com/jorgemmteixeira/nlmeU-datset/raw/main/data/armd0.rda”\n load(url(url_raw))\n\n Filter to post-baseline rows (baseline visual0 remains as a fixed covariate)\n\n armd0_sub ← armd0[armd0$time > 0, ]\n armd0_sub$time_f_ord ← factor(armd0_sub$time.f, ordered = TRUE)\n armd0_sub$subject ← as.factor(armd0_sub$subject)\n\n Compute and plot empirical variogram\n\n vgm_emp ← Variogram(gls_ols, form = ~ time | subject)\n plot(vgm_emp, main = “Empirical Semi-variogram (Initial Check)”)\n\n ── 2. Model Fitting (No Random Slopes) ─────────────────────────────────────\n\n — nlme GLS (Marginal Models) —\n\n gls_ar1 ← gls(visual ~ visual0 + time * treat.f, data = armd0_sub,\n correlation = corAR1(form = ~ tp | subject), method = “REML”)\n\n gls_exp ← gls(visual ~ visual0 + time * treat.f, data = armd0_sub,\n correlation = corExp(form = ~ time | subject), method = “REML”)\n\n gls_unstr ← gls(visual ~ visual0 + time * treat.f, data = armd0_sub,\n correlation = corSymm(form = ~ tp | subject),\n weights = varIdent(form = ~ 1 | time.f), method = “REML”)\n\n — lme4 LMM (Conditional Models - Random Intercept Only) —\n\n lme_cs ← lmer(visual ~ visual0 + time * treat.f + (1 | subject), data = armd0_sub)\n lme_ar1 ← lmer(visual ~ visual0 + time * treat.f + ar1(time_f_ord + 0 | subject), data = armd0_sub)\n lme_diag ← lmer(visual ~ visual0 + time * treat.f + diag(time.f + 0 | subject), data = armd0_sub)\n\n — Markov Transition Model (OLS) —\n\n armd_lag ← armd0_sub\n\n group_by(subject)\n\n mutate(visual_prev = lag(visual))\n\n filter(!is.na(visual_prev))\n\n markov_ols ← lm(visual ~ visual0 + visual_prev + time * treat.f, data = armd_lag)\n\n ── 3. Extract Estimates and Calculate CI Widths ────────────────────────────\n\n extract_52 ← function(mod, name) {\n emm ← emmeans(mod, pairwise ~ treat.f | time, at = list(time = 52))\n res ← as.data.frame(summary(emm$contrasts, infer = TRUE))\n data.frame(Model = name, Estimate = res$estimate, Lower = res$lower.CL,\n Upper = res$upper.CL, P_Value = res$p.value)\n }\n\n Combine all except Markov\n\n results ← rbind(\n extract_52(gls_ar1, “GLS AR(1)”),\n extract_52(gls_exp, “GLS Exp”),\n extract_52(gls_unstr, “GLS Unstr”),\n extract_52(lme_cs, “LMM CS”),\n extract_52(lme_ar1, “LMM AR(1)”),\n extract_52(lme_diag, “LMM Diag”)\n )\n\n Add Markov Manually (Calculated at t=52)\n\n m_summ ← summary(markov_ols)$coefficients\n m_est ← m_summ[“treat.fActive”,1] + m_summ[“time:treat.fActive”,1] * 52\n m_se ← sqrt(vcov(markov_ols)[“treat.fActive”,“treat.fActive”] +\n (52^2)vcov(markov_ols)[“time:treat.fActive”,“time:treat.fActive”])\n results ← rbind(results, data.frame(\n Model = “Markov OLS”, Estimate = m_est, Lower = m_est - 1.96m_se,\n Upper = m_est + 1.96*m_se, P_Value = 2 * (1 - pnorm(abs(m_est/m_se)))\n ))\n\n ── 4. Summary Table (Ordered by CI Width) ──────────────────────────────────\n\n final_table ← results\n\n mutate(CI_Width = Upper - Lower)\n\n arrange(CI_Width)\n\n select(Model, Estimate, Lower, Upper, CI_Width, P_Value)\n\n print(final_table)\n",
"title": "Power Calculations in Longitudinal Mixed Effects - from two measurements to three measurements"
}