R - readRDS()& load()无法提供与原始数据相同的data.tables

时间:2015-07-06 16:28:50

标签: r save load data.table

背景

我尝试用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 ver 3.2.0并使用data.table ver 1.9.4和1.9.5(最新)进行测试。

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

如果知识渊博的SO成员可以提供帮助,我将非常感激。谢谢!

修改

大家好,我碰巧找到了解决问题的方法 - 已经发布了以下解决方案。如果它相当不优雅我会道歉。现在,我还有两个问题:

(1)有更好的方法吗?

(2)可以通过R和/或data.table代码解决此问题吗?我的意思是,这个问题导致不可预测的错误,并不是第一个浮现在脑海中的东西。我的价值2美分。

4 个答案:

答案 0 :(得分:4)

可能这与指针有关:

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

答案 1 :(得分:3)

新加载的data.table不知道已加载的attributes(bDT)$.internal.selfref <- attributes(aDT)$.internal.selfref identical( aDT, bDT, ignore.environment = T ) # [1] TRUE 的指针值。你可以用

告诉它
data.frame

^不保留此属性,可能是因为它们没有进行就地修改。

答案 2 :(得分:1)

我碰巧找到了解决问题的方法(免责声明:这是一种相当不优雅的方式,但它有效!) - 添加然后删除加载的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 :(得分:1)

解决方案是在setDTload

之后使用readRDS
aDT2 <- readRDS("aDT2.RData")
setDT(aDT2)

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