web-dev-qa-db-ja.com

Rでのキャッシュ/メモ化/ハッシュのオプション

私は、Perlのハッシュ関数のようなものをR(本質的にはキャッシュ)で使用する簡単な方法を見つけようとしています。これは、Perlスタイルのハッシュを実行し、独自の計算のメモを書くことを意図していたためです。しかし、他の人たちは私をパンチに打ちのめし、記念のためのパッケージを持っています。掘るほど、見つけることが多くなります。例:memoiseR.cacheですが、違いはすぐにはわかりません。さらに、hashパッケージを使用する以外に、Perlスタイルのハッシュ(またはPythonスタイルの辞書)を取得して独自のメモを作成する方法が明確ではありません。メモ化パッケージ。

CRANまたは他の場所でオプションを区別するための情報が見つからないので、おそらくこれはSOのコミュニティwikiの質問であるはずです。Rでのメモ化とキャッシュのオプションは何ですか、それらの違いは何ですか?


比較の基礎として、ここに私が見つけたオプションのリストがあります。また、私はすべてハッシュに依存しているようですので、ハッシュオプションにも注意します。キーと値のストレージはある程度関連していますが、DBシステムに関する膨大な量のワームが開かれます(BerkeleyDB、Redis、MemcacheDB、および 他のユーザーのスコア など)。

オプションは次のようです。

ハッシュ

  • digest -任意のRオブジェクトにハッシュを提供します。

メモ化

  • memoise -関数をメモ化するための非常にシンプルなツール。
  • R.cache -一部の関数には例がないようですが、メモ化のためのより多くの機能を提供します。

キャッシング

  • ハッシュ -PerlのハッシュおよびPython辞書と同様のキャッシング機能を提供します。

キー/値のストレージ

これらは、Rオブジェクトの外部ストレージの基本的なオプションです。

チェックポイント

その他の

  • Base Rは、名前付きベクトルとリスト、データフレームの行と列の名前、環境内のアイテムの名前をサポートしています。リストを使用するのは少々厄介なことのようです。 (pairlistもありますが、 非推奨 です。)
  • data.table パッケージは、データテーブル内の要素の高速ルックアップをサポートしています。

使用事例

私は主にオプションを知ることに関心がありますが、次の2つの基本的な使用例があります。

  1. キャッシング:文字列の単純なカウント。 [注:これはNLP向けではありませんが、一般的に使用されるため、NLPライブラリは過剰です。文字列のセット全体がメモリに読み込まれるまで待機したくないので、テーブルは不十分です。 Perlスタイルのハッシュは、ユーティリティの適切なレベルにあります。]
  2. 巨大な計算のメモ化。

私は いくつかのslooooowコードのプロファイリングを掘り下げている であり、単純な文字列を数えて、メモ化によっていくつかの計算を高速化できるかどうかを確認したいので、これらは本当に発生します。メモ化しなくても、入力値をハッシュできることで、メモ化が役立つかどうかを確認できます。


注1: 再現可能な研究に関するCRANタスクビュー は、いくつかのパッケージ(cacherおよびR.cache)、ただし使用オプションについての詳細はありません。

注2:関連するコードを探している他の人を助けるために、作者またはパッケージの一部に関するいくつかの注意事項を次に示します。一部の著者はSOを使用しています。 :)

  • Dirk Eddelbuettel:digest-他の多くのパッケージがこれに依存しています。
  • ロジャーペン:cacherfilehashstashR-これらはさまざまな方法でさまざまな問題に対処します。その他のパッケージについては Rogerのサイト を参照してください。
  • Christopher Brown:hash-便利なパッケージのようですが、残念ながらODGへのリンクがダウンしています。
  • Henrik Bengtsson:R.cache&Hadley Wickham:memoise-あるパッケージを他のパッケージよりも優先する時期はまだ明確ではありません。

注3:一部のユーザーはメモ/メモを使用し、他のユーザーはメモ/メモを使用します。周りを検索している場合は、注意してください。 Henrikは「z」を使用し、Hadleyは「s」を使用します。

72
Iterator

memoisetoo 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
biocyberman

文字列を単純にカウントする場合(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)
9
Tommy

@ biocyperman solution に関連しています。 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})
}
1
user890739