J'essaie de trouver un moyen simple d'utiliser quelque chose comme les fonctions de hachage de Perl dans R (essentiellement la mise en cache), car j'avais l'intention de faire à la fois le hachage de style Perl et d'écrire ma propre mémoisation des calculs. Cependant, d'autres m'ont battu au poing et ont des paquets pour la mémoisation. Plus je creuse, plus j'en trouve, par exemple .memoise
et R.cache
, mais les différences ne sont pas évidentes. De plus, on ne sait pas trop comment on peut obtenir des hachages de style Perl (ou des dictionnaires de style Python) et écrire sa propre mémorisation, à part utiliser le package hash
, qui ne semble pas sous-tendre les deux packages de mémorisation.
Étant donné que je ne trouve aucune information sur CRAN ou ailleurs pour distinguer les options, cela devrait peut-être être une question wiki communautaire sur SO: quelles sont les options de mémorisation et de mise en cache dans R, et quelles sont leurs différences?
Comme base de comparaison, voici une liste des options que j'ai trouvées. De plus, il me semble que tout dépend du hachage, donc je noterai également les options de hachage. Le stockage de clé/valeur est quelque peu lié, mais ouvre une énorme boîte de vers concernant les systèmes de base de données (par exemple BerkeleyDB, Redis, MemcacheDB et des dizaines d'autres ).
Il semble que les options soient les suivantes:
Ce sont des options de base pour le stockage externe des objets R.
cacher
et fournit des fonctionnalités utiles.pairlist
, mais il est déconseillé .)Bien que je sois surtout intéressé à connaître les options, j'ai deux cas d'utilisation de base qui se présentent:
Celles-ci surviennent vraiment parce que je suis creusant dans le profilage d'un code slooooow et j'aimerais vraiment compter les chaînes simples et voir si je peux accélérer certains calculs via la mémorisation. Le fait de pouvoir hacher les valeurs d'entrée, même si je ne mémorise pas, me permettrait de voir si la mémorisation peut aider.
Remarque 1: Vue des tâches CRAN sur la recherche en matière de reproduction répertorie quelques packages (cacher
et R.cache
), mais il n'y a pas d'élaboration sur les options d'utilisation.
Note 2: Pour aider ceux qui recherchent du code associé, voici quelques notes sur certains des auteurs ou packages. Certains auteurs utilisent SO. :)
digest
- beaucoup d'autres packages en dépendent.cacher
, filehash
, stashR
- ceux-ci abordent différents problèmes de différentes manières; voir site de Roger pour plus de paquets.hash
- Semble être un package utile, mais les liens vers ODG sont malheureusement en panne.R.cache
& Hadley Wickham: memoise
- il n'est pas encore clair quand préférer un paquet à l'autre.Remarque 3: Certaines personnes utilisent memoise/memoisation, d'autres utilisent memoize/memoization. Juste une note si vous cherchez autour. Henrik utilise "z" et Hadley utilise "s".
Je n'ai pas eu de chance avec memoise
car cela a donné too deep recursive
problème avec une fonction d'un paquet avec lequel j'ai essayé. Avec R.cache
J'ai eu plus de chance. Voici un code plus annoté que j'ai adapté de R.cache
Documentation. Le code affiche différentes options pour effectuer la mise en 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 ...)
Pour un simple comptage de chaînes (et sans utiliser table
ou similaire), une structure de données multiset semble être un bon ajustement. L'objet environment
peut être utilisé pour émuler cela.
# 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)
Lié à @ solution biocyperman . R.cache a une fonction d'habillage pour éviter le chargement, l'enregistrement et l'évaluation du cache. Voir la fonction modifiée:
R.cache fournit un wrapper pour le chargement, l'évaluation et l'enregistrement. Vous pouvez simplifier votre code comme ça:
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})
}