Rolling mean (promedio móvil) por grupo / id con dplyr

Tengo un seguimiento longitudinal de las grabaciones de presión arterial.

El valor en un cierto punto es menos predictivo que el promedio móvil (media móvil), por lo que me gustaría calcularlo. Los datos se ven como

test <- read.table(header=TRUE, text = " ID AGE YEAR_VISIT BLOOD_PRESSURE TREATMENT 1 20 2000 NA 3 1 21 2001 129 2 1 22 2002 145 3 1 22 2002 130 2 2 23 2003 NA NA 2 30 2010 150 2 2 31 2011 110 3 4 50 2005 140 3 4 50 2005 130 3 4 50 2005 NA 3 4 51 2006 312 2 5 27 2010 140 4 5 28 2011 170 4 5 29 2012 160 NA 7 40 2007 120 NA ") 

Me gustaría calcular una nueva variable, llamada BLOOD_PRESSURE_UPDATED. Esta variable debe ser el promedio móvil para BLOOD_PRESSURE y tener las siguientes características:

  • Un promedio móvil es el valor actual más el valor anterior dividido entre dos.
  • Para la primera observación, BLOOD_PRESSURE_UPDATED es solo la BLOOD_PRESSURE actual. Si eso falta, BLOOD_PRESSURE_UPDATED debe ser la media general.
  • Los valores faltantes se deben completar con el valor anterior más cercano.

He intentado lo siguiente:

 test2 % group_by(ID) %>% arrange(ID, YEAR_VISIT) %>% mutate(BLOOD_PRESSURE_UPDATED = rollmean(x=BLOOD_PRESSURE, 2)) %>% ungroup() 

También probé con rollaply y rollmeanr sin éxito.

Apreciaría algo de ayuda.

Si no está comprometido con dplyr esto debería funcionar:

 get.mav <- function(bp,n=2){ require(zoo) if(is.na(bp[1])) bp[1] <- mean(bp,na.rm=TRUE) bp <- na.locf(bp,na.rm=FALSE) if(length(bp) 

Esto también funciona para promedios móviles> 2.

Y aquí hay una solución data.table, que es probable que sea mucho más rápida si su conjunto de datos es grande.

 library(data.table) setDT(test) # converts test to a data.table in place setkey(test,ID,YEAR_VISIT) test[,BLOOD_PRESSURE_UPDATED:=as.numeric(get.mav(BLOOD_PRESSURE,2)),by=ID] test # ID AGE YEAR_VISIT BLOOD_PRESSURE TREATMENT BLOOD_PRESSURE_UPDATED # 1: 1 20 2000 NA 3 134.6667 # 2: 1 21 2001 129 2 131.8333 # 3: 1 22 2002 145 3 137.0000 # 4: 1 22 2002 130 2 137.5000 # 5: 2 23 2003 NA NA 130.0000 # 6: 2 30 2010 150 2 140.0000 # 7: 2 31 2011 110 3 130.0000 # ... 

¿Qué tal esto?

  library(dplyr) test2<-arrange(test,ID,YEAR_VISIT) %>% mutate(lag1=lag(BLOOD_PRESSURE), lag2=lag(BLOOD_PRESSURE,2), movave=(lag1+lag2)/2) 

Otra solución que usa la función ‘rollapply’ en el paquete de zoológico (me gusta más)

 library(dplyr) library(zoo) test2<-arrange(test,ID,YEAR_VISIT) %>% mutate(ma2=rollapply(BLOOD_PRESSURE,2,mean,align='right',fill=NA))