【问题标题】:Filter data within function over do.call通过 do.call 过滤函数内的数据
【发布时间】:2019-04-26 14:47:58
【问题描述】:

数据:

 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()。

【问题讨论】:

  • 如果没有人看过你的代码,你会如何描述你的意图?请进行编辑以更明确地反映预期输出。
  • 当然,看我的编辑。
  • 如果我运行你的函数,然后像mapply(func, hourFilt = 1:5, minutesFilt = 31:35) 一样使用mapply,我会在你的data 上得到全0,这是有道理的,因为对于第一种情况data$index[data$hour == 1 &amp; data$minutes == 31] 返回numeric(0)。你怎么得到 1?
  • 我不确定说do.call 是否“更快”是公平的,因为它们做的事情完全不同。 do.call() 只会使用一组参数调用一次函数。您似乎想使用不同的参数多次调用一个函数。这些是非常不同的操作。我不确定do.call 是否按照您的想法行事。

标签: r do.call


【解决方案1】:

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() 可能是解决您问题的最佳方法。如果您担心性能,可以尝试parallel 包中的mcmapply(),它可以并行计算(不是在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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多