2014-10-05 4 views
7

У меня есть продольное наблюдение за записями артериального давления.Подвижность среднего (скользящее среднее) по группе/id с dplyr

Значение в определенной точке менее прогнозирующее, чем скользящее среднее (среднее значение поворота), поэтому я хотел бы рассчитать его. Полученные данные выглядят как

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 
        ") 

Я бы хотел рассчитать новую переменную, называемую BLOOD_PRESSURE_UPDATED. Эта переменная должна быть скользящей средней для BLOOD_PRESSURE и иметь следующие характеристики:

  • Скользящее среднее - текущее значение плюс предыдущее значение, деленное на два.
  • Для первого наблюдения BLOOD_PRESSURE_UPDATED является только текущим BLOOD_PRESSURE. Если это отсутствует, BLOOD_PRESSURE_UPDATED должно быть общим средним значением.
  • Отсутствующие значения должны быть заполнены с ближайшим предыдущим значением.

Я попытался следующие:

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

Я также попытался rollaply и rollmeanr без успеха.

Буду признателен за помощь.

+1

При расчете скользящего среднего, число элементов, возвращаемых меньше количества строк данных, то есть только " n-1 ". Таким образом, может возникнуть проблема здесь. Или вы рассмотрели бы добавление столбца скользящей средней отдельно, например: test2 $ BLOOD_PRESSURE_UPDATED <- with (test2, c (среднее значение (BLOOD_PRESSURE, na.rm = T), rollapply (BLOOD_PRESSURE, 2, mean, na.rm = T))) – KFB

+0

Спасибо за усилие KFB. К сожалению, это не сработало. Я попробовал несколько отредактированных версий. Возможно, зоо-функции не подходят для этого? Я закодировал следующее, что работает: test5 <- test test5 $ UM <- rep (NA, nrow (test5)) test5 $ first <-! Duplicated (test5 $ ID) для (i in 1: nrow (test5)) { if (test5 $ first [i]) { test5 $ UM [i] <- test5 $ BLOOD_PRESSURE [i] } else { test5 $ UM [i] <- среднее (c (test5 $ BLOOD_PRESSURE [i], test5 $ UM [i-1]), na.rm = TRUE) } } test5 Но это невероятно медленно. –

ответ

6

Если вы не обязаны в dplyr это должно работать:

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)<n) return(bp) 
    c(bp[1:(n-1)],rollapply(bp,width=n,mean,align="right")) 
} 
test <- with(test,test[order(ID,YEAR_VISIT),]) 

test$BLOOD_PRESSURE_UPDATED <- 
    unlist(aggregate(BLOOD_PRESSURE~ID,test,get.mav,na.action=NULL,n=2)$BLOOD_PRESSURE) 
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 
# ... 

Это работает для скользящих средних> 2, а также.

И вот решение data.table, которое, вероятно, будет намного быстрее, если ваш набор данных большой.

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 
# ... 
+0

Спасибо @jlhoward! - он решил проблему, но данные.table (который был более быстрым из двух) был очень медленным (3 миллиона строк, 15 минут на новом MBP). Но тем не менее проблема решена. –

+0

Спасибо @jlhoward. Это спасло мне длительное время вычисления ... Я использовал ddply раньше, и время было действительно плохо! – EsBee

6

Как насчет этого?

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

Другое решение с использованием «rollapply» функцию в пакете зоопарка (мне нравится больше)

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

Обратите внимание, что аргумент align может быть удален при использовании rollapplyr. –

Смежные вопросы