8

我有一个包含 18 列和 11520 行的 data.frame (链接到文件),我像这样转换:

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 的一部分,所以运行时间非常重要。有没有办法加快这个调用?

4

6 回答 6

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
于 2010-10-19T19:51:24.940 回答
7

只是总结一下评论中的一些观点:

  1. 在开始优化之前,您应该对“可接受的”性能有所了解。根据所需的性能,您可以更具体地了解如何改进代码。例如,在某个阈值下,您将需要停止使用 R 并转向编译语言。
  2. 一旦有了预期的运行时间,就可以分析现有代码以发现潜在的瓶颈。R 对此有多种机制,包括 Rprof (如果您搜索 [r] + rprof ,会有关于 stackoverflow 的示例)。
  3. plyr主要是为了易于使用而设计的,而不是为了性能(尽管最近的版本有一些不错的性能改进)。一些基本函数更快,因为它们的开销更少。@JDLong 指出了一个很好的线程,涵盖了其中一些问题,包括 Hadley 的一些专门技术。
于 2010-10-19T19:49:18.867 回答
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 应用程序之外)进行排序。

于 2010-10-20T13:57:29.817 回答
3

添加到约书亚的解决方案中。如果您决定使用均值而不是中位数,则可以将计算速度再加快 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 
于 2010-10-19T21:11:39.247 回答
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
于 2014-04-16T15:21:01.437 回答
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 

其次,我没有调查这是否会在您的情况下提高性能,但是对于您现在正在使用的大小和更大的数据框,我使用 CRAN 上提供的data.table库。创建 data.table 对象以及将现有的 data.frames 转换为 data.tables 很简单——只需在要转换的 data.frame 上调用 data.table 即可:

dt1 = data.table(my_dataframe)
于 2010-10-19T20:57:43.940 回答