Задний план

В следующем сценарии я рассматриваю следующий рабочий процесс:

  1. Функция-исполнитель верхнего уровня, в примере ниже running_function, вызывает ряд более мелких функций.
  2. Некоторые из этих функций требуют больших вычислительных ресурсов и будут вызываться с одним и тем же набором аргументов неоднократно, поскольку функции-исполнители вызываются, по общему мнению, сценарием верхнего уровня.

Примере

Без попытки кэширования объектов ситуацию можно резюмировать следующим образом:

Рабочие функции

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))
}

Это возвращает следующую ошибку:

running_function_mstash(stat_to_do = "min", painful_size = 1e6)

Ошибка в make_hash (depends_on, .TargetEnv): в среде отсутствуют некоторые зависимости.

Вопросы

Мне интересно узнать следующее:

  1. Как это сделать, т.е. running_function будет выполнять painful_function только в случае изменения одного из переданных аргументов, если не полученный объект сохраняется из файла
  2. Какие есть подходы к использованию этого лучше? Тривиальным методом «грубой силы» было бы создать временный RDS с забавным именем и выполнить painful_function только в том случае, если файл не существует. Этот хромой подход и имеет очевидные недостатки. Я хотел бы найти надежное решение, охватывающее аналогичный работоспособный сценарий.
2
Konrad 27 Ноя 2020 в 01:40

1 ответ

Лучший ответ

Возможно, объект не обнаруживается. Согласно примеру в ?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
1
akrun 26 Ноя 2020 в 23:43