Как оптимизировать итерации по огромному фрейму данных с неуникальными строками - PullRequest
0 голосов
/ 01 мая 2018

Я понимаю, что если R не обновляет переменную на месте в пределах цикла for, то я только что сделал ужасно медленный и дорогой код. К сожалению, с набором очень сжатых сроков и сильным опытом в C ++ / Java, я продолжаю работать, пока не смогу надеть R Hat.

У меня есть функция, которую мне нужно улучшить. Он принимает фрейм данных (как показано ниже), возвращает уникальные значения detad и использует их для извлечения подмножеств этого фрейма данных для изменений даты. Уточненный пример ниже (обратите внимание, я только что извлек это из завершенного прогона, поэтому дата уже была изменена). Последний прогон R, который я выполнил, длился более 27 миллионов строк данных и занял около четырех-пяти часов. Размер информационного кадра будет намного больше.

patid eventdate
1     12/03/1998   
1     12/03/1998   
2     04/03/2007   
3     15/11/1980   
3     15/11/1980   
3     01/02/1981  

Урезанный пример функции:

rearrangeDates <- function(dataFrame) {
   #return a list of the unique patient ids
   uniquePatids <- getUniquePatidList(dataFrame) #this is only called once and is very fast

    out=NULL
    for(i in 1:length(uniquePatids)) { # iterate over the list 
        idf <- subset(dataFrame, dataFrame$patid=uniquePatids[[i]])
        idf$eventdate <- as.POSIXct(idf$eventdate,format="%d/%m/%Y")
        idf <- idf[order(idf$eventdate,decreasing=FALSE),]
        out = rbind(out,idf)
    }
    return(out)
}

Кто-нибудь может предложить улучшения?

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Поскольку вы хотите отсортировать данные по patid & eventdate, это должно сработать.

library(dplyr)

df %>% 
  mutate(eventdate = as.Date(eventdate, format="%d/%m/%Y")) %>% 
  arrange(patid, eventdate)

Вывод:

  patid  eventdate
1     1 1998-03-12
2     1 1998-03-12
3     2 2007-03-04
4     3 1980-11-15
5     3 1980-11-15
6     3 1981-02-01

Пример данных:

df <- structure(list(patid = c(1L, 1L, 2L, 3L, 3L, 3L), eventdate = c("12/03/1998", 
"12/03/1998", "04/03/2007", "15/11/1980", "15/11/1980", "01/02/1981"
)), class = "data.frame", row.names = c(NA, -6L))
0 голосов
/ 01 мая 2018

Это идеально подходит для data.table: ваши данные имеют четко определенный ключ, который вы группируете по (patid,eventdate), вы знаете, что размер выходного df будет <= размер входного df, поэтому безопасно делайте назначения на месте (быстрее, быстрее) вместо добавлений, вам не нужно выводить iterative-append, а data.table имеет хорошую быструю <code>unique функцию. Поэтому, пожалуйста, попробуйте (без цикла!) Приведенный ниже код и дайте нам знать, как он сравнивается как с вашим исходным, так и с dplyr подходом:

require(data.table)
dt = data.table(patid=c(1,1,2,3,3,3), eventdate=c('12/03/1998','12/03/1998',
         '04/03/2007', '15/11/1980', '15/11/1980','01/02/1981'))  
dt[, eventdate := as.POSIXct(eventdate,format="%d/%m/%Y") ]

# If you set a key, the `by` operation will be super-fast
setkeyv(dt, c('patid','eventdate'))

odt <- dt[, by=.(patid,eventdate)]

   patid  eventdate
1:     1 1998-03-12
2:     1 1998-03-12
3:     2 2007-03-04
4:     3 1980-11-15
5:     3 1980-11-15
6:     3 1981-02-01

(И последнее: не бойтесь POSIXct / lt, конвертируйте их раньше, они более эффективны, чем строки, они поддерживают операторы сравнения, поэтому столбец можно использовать в качестве ключа, сортировать по, сравнивать.)

(И для самой быстрой реализации dplyr используйте dplyr::distinct())

...