【问题标题】:hash - Identical R Dataframes, different hashes (not an attribute problem)hash - 相同的 R 数据帧,不同的哈希值(不是属性问题)
【发布时间】:2023-02-11 04:48:57
【问题描述】:

我有两个大约 150 行的数据帧 XY,其中 identical(X, Y)TRUEidentical(digest(X), digest(Y))FALSE

我确实看过 this answer 并重新运行了他们测试的内容,得到了类似的结果,但与他们的问题不同的是,我的数据帧的属性是相同的。测试结果:

> names(attributes(X))
[1] "names"     "row.names" "class"
> names(attributes(Y))
[1] "names"     "row.names" "class"  

> digest(X)
[1] "07b7ef11ce6eaae01ddd79e4facef581"
> digest(Y)
[1] "09d8abcab0af0a72265a9b690f4eacc3"

> digest(X[1:nrow(X),])
[1] "2f338de9972529bd2bc9c39c3c5762ea"
> digest(Y[1:nrow(Y),])
[1] "2f338de9972529bd2bc9c39c3c5762ea"

> identical(X, Y, attrib.as.set=FALSE)
[1] TRUE

我还将数据帧保存为 .RDS 文件,并重新读取它们。

> X_rds <- read_rds("cache_vars/X.rds")
> Y_rds <- read_rds("cache_vars/Y.rds")
> identical(X_rds , Y_rds )
[2] TRUE
> digest(X_rds)
[2] "07b7ef11ce6eaae01ddd79e4facef581"
> digest(Y_rds )
[2] "09d8abcab0af0a72265a9b690f4eacc3"
> identical(X_rds , Y_rds , attrib.as.set=FALSE)
[2] TRUE

和其他海报一样,转换为矩阵并返回数据框产生了相同的摘要,所以这可能是一些结构性问题。

> X_Mat <- as.matrix(X_rds)
> Y_Mat <- as.matrix(Y_rds)
> identical(digest(X_Mat), digest(Y_Mat))
[2] TRUE
> X_DF <- as.data.frame(X_Mat)
> Y_DF <- as.data.frame(Y_Mat)
> identical(digest(X_DF ), digest(Y_DF))
[2] TRUE

Dataframe X 是从并行设计的循环中生成的(但带有 %do% 标志,因此没有完成实际的并行性),Y 是从顺序循环中生成的。

X 和 Y 的 .RDS 文件可以在 this link 找到。

【问题讨论】:

  • 你的问题又是什么?
  • 它们是如何创建的?仅供参考,Xraw &lt;- serialize(X, NULL)(和Yraw)后跟which(Xraw != Yraw)(对我而言)返回 9 个不同的字节。坦率地说,这并没有告诉我很多,因为我没有记住serialize 的方法,也没有记住如何快速知道这些字节在data.frame 的范围内是如何解释的。同样奇怪的是,serialize(X, NULL) 的长度与Y 的长度相同,而.rds 文件的大小却不同。有趣的。也许您可以比较这两个框架是如何创建的(但我认为我不在这个内部讨论中,对我来说太沉重了:-)。

标签: r dataframe hash


【解决方案1】:

当您写入rds 时,对象被序列化。除了向量包含的值之外,序列化还包含一些信息。请注意,如果我们只比较所有列,它们会产生不同的摘要

sapply(seq_along(X_rds), function(i)
  digest::digest(X_rds[[i]])==digest::digest(Y_rds[[i]])
)

所以存储在 data.frame 中的向量是不同的。我们可以使用内部的inspect函数来获取向量的一些元数据

.Internal(inspect(X_rds[[1]]))
# @135305a00 14 REALSXP g0c7 [REF(4),gp=0x20] (len=150, tl=0) 
# 1.009e+06,1.009e+06,1.009e+06,1.009e+06,1.009e+06,...
.Internal(inspect(Y_rds[[1]]))
# @115dbfc00 14 REALSXP g0c7 [REF(29)] (len=150, tl=0) 
# 1.009e+06,1.009e+06,1.009e+06,1.009e+06,1.009e+06,...

所以我们看到它们在 [] 部分有所不同。我相信 REF() 数字表示为了内存清除目的对该对象的引用计数。 X_rds 也设置了 gp=0x20。 “gp”代表“通用”位。我相信在这种情况下,这意味着在该对象上设置了 GROWABLE_MASK。这些值在对象被序列化时被保留,这是 digest 的默认行为。

当您使用 identical 时,只会比较 data.frame 中的值,不会比较额外的元数据。

如果您想解决这个问题,您可以围绕 digest 编写自己的包装器来避免序列化。例如

dfdigest <- function(x) {
  charsToRaw <- function(x) unlist(lapply(x, charToRaw))
  bytes <- unlist(c(list(charsToRaw(names(x))), 
                    lapply(x, function(col) {
    if (typeof(col)=="double") writeBin(col, raw())
    else if (typeof(col)=="character") charsToRaw(col)
    else stop(paste("unconfigured data type:", typeof(col)))
  })))
  digest::digest(bytes, serialize = FALSE)
}

dfdigest(X_rds)
# [1] "2488505e3ad1a370d030b539a287b7ca"
dfdigest(Y_rds)
# [1] "2488505e3ad1a370d030b539a287b7ca"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多