1. Paquetes necesarios.
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.4.3
## Warning: package 'tidyr' was built under R version 4.4.3
## Warning: package 'dplyr' was built under R version 4.4.3
## Warning: package 'forcats' was built under R version 4.4.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(knitr)
## Warning: package 'knitr' was built under R version 4.4.2
library(data.table)
## Warning: package 'data.table' was built under R version 4.4.3
##
## Adjuntando el paquete: 'data.table'
##
## The following objects are masked from 'package:lubridate':
##
## hour, isoweek, mday, minute, month, quarter, second, wday, week,
## yday, year
##
## The following objects are masked from 'package:dplyr':
##
## between, first, last
##
## The following object is masked from 'package:purrr':
##
## transpose
library(haven)
library(geepack)
## Warning: package 'geepack' was built under R version 4.4.3
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.4.2
## corrplot 0.95 loaded
library(psych)
## Warning: package 'psych' was built under R version 4.4.3
##
## Adjuntando el paquete: 'psych'
##
## The following objects are masked from 'package:ggplot2':
##
## %+%, alpha
library(kableExtra)
## Warning: package 'kableExtra' was built under R version 4.4.2
##
## Adjuntando el paquete: 'kableExtra'
##
## The following object is masked from 'package:dplyr':
##
## group_rows
options(scipen=999, digits=3)
2. Cargar el conjunto de datos
read_dta.
CD4_Ejercicio1 <- read_dta("C:/Users/Usuario/Desktop/iecs/ano_2/análisis_datos_longitudinales/encuentro_sincrónico_29_08_2025/CD4 Ejercicio1.dta")
3. Explorar observaciones con datos faltantes.
colSums(is.na(CD4_Ejercicio1))
## id time cd4 Age gender sex Treatment
## 0 0 42 0 0 0 0
Base de datos CD4.
LONG. Los datos se muestran en
formato LONG, donde cada fila es una medición y
time es el momento de la medición.id se repite para cada individuo de acuerdo al
número de mediciones que tuvo.age: numeric;sex: 1 = male, 0= female;treatment: 1 = yes , 0 = no;id: character;cd4: numeric (cantidad de cd4);time: numeric (tiempo de medición).Diferencia entre formato LONG y WIDE en análisis longitudinal.
En estudios longitudinales, un mismo individuo tiene varias mediciones repetidas a lo largo del tiempo.
La forma en que organizamos los datos puede ser:
Formato LONG
- Cada fila corresponde a una observación en un tiempo específico.
- Ejemplo:
| id | time | cd4 |
|---|---|---|
| 1 | 0 | 500 |
| 1 | 6 | 550 |
| 1 | 12 | 600 |
| 2 | 0 | 400 |
| 2 | 6 | 430 |
Formato WIDE
- Cada fila corresponde a un individuo y cada columna a un tiempo de
medición.
- Ejemplo:
| id | cd4_0 | cd4_6 | cd4_12 |
|---|---|---|---|
| 1 | 500 | 550 | 600 |
| 2 | 400 | 430 | NA |
👉 En la práctica:
- Usamos formato LONG para análisis longitudinales
(modelos mixtos, GEE, etc.).
- Usamos formato WIDE para correlaciones entre tiempos
o resúmenes descriptivos.
4. Consigna.
1.- Evaluar el cambio de CD4 en el tiempo ajustando por
edad y sexo como posibles confundidores.
2.- Evaluar el cambio de CD4 en función del tiempo en
HOMBRES y MUJERES.
3.- Evaluar el cambio de CD4 en función del tiempo en
los grupos de TRATAMIENTO.
Base WIDE.
CD4_Ejercicio1$Treatment <- as.numeric(CD4_Ejercicio1$Treatment)
CD4_WIDE <- CD4_Ejercicio1 %>%
pivot_wider(names_from = time, ## selecciono la variable repetida
names_prefix = "Tiempo", ## agrego el prefijo para el nuevo nombre
values_from = cd4) ### selecciono de donde va a tomar los valores
CD4_WIDE[1:10,-3]
## # A tibble: 10 × 7
## id Age sex Treatment Tiempo12 Tiempo6 Tiempo0
## <dbl+lbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 18 [DIC-107] 23 1 0 529 281 364
## 2 47 [JB-11] 30 1 0 506 605 311
## 3 11 [BKC-32] 33 1 0 735 780 554
## 4 71 [MLL-61*] 47 1 0 670 638 468
## 5 69 [ML-37] 44 1 0 365 487 281
## 6 65 [MDL-81] 38 0 0 1024 850 704
## 7 14 [CCG-45] 35 1 0 613 524 377
## 8 75 [NEC-119] 31 1 0 729 590 521
## 9 20 [DK-04] 34 1 0 682 777 652
## 10 62 [LFD-39] 26 1 0 434 372 607
pivot_wider(...) Convierte la base de formato
LONG a WIDE. Entonces, en vez de tener 3 filas
por individuo (una para cada tiempo), pasa a una sola fila con 3
columnas distintas.
CD4_WIDE[1:10, -3] Muestra solo las primeras 10 filas de
la nueva base CD4_WIDE y excluye la columna número 3.
👉 En resumen: este chunk sirve para reorganizar la base en formato WIDE y mostrar un vistazo de las primeras 10 filas sin una de las columnas. Es útil para análisis descriptivos o para ver las mediciones repetidas de CD4 en una sola línea por paciente.
Base LONG.
head(CD4_Ejercicio1[order(CD4_Ejercicio1$id, decreasing = F),]) # %>% kable()
## # A tibble: 6 × 7
## id time cd4 Age gender sex Treatment
## <dbl+lbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
## 1 1 [ACE-12] 0 311 62 M 1 1
## 2 1 [ACE-12] 6 473 62 M 1 1
## 3 1 [ACE-12] 12 408 62 M 1 1
## 4 2 [AES-47] 0 436 25 M 1 0
## 5 2 [AES-47] 6 442 25 M 1 0
## 6 2 [AES-47] 12 643 25 M 1 0
¿Existe correlación entre las medidas repetidas?
corrplot.mixed(cor(CD4_WIDE[,6:8], # selecciono las variables dependientes correlacionadas
use = "pairwise.complete"), # correlacion
lower = "number", # panel inferior = número
upper = "circle", # panel superior = Círculos
title = "Correlacion CD4") # título
Sí, hay correlación 👍.
En el gráfico:
Tiempo0 y Tiempo6 es
0.55,Tiempo0 y Tiempo12 es 0.51,Tiempo6 y Tiempo12 es 0.69.Todas son positivas y moderadas a fuertes → significa que los valores
de CD4 en un mismo paciente están relacionados a lo largo
del tiempo (lo esperable en datos longitudinales, porque un paciente con
CD4 alto al inicio tiende a tener CD4 alto
después).
🔹 ¿Para qué sirve saberlo?
👉 Resumen simple: sí hay correlación, y eso justifica que en análisis longitudinales no se usen modelos clásicos de regresión lineal sin más, sino modelos que respeten esa dependencia entre medidas repetidas.
5. Análisis longitudinal: evaluación efecto del género.
Utilizamos la base en formato LONG.
CD4_Long <- CD4_WIDE %>% # selecciono base wide
pivot_longer(
cols = starts_with("Tiempo"), # columnas que empiezan con tiempo (0, 6 ,12)
names_to = "tiempo_nuevo", # Nueba variable que va a contener tiempo(0, 6, 12)
names_transform = as.integer, # transformo tiempo a integer-numerica
names_prefix = "Tiempo", # saco la palabra tiempo para que no quede tiempo6 como valor
values_to = c("cd4_nuevo") # los valores de cd4 de cada tiempo a la nueva variable
)
head(CD4_Long)
## # A tibble: 6 × 7
## id Age gender sex Treatment tiempo_nuevo cd4_nuevo
## <dbl+lbl> <dbl> <chr> <dbl> <dbl> <int> <dbl>
## 1 18 [DIC-107] 23 M 1 0 12 529
## 2 18 [DIC-107] 23 M 1 0 6 281
## 3 18 [DIC-107] 23 M 1 0 0 364
## 4 47 [JB-11] 30 M 1 0 12 506
## 5 47 [JB-11] 30 M 1 0 6 605
## 6 47 [JB-11] 30 M 1 0 0 311
¿Estará correcto en relación a la base original?
cbind(CD4_Ejercicio1%>% select(id, time,cd4) %>% filter(id %in% 18),
CD4_Long%>% select(id, tiempo_nuevo, cd4_nuevo) %>% filter(id %in% 18))
## id time cd4 id tiempo_nuevo cd4_nuevo
## 1 18 12 529 18 12 529
## 2 18 6 281 18 6 281
## 3 18 0 364 18 0 364
🔹 ¿Qué hace ese código?
LONG
(CD4_Long) con la base original
(CD4_Ejercicio1) para un mismo paciente
(ejemplo id == 18). Muestra lado a lado los valores de
time y cd4 de la original, y
tiempo_nuevo y cd4_nuevo de la
transformada.🔹 ¿Es necesario hacerlo?
pivot_longer() o
pivot_wider(), el resultado ya debería estar correcto.🔹 ¿No alcanza con LONG?
lm,
lme, geeglm, etc.).6. Modelo de regresión lineal asumiendo INDEPENDENCIA de las observaciones.
mod_lineal <- lm(cd4~time +Age + sex, data = CD4_Ejercicio1)
summary(mod_lineal)
##
## Call:
## lm(formula = cd4 ~ time + Age + sex, data = CD4_Ejercicio1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -531.2 -149.0 -18.7 123.7 748.3
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 479.846 71.738 6.69 0.00000000013 ***
## time 17.224 2.703 6.37 0.00000000083 ***
## Age 0.857 1.529 0.56 0.58
## sex -13.929 55.412 -0.25 0.80
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 217 on 263 degrees of freedom
## (42 observations deleted due to missingness)
## Multiple R-squared: 0.135, Adjusted R-squared: 0.125
## F-statistic: 13.7 on 3 and 263 DF, p-value: 0.000000026
🔹 Supuesto
Se está usando un lm() (regresión lineal clásica), que
asume independencia de las observaciones. Pero como tus datos son
longitudinales (varias mediciones del mismo paciente), este supuesto no
es realista. Igual, sirve como “primer aproximación” para comparar
después con los modelos longitudinales que sí corrigen la
correlación.
Resultados
1. Intercepto (β0 = 479.846, p < 0.001): → Es el valor promedio de CD4 cuando time = 0, Age = 0 y sex = 0. - En la práctica, este valor “base” no tiene interpretación clínica directa (edad 0 no existe), pero marca el punto de partida del modelo.
2. Efecto del tiempo (β1 = 17.224, p = 0.008): → Cada unidad de aumento en time (probablemente meses) se asocia a un aumento promedio de 17 células CD4, ajustando por edad y sexo. ✅ Es significativo, o sea que el tiempo sí está asociado a cambios en CD4.
3. Edad (β2 = 0.857, p = 0.58): → La edad no tiene efecto significativo sobre los valores de CD4 en este modelo. Cada año de más, en promedio, se asocia con apenas +0.86 células CD4 (no significativo).
4. Sexo (β3 = -13.929, p = 0.77): → El sexo tampoco muestra un efecto significativo. Según el codificado (1 = hombre, 0 = mujer), los hombres tendrían ~14 CD4 menos en promedio que las mujeres, pero sin significancia estadística.
Conclusión rápida:
7. Modelo de regresión lineal asumiendo DEPENDENCIA de las observaciones (correlación no estructurada).
mod_gee <- geeglm(cd4 ~ time + Age + sex , # y~ covariables
data = CD4_Ejercicio1, # datos
id = CD4_Ejercicio1$id, # id= identificador del grupo al que corresponden las medidas repetidas
family = gaussian, # modelo lineal (existen otras: poisson,gaussian, etc)
corstr = "unstructured") # tipo de correlación ("exchangeable", "independence" , "ar1", etc)
options(scipen=999, digits=3)
tidy(mod_gee, conf.int = T)
## # A tibble: 4 × 7
## term estimate std.error statistic p.value conf.low conf.high
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) 481. 63.6 57.3 3.77e-14 357. 606.
## 2 time 17.6 2.81 39.2 3.78e-10 12.1 23.1
## 3 Age 0.734 1.43 0.265 6.07e- 1 -2.06 3.53
## 4 sex -13.1 48.6 0.0722 7.88e- 1 -108. 82.3
📊 Resultados principales (imagen que mostraste):
Intercepto = 481.4 (IC95%: 356.7 a 606.1, p < 0.001) → Cuando time = 0, edad = 0 y sexo = 0 (es decir, referencia: mujeres de edad 0 en el basal), el valor esperado de CD4 es ~481. → Obviamente “edad 0” es solo la referencia del modelo, no un valor real.
time = 17.6 (IC95%: 12.1 a 23.1, p < 0.001) → Por cada unidad de tiempo (ejemplo: cada visita en meses), los CD4 aumentan en promedio +17.6 células, de manera significativa. → Es el resultado más relevante: muestra una tendencia clara al aumento de CD4 a lo largo del seguimiento.
Age = 0.73 (IC95%: -2.06 a 3.53, p = 0.61) → No hay efecto significativo de la edad en la evolución de CD4. → O sea, dentro de esta cohorte, los CD4 no dependen de la edad de los participantes.
Sex = -13.1 (IC95%: -108.4 a 82.3, p = 0.79) → No se encontró diferencia significativa entre hombres y mujeres. → El valor negativo indica que los hombres tenderían a tener ~13 CD4 menos que las mujeres, pero como el intervalo es muy amplio y pasa por 0, no es concluyente.
🔎 Conclusión rápida:
Tiempo → sí tiene un efecto significativo. Los CD4 aumentan conforme pasa el tiempo.
Edad y sexo → no influyen significativamente en el cambio de CD4 en este modelo.
Ventaja del GEE → A diferencia del modelo lineal simple, aquí se está corrigiendo el problema de correlación intra-sujeto (porque cada persona tiene varias mediciones). Esto hace que los errores estándar y los IC sean más realistas.
👉 En resumen: la tendencia temporal es robusta y significativa. El resto de covariables (edad y sexo) no aportan cambios significativos en CD4 en este análisis.
8. Gráfico de predicción lineal del efecto del tiempo sobre cambio de CD4 con IC95%.
ggplot(CD4_Ejercicio1, aes(time,cd4 )) + geom_point()+
geom_smooth(method = "lm", se = TRUE) +
theme_classic()+
labs(x = "Tiempo", y = "CD4", title = "Efectos marginales")
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 42 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 42 rows containing missing values or values outside the scale range
## (`geom_point()`).
📈 Qué muestra
👉 En resumen:
9. Gráfico de predicción lineal del efecto del tiempo sobre cambio de CD4.
# Comparo predichos
datospredichosGEE <- data.frame(na.omit(CD4_Ejercicio1), ## sacamos datos faltantes
# o no podemos graficar
phat = fitted(mod_gee))
ggplot(datospredichosGEE, aes(time, phat)) +
geom_smooth(method = "lm") +
ylim (20, 1400) +
theme_classic()+
labs(x = "Tiempo", y = "CD4", title = "Efectos marginales")
## `geom_smooth()` using formula = 'y ~ x'
🔎 Interpretación:
phat), no las
observaciones originales.📌 En resumen:
time ≈ 17.6, p < 0.001).10. Modelo de regresión lineal asumiendo DEPENDENCIA y evaluando interacción entre sexo y tiempo.
mod_gee2 <- geeglm(cd4 ~ time*sex ,
data = CD4_Ejercicio1,
id = CD4_Ejercicio1$id,
corstr = "unstructured")
tidy(mod_gee2, conf.int = T)
## # A tibble: 4 × 7
## term estimate std.error statistic p.value conf.low conf.high
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) 486. 75.8 41.2 1.40e-10 338. 635.
## 2 time 20.7 9.95 4.32 3.78e- 2 1.17 40.2
## 3 sex 10.1 78.5 0.0166 8.98e- 1 -144. 164.
## 4 time:sex -3.24 10.4 0.0973 7.55e- 1 -23.6 17.1
Interpretación:
👉 El cambio de CD4 a lo largo del tiempo NO es significativamente diferente entre hombres y mujeres.
11. Análisis longitudinal: evaluación del efecto del tratamiento.
Analisis exploratorio: media de CD4 en cada medición por grupo de tratamiento
CD4_WIDE %>% group_by(Treatment) %>% summarise(T0 = mean(Tiempo0, na.rm = T),
T6 = mean(Tiempo6, na.rm = T),
T12 = mean(Tiempo12, na.rm = T))
## # A tibble: 2 × 4
## Treatment T0 T6 T12
## <dbl> <dbl> <dbl> <dbl>
## 1 0 535. 601. 648.
## 2 1 468. 631. 730.
1. Exploratorio (tabla de medias por grupo y tiempo).
Grupo 0 (sin tratamiento):
T0 = 535
T6 = 601
T12 = 648
Grupo 1 (tratamiento):
T0 = 468
T6 = 631
T12 = 730
👉 Ambos grupos aumentan CD4 con el tiempo, pero el grupo tratado arranca con menos CD4 (468 vs 535) y luego supera al no tratado (730 vs 648 a los 12 meses).
2. Respuestas a las preguntas:
¿Existen diferencias basales entre grupos? Sí. El grupo tratado tiene menor CD4 basal (~468 vs 535), diferencia observable ya desde el inicio.
¿Existe efecto del tiempo? Sí. En ambos grupos los CD4 aumentan a lo largo del seguimiento (de T0 a T6 y T12).
¿Existe efecto del tratamiento? Sí. Aunque empieza con menor CD4, el grupo tratado muestra un incremento mayor:
No tratados: +113 entre T0 y T12.
Tratados: +262 entre T0 y T12. Esto sugiere un beneficio adicional del tratamiento en la recuperación de CD4.
Conclusión rápida:
12. Modelo marginal (promedio poblacional) de regresion lineal asumiendo dependencia.
Ver efecto del tiempo (magnitud del cambio por mes) y el del tratamiento (¿existe diferencia basal de CD4 entre los grupos?)
mod_gee3 <- geeglm(cd4 ~ time +Treatment + sex ,
data = CD4_Ejercicio1,
id = CD4_Ejercicio1$id,
corstr = "unstructured")
tidy(mod_gee3, conf.int = T)
## # A tibble: 4 × 7
## term estimate std.error statistic p.value conf.low conf.high
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) 495. 54.1 83.7 0 389. 601.
## 2 time 17.7 2.84 39.0 4.15e-10 12.2 23.3
## 3 Treatment 11.9 26.2 0.206 6.50e- 1 -39.5 63.3
## 4 sex -7.77 48.7 0.0254 8.73e- 1 -103. 87.7
Este es el modelo marginal GEE (promedio poblacional)
asumiendo dependencia. Vamos a interpretar lo que aparece en el output
(mod_gee3):
Resultados principales:
Intercepto (495, p<0.001): valor promedio estimado de CD4 en el tiempo basal (T0), en el grupo de referencia (no tratados, mujeres).
Tiempo (β = 17.7, p < 0.001): cada mes se asocia con un aumento significativo de ~18 células CD4 en promedio → efecto del tiempo positivo y significativo.
Tratamiento (β = 11.9, p = 0.28): los tratados tienen, en promedio, 12 CD4 más que los no tratados, aunque esta diferencia no es estadísticamente significativa.
Sexo (β = -7.8, p = 0.73): los hombres tendrían ~8 CD4 menos que las mujeres, pero tampoco es significativo.
Respuesta a la consigna:
¿Efecto del tiempo (magnitud del cambio por mes)? Sí, significativo → +17.7 CD4/mes (p<0.001).
¿Efecto del tratamiento? En este modelo marginal, la diferencia promedio entre grupos (tratados vs no tratados) no es significativa (p=0.28), aunque la tendencia favorece al tratamiento.
¿Diferencia basal de CD4 entre los grupos? La diferencia basal no resulta significativa al ajustar en el modelo (capturada por el coeficiente de “Treatment”).
📌 Conclusión:
13. Gráfico la trayectoria de los valores de CD4 en tratados y no tratados.
mod_gee4 <- geeglm(cd4 ~ time*Treatment + sex ,
data = CD4_Ejercicio1,
id = CD4_Ejercicio1$id,
corstr = "unstructured")
tidy(mod_gee4, conf.int = T)
## # A tibble: 5 × 7
## term estimate std.error statistic p.value conf.low conf.high
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 (Intercept) 544. 53.5 104. 0 440. 649.
## 2 time 9.42 3.65 6.64 0.00998 2.25 16.6
## 3 Treatment -63.6 37.9 2.81 0.0935 -138. 10.7
## 4 sex -7.06 49.1 0.0207 0.886 -103. 89.1
## 5 time:Treatment 13.2 5.29 6.23 0.0126 2.83 23.6
Gráfico del cambio de CD4 en tratados y no tratados.
predichosTTO <- data.frame(na.omit(CD4_Ejercicio1), TTO = fitted(mod_gee4))
ggplot(predichosTTO, aes(time, TTO, colour = factor(Treatment))) +
geom_smooth(method = "lm") + theme_classic()+ ggtitle("Efectos marginales") +
labs(x = "Tiempo", y = "CD4")
## `geom_smooth()` using formula = 'y ~ x'
Resultados del modelo (mod_gee4):
Interpretación:
Conclusión: