如何使用非唯一行优化迭代庞大的数据帧

时间:2018-05-01 05:40:13

标签: r for-loop optimization dplyr data.table

据我所知,如果R没有在for循环的范围内更新变量,那么我只是做了一些非常缓慢而昂贵的代码。不幸的是,在一系列非常紧迫的期限和C ++ / Java的强大背景下,这是我的首选行为,直到我可以开始我的R帽。

我有一个需要改进的功能。它需要一个数据帧(如下所示)返回唯一的 patid 值,并使用这些值来检索该数据帧的子集以进行日期修改。下面是一个修剪过的例子(注意,我刚从完成的运行中拉出来,所以日期已被修改)。我执行的最后一次R运行超过了2700万行的数据帧,大约需要四五个小时。数据框的大小会更大。

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 :(得分:2)

由于您希望对patid&amp; 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))

答案 1 :(得分:1)

这非常适合data.table:您的数据有一个明确定义的键,您按(patid,eventdate)进行分组,您知道输出df的大小将是&lt; =输入df的大小,这样可以安全地进行就地分配(更快),而不是追加,你不需要输出迭代附加,而data.table有一个很好的快速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()