如何加速这个R代码

时间:2010-10-19 18:52:22

标签: r plyr

我有一个包含18列和11520行的data.frame(link to file),我将这样转换:

library(plyr)
df.median<-ddply(data, .(groupname,starttime,fPhase,fCycle), 
                 numcolwise(median), na.rm=TRUE)

根据system.time(),运行需要很长时间:

   user  system elapsed 
   5.16    0.00    5.17

此调用是webapp的一部分,因此运行时间非常重要。有没有办法加快这个调用?

6 个答案:

答案 0 :(得分:9)

只使用aggregate要快得多......

> groupVars <- c("groupname","starttime","fPhase","fCycle")
> dataVars <- colnames(data)[ !(colnames(data) %in% c("location",groupVars)) ]
> 
> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median))
   user  system elapsed 
   1.89    0.00    1.89 
> system.time(df.median <- ddply(data, .(groupname,starttime,fPhase,fCycle), numcolwise(median), na.rm=TRUE))
   user  system elapsed 
   5.06    0.00    5.06 
> 
> ag.median <- ag.median[ do.call(order, ag.median[,groupVars]), colnames(df.median)]
> rownames(ag.median) <- 1:NROW(ag.median)
> 
> identical(ag.median, df.median)
[1] TRUE

答案 1 :(得分:7)

总结一下评论中的一些要点:

  1. 在开始优化之前,您应该对“可接受”的性能有所了解。根据所需的性能,您可以更具体地了解如何改进代码。例如,在某个阈值处,您需要停止使用R并转移到编译语言。
  2. 一旦有了预期的运行时间,您就可以对现有代码进行分析,以找出潜在的瓶颈。 R有几种机制,包括Rprof(如果你search for [r] + rprof,有关于stackoverflow的例子)。
  3. plyr主要是为了易用而不是为了提高性能而设计的(尽管最近的版本有一些不错的性能改进)。一些基本功能更快,因为它们具有更少的开销。 @JDLong指出a nice thread涵盖了其中一些问题,包括哈德利的一些专业技术。

答案 2 :(得分:4)

计算中位数时数据的顺序很重要:如果数据的顺序从最小到最大,那么计算速度会快一些。

x <- 1:1e6
y <- sample(x)
system.time(for(i in 1:1e2) median(x))
   user  system elapsed 
   3.47    0.33    3.80

system.time(for(i in 1:1e2) median(y))
   user  system elapsed 
   5.03    0.26    5.29

对于新数据集,在导入数据时按适当的列对数据进行排序。对于现有数据集,您可以将它们排序为批处理作业(在Web应用程序之外)。

答案 3 :(得分:3)

添加Joshua的解决方案。如果您决定使用均值而不是中位数,则可以将计算速度提高4倍:

> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median))
   user  system elapsed 
   3.472   0.020   3.615 
> system.time(ag.mean <- aggregate(data[,dataVars], data[,groupVars], mean))
   user  system elapsed 
   0.936   0.008   1.006 

答案 4 :(得分:3)

使用dplyr:

可以更快地处理这些数据
library(dplyr)

system.time({
  data %>% 
    group_by(groupname, starttime, fPhase, fCycle) %>%
    summarise_each(funs(median(., na.rm = TRUE)), inadist:larct)
})
#>    user  system elapsed 
#>   0.391   0.004   0.395

(你需要dplyr 0.2来获得%>%summarise_each

这比plyr更有利:

library(plyr)
system.time({
  df.median <- ddply(data, .(groupname, starttime, fPhase, fCycle), 
    numcolwise(median), na.rm = TRUE)
})
#>    user  system elapsed 
#>   0.991   0.004   0.996

aggregate()(来自@ joshua-ulrich的代码)

groupVars <- c("groupname", "starttime", "fPhase", "fCycle")
dataVars <- colnames(data)[ !(colnames(data) %in% c("location", groupVars))]
system.time({
  ag.median <- aggregate(data[,dataVars], data[,groupVars], median)
})
#>    user  system elapsed 
#>   0.532   0.005   0.537

答案 5 :(得分:2)

我只是使用标准库函数(例如,'table','tapply','aggregate'等)对大型数据框(plyr包中的棒球数据集)进行了一些简单的转换。类似的plyr函数 - 在每种情况下,我发现plyr明显更慢。如,

> system.time(table(BB$year))
    user  system elapsed 
   0.007   0.002   0.009 

> system.time(ddply(BB, .(year), 'nrow'))
    user  system elapsed 
   0.183   0.005   0.189 

其次,我确实调查这是否会提高您的性能,但对于您现在正在使用的大小的数据框架,我使用 {{3 库,可在CRAN上使用。创建data.table对象以及将现有的data.frames转换为data.tables很简单 - 只需在要转换的data.frame上调用data.table:

dt1 = data.table(my_dataframe)