通过do.call在函数内过滤数据

时间:2019-04-26 14:47:58

标签: r do.call

数据:

 data <- structure(list(index = c(1, 2, 3, 4, 5, 6), 
hour = c(13, 13, 13, 1, 1, 1), minutes = c(31, 
     31, 32, 36, 36, 36)), class = "data.frame", row.names = c(1067L, 
    1069L, 1070L, 1072L, 1073L, 1074L))

使用do.call

func <- function(hourFilt, minutesFilt){
  filt <- data[data$hour == hourFilt & data$minutes == minutesFilt, ]$idx
  sum(filt)
}

do.call(func, list(hourFilt = 1:5, minutesFilt = 31:35))

我知道警告的含义:

  

警告消息:   1:在data $ hour == hourFilt中:     较长的物体长度不是较短的物体长度的倍数

但是我希望该函数被调用五次,而不仅仅是被调用一次,从而导致警告和错误的结果。

预期结果:

mapply(func, hourFilt = 1:5, minutesFilt = 31:35)
1 2 0 0 0 

但是,我更喜欢使用do.call(),因为它更快。

修改:添加意图 我想过滤特定时间的25k-200k行的数据集。对原始数据集的过滤将导致三行。对于这个结果,我想总结一个给定的变量-在这里:索引。该过程将重复数百次。因此,我调查了mapply()do.call()。性能确实很重要,这就是为什么我更喜欢do.call()

1 个答案:

答案 0 :(得分:3)

do.call的目的不是多次运行一个函数(如mapply那样),而是一次在一个元素列表上运行一个函数。当使用大型列表并尝试将单个函数应用于列表的所有参数时,这非常实用。如果要创建一个表格,其中每一列都是列表的元素,则典型示例为do.call(cbind,list)

因此,当您运行do.call(func, list(hourFilt = 1:5, minutesFilt = 31:35))时R正在运行

func(hourFilt = 1:5, minutesFilt = 31:35)

因此您得到了错误。列表中的所有元素都立即传递给func()的参数。

我认为mapply()可能是解决您问题的最佳方法。如果您担心性能,可以尝试使用mcmapply()软件包中的parallel,该软件包可以并行化计算(在Windows中不适用)。

corenum <- parallel::detectCores()-1
parallel::mcmapply(func,hourFilt=1:5,minutesFilt=31:35,mc.cores=corenum)

或者,如果您使用的是Windows,则更麻烦的parSapply()可能适合您:

corenum <- parallel::detectCores()-1
cl<-parallel::makeCluster(corenum)

#export the objects so that the parallel sockets can use them
parallel::clusterExport(cl,c("func","hourFilt","minutesFilt","data"))

result<-parallel::parSapply(cl,1:length(hourFilt),function(i){
  func(hourFilt[i],minutesFilt[i])
})

PS:对于您的数据集,预期结果应为0 0 0 0 0