【问题标题】:R - readRDS() & load() fail to give identical data.tables as the originalR - readRDS() & load() 无法提供与原始数据相同的 data.tables
【发布时间】:2015-09-23 21:41:43
【问题描述】:

背景

我尝试将一些CSV 输出文件替换为rds 文件以提高效率。这些是中间文件,将作为其他 R 脚本的输入。

问题

当我的脚本失败时我开始调查,发现 readRDS()load() 不会返回与原始相同的 data tables。这应该发生吗?还是我错过了什么?

示例代码

library( data.table )

aDT <- data.table( a=1:10, b=LETTERS[1:10] )
saveRDS( aDT, file = "aDT.rds")
bDT <- readRDS( file = "aDT.rds" )
identical( aDT, bDT, ignore.environment = T )  # Gives 'False'

aDF <- data.frame( a=1:10, b=LETTERS[1:10] )
saveRDS( aDF, file = "aDF.rds")
bDF <- readRDS( file = "aDF.rds" )
identical( aDF, bDF, ignore.environment = T )  # Gives 'True'

# Using 'save'& 'load' doesn't help either
aDT2 <- data.table( a=1:10, b=LETTERS[1:10] )
save( aDT2, file = "aDT2.RData")
bDT2 <- aDT2; rm( aDT2 )
load( file = "aDT2.RData" )
identical( aDT2, bDT2, ignore.environment = T )  # Gives 'False'

我在 Linux Mint 上运行 R 版本 3.2.0,并使用 data.table 版本 1.9.4 和 1.9.5(最新)进行了测试。

在 SO 和 google 中搜索返回 thisthis 但我认为他们没有回答这个问题。当我切换到rds 时,我仍在试图弄清楚为什么我的脚本失败了,但我是从这个开始的。

如果知识渊博的 SO 成员能提供帮助,我们将不胜感激。谢谢!

编辑:

大家好,我碰巧找到了解决问题的方法 - 已在下面发布了解决方案。我很抱歉,如果它相当不雅。现在,我还有 2 个问题:

(1) 有没有更好的方法?

(2) 可以在R 和/或data.table 代码处解决此问题吗?我的意思是,这个问题会导致不可预知的错误,而不是首先想到的。我的 2 美分值。

【问题讨论】:

  • 然后all.equal(aDT, bDT) #TRUE
  • 嗯...好点...我一直只使用identical。通过 ?all.equal 表明这是对“近似相等”的测试,所以也许区别在于下面两位先生提到的指针?

标签: r save load data.table


【解决方案1】:

解决方法是在loadreadRDS之后使用setDT

aDT2 <- readRDS("aDT2.RData")
setDT(aDT2)

来源:Adding new columns to a data.table by-reference within a function not always working

【讨论】:

    【解决方案2】:

    我碰巧找到了解决问题的方法(免责声明:这是一种相当不雅的方法,但它有效!) - 在加载的data table 中添加然后删除一个虚拟列导致identical 为“真”。我还成功地将自己代码中的csv 替换为rds 中间文件。

    老实说,我对 R 的内部工作原理和 data table 的了解不够多,不知道它为什么起作用,因此欢迎任何解释和/或更优雅的解决方案。

    library( data.table )
    
    aDT <- data.table( a=1:10, b=LETTERS[1:10] )
    saveRDS( aDT, file = "aDT.rds")
    bDT <- readRDS( file = "aDT.rds" )
    identical( aDT, bDT, ignore.environment = T )  # Gives 'False'
    
    bDT[ , aaa := NA ]; bDT[ , aaa := NULL ]
    identical( aDT, bDT, ignore.environment = T )  # Now gives 'True'
    
    
    # Using the add-del-col 'trick' works here too
    aDT2 <- data.table( a=1:10, b=LETTERS[1:10] )
    save( aDT2, file = "aDT2.RData")
    bDT2 <- aDT2; rm( aDT2 )
    load( file = "aDT2.RData" )
    identical( aDT2, bDT2, ignore.environment = T )  # Gives 'False'
    
    aDT2[ , aaa := NA ]; aDT2[ , aaa := NULL ]
    identical( aDT2, bDT2, ignore.environment = T )  # Now gives 'True'
    

    【讨论】:

      【解决方案3】:

      这可能与指针有关:

       attributes(aDT)
      $names
      [1] "a" "b"
      
      $row.names
       [1]  1  2  3  4  5  6  7  8  9 10
      
      $class
      [1] "data.table" "data.frame"
      
      $.internal.selfref
      <pointer: 0x0000000000390788>
      
      > attributes(bDT)
      $names
      [1] "a" "b"
      
      $row.names
       [1]  1  2  3  4  5  6  7  8  9 10
      
      $class
      [1] "data.table" "data.frame"
      
      $.internal.selfref
      <pointer: (nil)>
      
      > attributes(bDF)
      $names
      [1] "a" "b"
      
      $row.names
       [1]  1  2  3  4  5  6  7  8  9 10
      
      $class
      [1] "data.frame"
      
      > attributes(aDF)
      $names
      [1] "a" "b"
      
      $row.names
       [1]  1  2  3  4  5  6  7  8  9 10
      
      $class
      [1] "data.frame"
      

      您可以使用.Internal(inspect(.)) 命令仔细查看发生了什么:

      .Internal(inspect(aDT))
      
       .Internal(inspect(bDT))
      

      【讨论】:

      • 感谢您的回复,@user227710。有没有什么办法可以为重新加载的data table重新建立指针,而无需访问原始DT?
      • @NoviceProg:您的问题将在here 详细讨论。 saveRDS 不保存 .internal.selfref 所以,我认为这是不可能的。
      • 我浏览了您提供的链接以及链接中的 SO 线程。有趣的是,他们提到该问题已在 data table v1.9.3 中解决,不确定该 OP 是否面临类似问题。
      【解决方案4】:

      新加载的data.table不知道已经加载的指针值。你可以告诉它

      attributes(bDT)$.internal.selfref <- attributes(aDT)$.internal.selfref
      identical( aDT, bDT, ignore.environment = T )
      # [1] TRUE
      

      data.frame不要保留这个属性,可能是因为他们没有做就地修改。

      【讨论】:

      • 嗨@LegalizeIt,我知道你要去哪里,但是如果加载bDT的脚本无法访问aDT会发生什么?这就是中间文件的原因(csv/rds)。
      猜你喜欢
      • 2021-10-19
      • 2020-05-25
      • 1970-01-01
      • 2020-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多