do.call 基于先前 sapply(seq_along()) 迭代的输出
do.call based on output of previous sapply(seq_along()) iteration
我有一些算法的命名列表,它可能看起来像这样
> algorithm
$rBinarize
$rBinarize$x
[1] 40
并且可能包含任意数量的附加算法。每个算法对空间对象(spObj
,class 栅格)和 returns 修改后的栅格执行操作。然后我想使用 do.call
将父函数中的这个(和所有其他)算法应用于原始输入。但是,我另外想要实现的是定义算法的顺序应用,即在先前算法的输出上。我想出了以下代码,但我对提高性能的其他建议感到好奇,因为这是可能的。
if(sequential){
for(k in seq_along(algorithm)){
if(length(algorithm[[k]])==0){
args <- c(spObj = spObj)
} else{
args <- c(algorithm[[k]], spObj = spObj)
}
spObj <- do.call(what = names(algorithm)[k], args = args)
}
} else{
algorithm2 <- lapply(algorithm, function(x) x <- c(x, spObj = spObj))
modified <- sapply(seq_along(algorithm2), function(j) do.call(what = names(algorithm2)[[j]], args = algorithm2[[j]]))
}
是否可以使用某种 apply()
结构来代替 for
循环?我不确定我是否只是没有充分理解 apply
/do.call
的逻辑,或者这在 R.
中实际上是不可能的
我修改了 for-loop 以使其与 Davids 的建议相媲美,运行 对其进行了微基准测试:
microbenchmark(a = for(k in seq_along(alg)){
if(length(alg[[k]][-1])==0){
args <- c(spObj = spObj)
} else{
args <- c(alg[[k]][-1], spObj = spObj)
}
spObj <- do.call(what = alg[[k]]$algorithm, args = args)
},
b = Reduce(f = function(x, y) do.call(what = y$algorithm, args = c(list(x), y[-1])),
x = alg,
init = spObj))
这导致
Unit: milliseconds
expr min lq mean median uq max neval
a 33.36777 35.22067 39.60699 36.79661 40.75072 152.0171 100
b 33.35236 35.39173 40.32860 37.51993 40.25102 154.0441 100
这是其中一个 for 循环实际上并不比任何其他解决方案慢的示例吗?
您可以使用内置的 Reduce
函数。
举个简单的例子,假设你的链是这样的:
algorithms <- list(list(func = "sin"),
list(func = "cos"),
list(func = "log", base = 2))
您希望应用 log(cos(sin(x)), 2)
的等效项。请注意,我已将您的输入结构更改为在每个列表中都有一个名为 func
的项目,而不是名称。
然后您可以通过以下方式应用这些:
Reduce(function(x, y) do.call(y$func, c(list(x), y[-1])),
algorithms,
init = spObj)
例如,如果 spObj
以 10
开头,则结果为 -0.2249337
,您会注意到它与 log(cos(sin(spObj)), 2)
.[=20= 相同]
根据您使用的功能,您可能需要根据您的用例稍微调整一下,但通常 Reduce
就是您要查找的内容。
我有一些算法的命名列表,它可能看起来像这样
> algorithm
$rBinarize
$rBinarize$x
[1] 40
并且可能包含任意数量的附加算法。每个算法对空间对象(spObj
,class 栅格)和 returns 修改后的栅格执行操作。然后我想使用 do.call
将父函数中的这个(和所有其他)算法应用于原始输入。但是,我另外想要实现的是定义算法的顺序应用,即在先前算法的输出上。我想出了以下代码,但我对提高性能的其他建议感到好奇,因为这是可能的。
if(sequential){
for(k in seq_along(algorithm)){
if(length(algorithm[[k]])==0){
args <- c(spObj = spObj)
} else{
args <- c(algorithm[[k]], spObj = spObj)
}
spObj <- do.call(what = names(algorithm)[k], args = args)
}
} else{
algorithm2 <- lapply(algorithm, function(x) x <- c(x, spObj = spObj))
modified <- sapply(seq_along(algorithm2), function(j) do.call(what = names(algorithm2)[[j]], args = algorithm2[[j]]))
}
是否可以使用某种 apply()
结构来代替 for
循环?我不确定我是否只是没有充分理解 apply
/do.call
的逻辑,或者这在 R.
我修改了 for-loop 以使其与 Davids 的建议相媲美,运行 对其进行了微基准测试:
microbenchmark(a = for(k in seq_along(alg)){
if(length(alg[[k]][-1])==0){
args <- c(spObj = spObj)
} else{
args <- c(alg[[k]][-1], spObj = spObj)
}
spObj <- do.call(what = alg[[k]]$algorithm, args = args)
},
b = Reduce(f = function(x, y) do.call(what = y$algorithm, args = c(list(x), y[-1])),
x = alg,
init = spObj))
这导致
Unit: milliseconds
expr min lq mean median uq max neval
a 33.36777 35.22067 39.60699 36.79661 40.75072 152.0171 100
b 33.35236 35.39173 40.32860 37.51993 40.25102 154.0441 100
这是其中一个 for 循环实际上并不比任何其他解决方案慢的示例吗?
您可以使用内置的 Reduce
函数。
举个简单的例子,假设你的链是这样的:
algorithms <- list(list(func = "sin"),
list(func = "cos"),
list(func = "log", base = 2))
您希望应用 log(cos(sin(x)), 2)
的等效项。请注意,我已将您的输入结构更改为在每个列表中都有一个名为 func
的项目,而不是名称。
然后您可以通过以下方式应用这些:
Reduce(function(x, y) do.call(y$func, c(list(x), y[-1])),
algorithms,
init = spObj)
例如,如果 spObj
以 10
开头,则结果为 -0.2249337
,您会注意到它与 log(cos(sin(spObj)), 2)
.[=20= 相同]
根据您使用的功能,您可能需要根据您的用例稍微调整一下,但通常 Reduce
就是您要查找的内容。