在 do.call 的函数内过滤数据
Filter data within function over 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))
我知道警告的含义:
Warning messages:
1: In data$hour == hourFilt :
longer object length is not a multiple of shorter object length
但我希望该函数被调用五次而不是一次,从而导致该警告和错误结果。
预期结果:
mapply(func, hourFilt = 1:5, minutesFilt = 31:35)
1 2 0 0 0
不过,我更喜欢使用 do.call()
,因为它更快。
编辑:添加意图
我想在特定时间过滤 25k-200k 行的数据集。对原始数据集的过滤将产生三行。对于这个结果,我想总结一个给定的变量——在这里:索引。该过程将重复数百次。因此,我调查了mapply()
、do.call()
。性能确实很重要,这就是为什么我更喜欢 do.call()
。
do.call
的目的不是多次 运行 一个函数,例如 mapply 会做的,而是 运行 一次遍历元素列表的函数。这在处理大型列表并尝试将单个函数应用于列表的所有参数时非常实用。一个典型的例子是 do.call(cbind,list)
,如果你想创建一个 table,其中每一列都是列表的一个元素。
所以,当你 运行 do.call(func, list(hourFilt = 1:5, minutesFilt = 31:35))
R 是 运行ning
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
数据:
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))
我知道警告的含义:
Warning messages: 1: In data$hour == hourFilt : longer object length is not a multiple of shorter object length
但我希望该函数被调用五次而不是一次,从而导致该警告和错误结果。
预期结果:
mapply(func, hourFilt = 1:5, minutesFilt = 31:35)
1 2 0 0 0
不过,我更喜欢使用 do.call()
,因为它更快。
编辑:添加意图
我想在特定时间过滤 25k-200k 行的数据集。对原始数据集的过滤将产生三行。对于这个结果,我想总结一个给定的变量——在这里:索引。该过程将重复数百次。因此,我调查了mapply()
、do.call()
。性能确实很重要,这就是为什么我更喜欢 do.call()
。
do.call
的目的不是多次 运行 一个函数,例如 mapply 会做的,而是 运行 一次遍历元素列表的函数。这在处理大型列表并尝试将单个函数应用于列表的所有参数时非常实用。一个典型的例子是 do.call(cbind,list)
,如果你想创建一个 table,其中每一列都是列表的一个元素。
所以,当你 运行 do.call(func, list(hourFilt = 1:5, minutesFilt = 31:35))
R 是 运行ning
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