Ich versuche, einen einfachen Weg zu finden, um so etwas wie Perls Hash-Funktionen in R zu verwenden (im Wesentlichen Caching), da ich sowohl Hashing im Perl-Stil als auch meine eigene Memoisierung von Berechnungen schreiben wollte. Andere haben mich jedoch bis zum Anschlag geschlagen und haben Pakete zum Auswendiglernen. Je mehr ich grabe, desto mehr finde ich zB memoise
und R.cache
, aber Unterschiede sind nicht ohne weiteres klar. Außerdem ist nicht klar, wie man sonst Hashes im Perl-Stil (oder Wörterbücher im Python-Stil) erhalten und eigene Memoisierungen schreiben kann, außer das hash
Paket zu verwenden, das die beiden Memoisierungspakete nicht zu untermauern scheint.
Da ich keine Informationen zu CRAN oder anderswo finden kann, um zwischen den Optionen zu unterscheiden, sollte dies möglicherweise eine Community-Wiki-Frage zu SO sein: Welche Optionen gibt es für das Speichern und Zwischenspeichern in R und welche Unterschiede gibt es?
Als Vergleichsbasis finden Sie hier eine Liste der Optionen, die ich gefunden habe. Außerdem scheint es mir, dass alle vom Hashing abhängen, daher werde ich auch die Hashing-Optionen beachten. Die Schlüssel- / Wertspeicherung ist etwas verwandt, eröffnet jedoch eine große Anzahl von Würmern in Bezug auf DB-Systeme (z. B. BerkeleyDB, Redis, MemcacheDB und viele andere ).
Es sieht so aus, als wären die Optionen:
Hashing
- Digest - Bietet Hashing für beliebige R-Objekte.
Auswendiglernen
- memoise - ein sehr einfaches Werkzeug zum Speichern von Funktionen.
- R.cache - bietet mehr Funktionen zum Auswendiglernen, obwohl einigen Funktionen anscheinend Beispiele fehlen.
Caching
- Hash - Bietet Caching-Funktionen, die Perls Hashes und Python-Wörterbüchern ähneln.
Schlüssel- / Wertspeicherung
Dies sind grundlegende Optionen für die externe Speicherung von R-Objekten.
Checkpointing
- Cacher - dies scheint eher dem Checkpointing zu ähneln .
- CodeDepends - Ein OmegaHat-Projekt,
cacher
das einige nützliche Funktionen unterstützt. - DMTCP (kein R-Paket) - scheint Checkpointing in einer Reihe von Sprachen zu unterstützen, und ein Entwickler hat kürzlich um Unterstützung beim Testen von DMTCP-Checkpointing in R gebeten .
Andere
- Base R unterstützt: benannte Vektoren und Listen, Zeilen- und Spaltennamen von Datenrahmen und Namen von Elementen in Umgebungen. Es scheint mir, dass die Verwendung einer Liste ein bisschen kludge ist. (Es gibt auch
pairlist
, aber es ist veraltet .) - Das Paket data.table unterstützt die schnelle Suche nach Elementen in einer Datentabelle.
Anwendungsfall
Obwohl ich hauptsächlich daran interessiert bin, die Optionen zu kennen, ergeben sich zwei grundlegende Anwendungsfälle:
- Caching: Einfaches Zählen von Strings. [Hinweis: Dies ist nicht für NLP, sondern für den allgemeinen Gebrauch, daher sind NLP-Bibliotheken übertrieben. Tabellen sind unzureichend, weil ich lieber nicht warten möchte, bis der gesamte Satz von Zeichenfolgen in den Speicher geladen ist. Perl-artige Hashes sind auf dem richtigen Nutzen.]
- Auswendiglernen monströser Berechnungen.
Diese entstehen wirklich, weil ich mich mit der Profilerstellung von Sloooooow-Code beschäftige und wirklich nur einfache Zeichenfolgen zählen möchte, um zu sehen, ob ich einige Berechnungen durch Memoisierung beschleunigen kann. Wenn ich in der Lage bin, die Eingabewerte zu hashen, auch wenn ich mich nicht merke, kann ich sehen, ob das Speichern hilfreich ist.
Hinweis 1: In der CRAN-Aufgabenansicht für reproduzierbare Forschung sind einige der Pakete ( cacher
und R.cache
) aufgeführt, die Verwendungsoptionen werden jedoch nicht näher erläutert.
Hinweis 2: Um anderen bei der Suche nach verwandtem Code zu helfen, finden Sie hier einige Hinweise zu einigen Autoren oder Paketen. Einige der Autoren verwenden SO. :) :)
- Dirk Eddelbuettel:
digest
- Viele andere Pakete hängen davon ab. - Roger Peng:
cacher
,filehash
,stashR
- diese Adresse unterschiedliche Probleme auf unterschiedliche Weise; Weitere Pakete finden Sie auf Rogers Website . - Christopher Brown:
hash
- Scheint ein nützliches Paket zu sein, aber die Links zu ODG sind leider nicht verfügbar. - Henrik Bengtsson:
R.cache
& Hadley Wickham:memoise
- Es ist noch nicht klar, wann ein Paket dem anderen vorzuziehen ist.
Hinweis 3: Einige Personen verwenden Memoise / Memoization, andere verwenden Memoize / Memoization. Nur eine Notiz, wenn Sie herum suchen. Henrik benutzt "z" und Hadley benutzt "s".
?environment
zBenv.profile(new.env())$size
# [1] 29Antworten:
Ich hatte kein Glück damit,
memoise
weil estoo deep recursive
Probleme mit einer Funktion eines Pakets gab, mit dem ich es versucht hatte. Mit hatteR.cache
ich besseres Glück. Es folgt ein kommentierter Code, den ich aus derR.cache
Dokumentation übernommen habe. Der Code zeigt verschiedene Optionen für das Caching.# 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 ...)
quelle
Für das einfache Zählen von Zeichenfolgen (und nicht das Verwenden
table
oder Ähnliches) scheint eine Multiset- Datenstruktur eine gute Anpassung zu sein. Dasenvironment
Objekt kann verwendet werden, um dies zu emulieren.# 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)
quelle
Bezogen auf @biocyperman Lösung . R.cache verfügt über eine Wrapping-Funktion, um das Laden, Speichern und Auswerten des Caches zu vermeiden. Siehe die geänderte Funktion:
R.cache bietet einen Wrapper zum Laden, Auswerten und Speichern. Sie können Ihren Code folgendermaßen vereinfachen:
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}) }
quelle