Варианты кеширования / запоминания / хеширования в R
Я пытаюсь найти простой способ использовать что-то вроде хеш-функций Perl в R (по сути, кеширование), так как я собирался выполнять как хеширование в стиле Perl, так и писать свои собственные запоминания вычислений. Тем не менее, другие избили меня до отказа и имеют пакеты для запоминания. Чем больше я копаю, тем больше нахожу, например memoise
а также R.cache
, но различия не всегда понятны. Кроме того, неясно, как еще можно получить хеши в стиле Perl (или словари в стиле Python) и написать свои собственные памятки, кроме как использовать hash
пакет, который, кажется, не лежит в основе двух пакетов памятки.
Поскольку я не могу найти информацию о CRAN или где-либо еще, чтобы различать варианты, возможно, это должен быть вопрос вики сообщества для SO: Какие есть варианты для запоминания и кэширования в R, и каковы их различия?
В качестве основы для сравнения, вот список вариантов, которые я нашел. Кроме того, мне кажется, что все зависит от хеширования, поэтому я также отмечу варианты хеширования. Хранилище ключей / значений в некоторой степени связано, но открывает огромную кучу червей в отношении систем БД (например, BerkeleyDB, Redis, MemcacheDB и множество других).
Похоже, варианты:
хеширования
- digest - обеспечивает хеширование для произвольных объектов R.
мемоизации
- memoise - очень простой инструмент для запоминания функций.
- R.cache - предлагает больше возможностей для запоминания, хотя, похоже, в некоторых функциях отсутствуют примеры.
Кэширование
- hash - обеспечивает функциональность кэширования, аналогичную хешам Perl и словарям Python.
Хранение ключа / значения
Это базовые параметры для внешнего хранения объектов R.
Checkpointing
- cacher - это похоже на контрольно-пропускной пункт.
- CodeDepends - проект OmegaHat, который лежит в основе
cacher
и предоставляет некоторые полезные функции. - DMTCP (не пакет R) - кажется, поддерживает контрольные точки на нескольких языках, и разработчик недавно обратился за помощью в тестировании контрольных точек DMTCP в R.
Другой
- Base R поддерживает: именованные векторы и списки, имена строк и столбцов фреймов данных и имена элементов в средах. Мне кажется, что использование списка является чем-то вроде клочья. (Есть также
pairlist
, но это устарело.) - Пакет data.table поддерживает быстрый поиск элементов в таблице данных.
Случай использования
Хотя я в основном заинтересован в знании опций, у меня есть два основных варианта использования:
- Кэширование: простой подсчет строк. [Примечание: это не для NLP, а для общего использования, поэтому библиотеки NLP излишни; таблицы неадекватны, потому что я предпочитаю не ждать, пока весь набор строк будет загружен в память. Хеши в стиле Perl находятся на правильном уровне полезности.]
- Запоминание чудовищных расчетов.
Они действительно возникают из-за того, что я копаюсь в профилировании некоторого slooooow-кода, и мне бы очень хотелось просто посчитать простые строки и посмотреть, смогу ли я ускорить некоторые вычисления с помощью запоминания. Возможность хэшировать входные значения, даже если я не запоминаю, позволит мне увидеть, поможет ли запоминание.
Примечание 1. В представлении задач CRAN в разделе " Воспроизводимые исследования" перечислено несколько пакетов (cacher
а также R.cache
), но нет подробного описания вариантов использования.
Примечание 2: Чтобы помочь другим, ищущим связанный код, вот несколько заметок о некоторых авторах или пакетах. Некоторые из авторов используют SO.:)
- Дирк Эддельбюттель:
digest
- от этого зависит множество других пакетов. - Роджер Пэн:
cacher
,filehash
,stashR
- они решают разные проблемы по-разному; см . сайт Роджера для большего количества пакетов. - Кристофер Браун:
hash
- Кажется, полезный пакет, но ссылки на ODG, к сожалению, не работают. - Хенрик Бенгтссон:
R.cache
И Хэдли Уикхем:memoise
- пока не ясно, когда отдать предпочтение одному пакету над другим.
Примечание 3: Некоторые люди используют памятку / памятку, другие используют памятку / памятку. Просто заметка, если вы ищете вокруг. Хенрик использует "z", а Хэдли - "s".
3 ответа
Мне не повезло с memoise
потому что это дало too deep recursive
проблема с какой-то функцией упакованного я пробовал. С R.cache
Мне повезло больше Ниже приведен более аннотированный код, который я адаптировал из R.cache
документация. В коде показаны разные варианты кеширования.
# Workaround to avoid question when loading R.cache library
dir.create(path="~/.Rcache", showWarnings=F)
library("R.cache")
setCacheRootPath(path="./.Rcache") # Create .Rcache at current working dir
# In case we need the cache path, but not used in this example.
cache.root = getCacheRootPath()
simulate <- function(mean, sd) {
# 1. Try to load cached data, if already generated
key <- list(mean, sd)
data <- loadCache(key)
if (!is.null(data)) {
cat("Loaded cached data\n")
return(data);
}
# 2. If not available, generate it.
cat("Generating data from scratch...")
data <- rnorm(1000, mean=mean, sd=sd)
Sys.sleep(1) # Emulate slow algorithm
cat("ok\n")
saveCache(data, key=key, comment="simulate()")
data;
}
data <- simulate(2.3, 3.0)
data <- simulate(2.3, 3.5)
a = 2.3
b = 3.0
data <- simulate(a, b) # Will load cached data, params are checked by value
# Clean up
file.remove(findCache(key=list(2.3,3.0)))
file.remove(findCache(key=list(2.3,3.5)))
simulate2 <- function(mean, sd) {
data <- rnorm(1000, mean=mean, sd=sd)
Sys.sleep(1) # Emulate slow algorithm
cat("Done generating data from scratch\n")
data;
}
# Easy step to memoize a function
# aslo possible to resassign function name.
This would work with any functions from external packages.
mzs <- addMemoization(simulate2)
data <- mzs(2.3, 3.0)
data <- mzs(2.3, 3.5)
data <- mzs(2.3, 3.0) # Will load cached data
# aslo possible to resassign function name.
# but different memoizations of the same
# function will return the same cache result
# if input params are the same
simulate2 <- addMemoization(simulate2)
data <- simulate2(2.3, 3.0)
# If the expression being evaluated depends on
# "input" objects, then these must be be specified
# explicitly as "key" objects.
for (ii in 1:2) {
for (kk in 1:3) {
cat(sprintf("Iteration #%d:\n", kk))
res <- evalWithMemoization({
cat("Evaluating expression...")
a <- kk
Sys.sleep(1)
cat("done\n")
a
}, key=list(kk=kk))
# expressions inside 'res' are skipped on the repeated run
print(res)
# Sanity checks
stopifnot(a == kk)
# Clean up
rm(a)
} # for (kk ...)
} # for (ii ...)
Для простого подсчета строк (а не использования table
или аналогичный), многосетевая структура данных выглядит как подходящая. environment
объект может быть использован для эмуляции этого.
# Define the insert function for a multiset
msetInsert <- function(mset, s) {
if (exists(s, mset, inherits=FALSE)) {
mset[[s]] <- mset[[s]] + 1L
} else {
mset[[s]] <- 1L
}
}
# First we generate a bunch of strings
n <- 1e5L # Total number of strings
nus <- 1e3L # Number of unique strings
ustrs <- paste("Str", seq_len(nus))
set.seed(42)
strs <- sample(ustrs, n, replace=TRUE)
# Now we use an environment as our multiset
mset <- new.env(TRUE, emptyenv()) # Ensure hashing is enabled
# ...and insert the strings one by one...
for (s in strs) {
msetInsert(mset, s)
}
# Now we should have nus unique strings in the multiset
identical(nus, length(mset))
# And the names should be correct
identical(sort(ustrs), sort(names(as.list(mset))))
# ...And an example of getting the count for a specific string
mset[["Str 3"]] # "Str 3" instance count (97)
Связано с решением @biocyperman. R.cache имеет функцию обертки, позволяющую избежать загрузки, сохранения и оценки кэша. Смотрите измененную функцию:
R.cache предоставляет оболочку для загрузки, оценки, сохранения. Вы можете упростить свой код следующим образом:
simulate <- function(mean, sd) {
key <- list(mean, sd)
data <- evalWithMemoization(key = key, expr = {
cat("Generating data from scratch...")
data <- rnorm(1000, mean=mean, sd=sd)
Sys.sleep(1) # Emulate slow algorithm
cat("ok\n")
data})
}