【问题标题】:Options for caching / memoization / hashing in RR中的缓存/记忆/散列选项
【发布时间】:2011-11-07 21:58:01
【问题描述】:

我试图找到一种简单的方法来在 R 中使用类似 Perl 的散列函数(本质上是缓存),因为我打算同时进行 Perl 风格的散列并编写我自己的计算记忆。然而,其他人已经打败了我,并且有用于记忆的包。我挖掘的越多,我发现的越多,例如memoiseR.cache,但它们之间的区别还不是很清楚。此外,除了使用 hash 包之外,还不清楚如何获得 Perl 风格的哈希(或 Python 风格的字典)并编写自己的 memoization,这似乎并不支持这两个 memoization 包。

由于我找不到关于 CRAN 或其他地方的信息来区分选项,也许这应该是关于 SO 的社区 wiki 问题:R 中的记忆和缓存选项有哪些,它们有什么区别?


作为比较的基础,这里列出了我找到的选项。另外,在我看来,这一切都依赖于散列,所以我也会注意散列选项。键/值存储有些相关,但会引发大量有关数据库系统(例如 BerkeleyDB、Redis、MemcacheDB 和scores of others)的蠕虫。

看起来选项是:

散列

  • digest - 为任意 R 对象提供散列。

记忆

  • memoise - 一个非常简单的函数记忆工具。
  • R.cache - 提供了更多的记忆功能,但似乎有些功能缺少示例。

缓存

  • hash - 提供类似于 Perl 的哈希和 Python 字典的缓存功能。

键/值存储

这些是 R 对象外部存储的基本选项。

检查点

其他

  • Base R 支持:命名向量和列表、数据框的行和列名称以及环境中的项目名称。在我看来,使用列表有点笨拙。 (还有pairlist,但it is deprecated。)
  • data.table 包支持快速查找数据表中的元素。

用例

虽然我最感兴趣的是了解这些选项,但我有两个基本用例:

  1. 缓存:简单的字符串计数。 [注意:这不是 NLP 的,而是通用的,所以 NLP 库是矫枉过正的;表是不够的,因为我不想等到整个字符串集加载到内存中。 Perl 风格的散列在实用程序的正确级别。]
  2. 巨大的计算记忆。

这些确实出现了,因为我是digging in to the profiling of some slooooow code,我真的很想计算简单的字符串,看看我是否可以通过记忆加快一些计算。能够对输入值进行哈希处理,即使我不记忆,也会让我看看记忆是否有帮助。


注意 1:CRAN Task View on Reproducible Research 列出了几个包(cacherR.cache),但没有详细说明使用选项。

注 2:为了帮助其他人寻找相关代码,这里对一些作者或包进行了一些注解。一些作者使用 SO。 :)

  • Dirk Eddelbuettel:digest - 许多其他软件包都依赖于此。
  • Roger Peng:cacherfilehashstashR - 这些以不同的方式解决不同的问题;更多软件包请参见Roger's site
  • Christopher Brown:hash - 似乎是一个有用的软件包,但不幸的是,ODG 的链接已关闭。
  • Henrik Bengtsson:R.cache 和 Hadley Wickham:memoise -- 目前尚不清楚何时更喜欢一个包。

注意 3:有些人使用 memoise/memoisation 其他人使用 memoize/memoization。如果您正在四处寻找,请注意。 Henrik 使用“z”,Hadley 使用“s”。

【问题讨论】:

  • 添加一个或两个真实用例可能会更好,以便比较方法......
  • @Tommy:谢谢,我会的!
  • 对您的 cmets re: 环境感到困惑。如果您创建一个新环境,它将被散列。 ?environment 例如,env.profile(new.env())$size # [1] 29
  • @DWin:你是对的。我只提到它作为哈希功能的一个选项。
  • 这篇文章由“R in a Nutshell”的作者撰写,包括对查找对象的几种不同选项的速度测试,包括将它们置于环境中(查找使用散列名称)broadcast.oreilly.com/2010/03/lookup-performance-in-r.html。不知道它是否对你有用,但我想我会将它附加到这篇文章中,以供其他人使用。

标签: r caching hash memoization memoise


【解决方案1】:

我对@9​​87654321@ 不满意,因为它给我尝试使用的包的某些功能带来了“递归太深”的问题。有了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 ...)

【讨论】:

    【解决方案2】:

    @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})
    }
    

    【讨论】:

      【解决方案3】:

      对于字符串的简单计数(而不是使用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)
      

      【讨论】:

        猜你喜欢
        • 2012-07-06
        • 2021-11-24
        • 2015-04-03
        • 2016-06-27
        • 2014-12-27
        • 2016-05-19
        • 2016-08-14
        • 2017-10-04
        • 2021-02-21
        相关资源
        最近更新 更多