如何在R中计算大对象的哈希值?

时间:2016-02-13 08:25:45

标签: r

我在R中有大对象,几乎不适合我的16GB内存(data.table数据库>> 4M记录,> 400变量。

我希望有一个哈希函数,用于确认加载到R中的数据库没有被修改。

一种快速的方法是使用先前存储的哈希计算数据库的哈希值。

问题是digest::digest函数复制(序列化)数据,并且只有在序列化所有数据之后,它才会计算散列。对我的硬件来说太迟了......: - (

有没有人知道解决这个问题的方法?

有一个不好的人解决方案:将对象保存到文件中,并计算文件的哈希值。但它引入了大量不必要的开销(我必须确保硬盘上还有一个备用副本,并且需要跟踪所有可能无法自动删除的文件)

2 个答案:

答案 0 :(得分:0)

我们的问题跟踪器中已经描述了类似的问题: https://github.com/eddelbuettel/digest/issues/33

当前版本的digest可以读取文件来计算哈希值。

因此,至少在Linux上,我们可以使用一个命名管道,它将由摘要包读取(在一个线程中),另一方面,数据将由另一个线程写入。

以下代码片段显示了我们如何通过首先以1:5然后6:10提供消化器来计算10个数字的MD5哈希值。

library(parallel)
library(digest)

x <- as.character(1:10) # input

fname <- "mystream.fifo" # choose name for your named pipe
close(fifo(fname, "w")) # creates your pipe if does not exist

producer <- mcparallel({
    mystream <- file(fname, "w")
    writeLines(x[1:5], mystream)
    writeLines(x[6:10], mystream)
    close(mystream) # sends signal to the consumer (digester)
})

digester <- mcparallel({
    digest(fname, file = TRUE, algo = "md5") # just reads the stream till signalled
})

# runs both processes in parallel
mccollect(list(producer, digester))

unlink(fname) # named pipe removed

更新: Henrik Bengtsson提供了基于期货的修改示例:

library("future")
plan(multiprocess)

x <- as.character(1:10) # input

fname <- "mystream.fifo" # choose name for your named pipe
close(fifo(fname, open="wb")) # creates your pipe if does not exists

producer %<-% {
    mystream <- file(fname, open="wb")
    writeBin(x[1:5], endian="little", con=mystream)
    writeBin(x[6:10], endian="little", con=mystream)
    close(mystream) # sends signal to the consumer (digester)
}

# just reads the stream till signalled
md5 <- digest::digest(fname, file = TRUE, algo = "md5")
print(md5)
## [1] "25867862802a623c16928216e2501a39"
# Note: Identical on Linux and Windows

答案 1 :(得分:0)

在紧跟nicola的评论之后,这是专栏观点的基准。似乎并没有太大帮助,至少对于这种规模的人来说,没有帮助。 long_iris是150行,library(microbenchmark) #iris nrow(iris) microbenchmark( whole = digest::digest(iris), cols = digest::digest(lapply(iris, digest::digest)) ) #long iris long_iris = do.call(bind_rows, replicate(20e3, iris, simplify = F)) nrow(long_iris) microbenchmark( whole = digest::digest(long_iris), cols = digest::digest(lapply(long_iris, digest::digest)) ) 是3M(3,000,000)。

#normal
Unit: milliseconds
  expr  min   lq mean median   uq  max neval cld
 whole 12.6 13.6 14.4   14.0 14.6 24.9   100   b
  cols 12.5 12.8 13.3   13.1 13.5 23.0   100  a 

#long
Unit: milliseconds
  expr min  lq mean median  uq max neval cld
 whole 296 306  317    311 316 470   100   b
  cols 261 276  290    282 291 429   100  a 

结果:

CANVAS