R中的缓存/记忆/散列选项

我试图找到一种简单的方法来在R中使用类似Perl的哈希函数(本质上是缓存),因为我打算同时执行Perl风格的哈希和编写自己的计算记忆。 然而,其他人已经打了我一拳,并有包裹为memoisation。 我挖的越多,我发现的越多,例如memoiseR.cache ,但差异不是很清楚。 此外,还不清楚除了使用hash包之外,还有其他人可以获得Perl风格的哈希(或Python风格的词典)并编写自己的记忆,这似乎并不支持这两个记忆包。

由于我找不到有关CRAN或其他地方的信息来区分这些选项,因此这可能应该是关于SO的社区维基问题:R中存储和缓存有哪些选项?它们有什么区别?


作为比较的基础,这里是我找到的选项列表。 此外,在我看来,所有依赖于哈希,所以我会注意到哈希选项。 键/值存储有点相关,但是会打开一大堆关于数据库系统的蠕虫(例如BerkeleyDB,Redis,MemcacheDB和其他数十个蠕虫)。

它看起来像选项是:

哈希

  • 摘要 - 为任意R对象提供散列。
  • 记忆化

  • 记忆 - 一种用于记忆功能的非常简单的工具。
  • R.cache - 为记忆提供更多的功能,虽然它看起来有些功能缺乏示例。
  • 高速缓存

  • 散列 - 提供类似于Perl的哈希和Python字典的缓存功能。
  • 键/值存储

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

  • stashr
  • filehash
  • 检查点

  • cacher - 这看起来更像是检查点。
  • CodeDepends - 支持cacher并提供一些有用功能的OmegaHat项目。
  • DMTCP(不是R软件包) - 似乎支持多种语言的检查点设计,最近一位开发人员在R中寻求协助测试DMTCP检查点。
  • 其他

  • Base R支持:命名向量和列表,数据框的行和列名以及环境中的项目名称。 在我看来,使用列表有点混乱。 (也有pairlist ,但不推荐使用。)
  • data.table包支持快速查找数据表中的元素。

  • 用例

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

  • 缓存:简单的字符串计数。 [注:这不是NLP,而是一般用途,所以NLP库是矫枉过正的; 表格是不够的,因为我不想等到整个字符串集合加载到内存中。 Perl风格的哈希处于正确的效用水平。]
  • 记忆怪异的计算。
  • 这些都是因为我正在深入分析一些slooooow代码,我真的只想简单地计算一下字符串,看看我能否通过记忆加速一些计算。 如果能够散列输入值,即使我不记忆,也会让我看到memoization是否可以提供帮助。


    注1:可重复研究的CRAN任务视图列出了一些包( cacherR.cache ),但没有详细说明使用选项。

    注2:为了帮助其他人寻找相关的代码,这里有一些关于作者或包的说明。 一些作者使用SO。 :)

  • 德克Eddelbuettel: digest - 许多其他包依赖于此。
  • Roger Peng: cacherfilehashstashR它们以不同的方式解决不同的问题; 请参阅Roger的网站了解更多软件包。
  • 克里斯托弗布朗: hash - 似乎是一个有用的软件包,但不幸的是,与ODG的链接已经关闭。
  • Henrik Bengtsson: R.cache &Hadley Wickham: memoise - 现在还不清楚何时比其他人更喜欢一个包。
  • 注3:有些人使用memoise / memoisation他人使用memoize / memoization。 如果你在四处搜寻,请注意。 Henrik使用“z”,Hadley使用“s”。


    对于字符串的简单计数(而不是使用table或类似),多重数据结构似乎是一个很好的选择。 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)
    

    我没有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 datan")
            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("okn")
        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 scratchn")
        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("donen")
                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 ...)
    

    与@biocyperman解决方案相关。 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("okn")
        data})
    }
    
    链接地址: http://www.djcxy.com/p/62993.html

    上一篇: Options for caching / memoization / hashing in R

    下一篇: ASP.net Cache Absolute Expiration not working