缓存函数内生成的计算量大的对象的正确方法
Correct approach to caching a computationally expensive object generated within function
背景
在以下场景中,我正在查看以下工作流程:
- 顶级运行器函数,在下面的示例中
running_function
,调用了一些较小的函数。
- 其中一些函数的计算量很大,并且会在同一组参数上重复调用,因为据称顶级脚本会调用运行器函数
例子
没有尝试缓存对象的情况可以总结如下:
工作函数
painful_function <- function(n = 100) {
matrix(1:n * n, nrow = n)
}
running_function <-
function(stat_to_do = c("min", "max", "mean", "sum"),
painful_size = 1e4) {
stat_to_do <- match.arg(stat_to_do)
M_pain <- painful_function(n = painful_size)
do.call(stat_to_do, list(M_pain))
}
实际工作
# Object M_pain is created inside running_function
running_function(stat_to_do = "min", painful_size = 100)
# I would like to re-use the M_pain object from the previous function
running_function(stat_to_do = "max", painful_size = 100)
# Re-using M_pain again...
running_function(stat_to_do = "mean", painful_size = 100)
# And again ...
running_function(stat_to_do = "sum", painful_size = 100)
期望的结果
我们的想法是不要多次调用 painful_function
,因为它生成的对象在每个场景中都是相同的。 running_function
应使用提供的参数进行评估。
方法
我正在考虑使用 mustashe
包:
library("mustashe")
running_function_mstash <-
function(stat_to_do = c("min", "max", "mean", "sum"),
painful_size = 1e4) {
stat_to_do <- match.arg(stat_to_do)
stash(var = "M_pain",
code = {
painful_function(n = painful_size)
},
depends_on = "painful_size")
do.call(stat_to_do, list(M_pain))
}
这个returns下面的错误:
running_function_mstash(stat_to_do = "min", painful_size = 1e6)
Error in make_hash(depends_on, .TargetEnv) :
Some dependencies are missing from the environment.
问题
我有兴趣学习以下内容:
- 如何进行这项工作,即
running_function
将仅在传递下来的参数之一发生变化时执行 painful_function
,否则结果对象存储在文件中
- 有什么更好的使用方法。一种微不足道的“蛮力”方法是创建一个临时的 RDS,名称古怪,并且仅在文件不存在时才执行
painful_function
。这种蹩脚的做法有明显的弊端。我想找到一个强大的解决方案,涵盖类似的、可行的场景。
可能是对象没有被检测到。根据?stash
中的例子,我们需要使用<<-
running_function_mstash <-
function(stat_to_do = c("min", "max", "mean", "sum"),
painful_size = 1e4) {
stat_to_do <- match.arg(stat_to_do)
painful_size <<- painful_size
stash(var = "M_pain",
code = {
painful_function(n = painful_size)
},
depends_on = "painful_size")
do.call(stat_to_do, list(M_pain))
}
running_function_mstash(stat_to_do = "min", painful_size = 1e6)
#Stashing object.
#[1] 1e+06
背景
在以下场景中,我正在查看以下工作流程:
- 顶级运行器函数,在下面的示例中
running_function
,调用了一些较小的函数。 - 其中一些函数的计算量很大,并且会在同一组参数上重复调用,因为据称顶级脚本会调用运行器函数
例子
没有尝试缓存对象的情况可以总结如下:
工作函数
painful_function <- function(n = 100) {
matrix(1:n * n, nrow = n)
}
running_function <-
function(stat_to_do = c("min", "max", "mean", "sum"),
painful_size = 1e4) {
stat_to_do <- match.arg(stat_to_do)
M_pain <- painful_function(n = painful_size)
do.call(stat_to_do, list(M_pain))
}
实际工作
# Object M_pain is created inside running_function
running_function(stat_to_do = "min", painful_size = 100)
# I would like to re-use the M_pain object from the previous function
running_function(stat_to_do = "max", painful_size = 100)
# Re-using M_pain again...
running_function(stat_to_do = "mean", painful_size = 100)
# And again ...
running_function(stat_to_do = "sum", painful_size = 100)
期望的结果
我们的想法是不要多次调用 painful_function
,因为它生成的对象在每个场景中都是相同的。 running_function
应使用提供的参数进行评估。
方法
我正在考虑使用 mustashe
包:
library("mustashe")
running_function_mstash <-
function(stat_to_do = c("min", "max", "mean", "sum"),
painful_size = 1e4) {
stat_to_do <- match.arg(stat_to_do)
stash(var = "M_pain",
code = {
painful_function(n = painful_size)
},
depends_on = "painful_size")
do.call(stat_to_do, list(M_pain))
}
这个returns下面的错误:
running_function_mstash(stat_to_do = "min", painful_size = 1e6)
Error in make_hash(depends_on, .TargetEnv) : Some dependencies are missing from the environment.
问题
我有兴趣学习以下内容:
- 如何进行这项工作,即
running_function
将仅在传递下来的参数之一发生变化时执行painful_function
,否则结果对象存储在文件中 - 有什么更好的使用方法。一种微不足道的“蛮力”方法是创建一个临时的 RDS,名称古怪,并且仅在文件不存在时才执行
painful_function
。这种蹩脚的做法有明显的弊端。我想找到一个强大的解决方案,涵盖类似的、可行的场景。
可能是对象没有被检测到。根据?stash
中的例子,我们需要使用<<-
running_function_mstash <-
function(stat_to_do = c("min", "max", "mean", "sum"),
painful_size = 1e4) {
stat_to_do <- match.arg(stat_to_do)
painful_size <<- painful_size
stash(var = "M_pain",
code = {
painful_function(n = painful_size)
},
depends_on = "painful_size")
do.call(stat_to_do, list(M_pain))
}
running_function_mstash(stat_to_do = "min", painful_size = 1e6)
#Stashing object.
#[1] 1e+06