Варианты кеширования / запоминания / хеширования в R - PullRequest
69 голосов
/ 31 августа 2011

Я пытаюсь найти простой способ использовать что-то вроде хеш-функций Perl в R (по сути, кеширование), поскольку я собирался выполнять как хеширование в стиле Perl, так и писать свои собственные запоминания вычислений.Тем не менее, другие избили меня до отказа и имеют пакеты для запоминания.Чем больше я копаю, тем больше нахожу, например, memoise и R.cache, но различия не всегда очевидны.Кроме того, неясно, как еще можно получить хеши в стиле Perl (или словари в стиле Python) и написать собственную памятку, кроме использования пакета hash, который, кажется, не лежит в основе двух пакетов памятки.

Поскольку я не могу найти информацию о CRAN или где-либо еще, чтобы различать варианты, возможно, это должен быть вопрос вики сообщества для SO: Какие есть варианты для запоминания и кэширования в R, и каковы их различия?


В качестве основы для сравнения приведен список опций, которые я нашел.Кроме того, мне кажется, что все зависит от хеширования, поэтому я также отмечу варианты хеширования.Хранилище ключей / значений в некоторой степени связано, но открывает огромную кучу червей в отношении систем БД (например, BerkeleyDB, Redis, MemcacheDB и множество других ).

Похоже, варианты:

Хеширование

  • Дайджест - обеспечивает хеширование для произвольных объектов R.

Памятка

  • memoise - очень простой инструмент для запоминания функций.
  • R.cache - предлагает больше функций для запоминания, хотя в некоторых функциях нет примеров.

Кэширование

  • hash - Обеспечивает функциональность кэширования, аналогичную хешам Perl и словарям Python.

Хранение ключей / значений

Это основные параметры для внешнего хранения объектов R.

Контрольная точка

Other

  • Base Rподдерживает: именованные векторы и списки, имена строк и столбцов фреймов данных и имена элементов в средах.Мне кажется, что использование списка является чем-то вроде клочья.(Существует также pairlist, но устарела .)
  • Пакет data.table поддерживает быстрый поиск элементов в таблице данных.

Вариант использования

Хотя я в основном заинтересован в знании опций, у меня есть два основных варианта использования:

  1. Кэширование: Простой подсчетстроки.[Примечание: это не для NLP, а для общего использования, поэтому библиотеки NLP излишни;таблицы неадекватны, потому что я предпочитаю не ждать, пока весь набор строк будет загружен в память.Хеши в стиле Perl находятся на правильном уровне полезности.]
  2. Запоминание чудовищных вычислений.

Они действительно возникают, потому что я копаюсь в профилировании некоторыхslooooow code и мне бы очень хотелось просто посчитать простые строки и посмотреть, смогу ли я ускорить некоторые вычисления с помощью запоминания.Возможность хэширования входных значений, даже если я не запоминаю, позволила бы мне понять, может ли помочь запоминание.


Примечание 1. Представление задачи CRAN для исследования воспроизводимости перечисляет пару пакетов (cacher и R.cache), но нет подробного описания вариантов использования.

Примечание 2: Чтобы помочь другим, ищущим связанный код, вот несколько замечаний по некоторым изавторы или пакеты.Некоторые из авторов используют SO.:)

  • Dirk Eddelbuettel: digest - от этого зависит множество других пакетов.
  • Роджер Пэн: cacher, filehash, stashR - они по-разному решают разные проблемы; см. сайт Роджера для получения дополнительных пакетов.
  • Кристофер Браун: hash - Кажется, это полезный пакет, но ссылки на ODG, к сожалению, недоступны.
  • Хенрик Бенгтссон: R.cache и Хэдли Уикхем: memoise - пока не ясно, когда предпочесть одну упаковку другой.

Примечание 3: Некоторые люди используют памятку / памятку, другие используют памятку / памятку. Просто заметка, если вы ищете вокруг. Хенрик использует «z», а Хэдли использует «s».

Ответы [ 3 ]

9 голосов
/ 31 июля 2014

Мне не повезло с 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 ...)
9 голосов
/ 01 сентября 2011

Для простого подсчета строк (без использования table и т. П.) Структура данных multiset кажется подходящей.Объект 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)
1 голос
/ 04 июля 2017

Относится к @ раствору биоципермана . 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})
}
...