r - 在函数内通过引用向 data.table 添加新列并不总是有效

标签 r data.table

在编写依赖于data.table的包时,我发现了一些奇怪的行为。我有一个函数可以通过引用删除和重新排序某些列,并且它工作得很好,这意味着我传入的 data.table 已被修改而没有分配函数输出。我有另一个函数添加列,但是这些更改并不总是保留在传入的data.table中。

这是一个小例子:

library(data.table)  # I'm using 1.9.4
test <- data.table(id = letters[1:2], val=1:2)
foobar <- function(dt, col) {
    dt[, (col) := 1]
    invisible(dt)
}

test
#  id val
#1: a   1
#2: b   2
saveRDS(test, "test.rds")
test2 <- readRDS("test.rds")
all.equal(test, test2)
#[1] TRUE
foobar(test, "new")
test
#  id val new
#1: a   1   1
#2: b   2   1
foobar(test2, "new")
test2
#  id val
#1: a   1
#2: b   2

发生了什么? test2 有什么不同?我可以就地修改现有列:

foobar(test, "val")
test
#  id val new
#1: a   1   1
#2: b   1   1
foobar(test2, "val")
test2
#  id val
#1: a   1
#2: b   1

但是添加到 test2 仍然不起作用:

foobar(test2, "someothercol")
.Last.value
#  id val someothercol
#1: a   1            1
#2: b   1            1
test2
#  id val
#1: a   1
#2: b   1

我无法确定看到此行为的所有情况,但保存到 RDS 并从中读取是我可以可靠复制的第一个情况。写入和读取 CSV 似乎没有同样的问题。

这是一个指针问题吗this issue ,就像序列化 data.table 会破坏过度分配的指针一样?有没有简单的方法来恢复它们?我如何在函数内检查它们,以便在操作不起作用时可以恢复指针或错误?

我知道我可以分配函数输出作为解决方法,但这不是很data.table-y。那不是也会在内存中创建一个临时副本吗?

对 Arun 解决方案的回应

Arun 表示这确实是一个指针问题,可以使用 truelength 进行诊断,并使用 setDTalloc.col 进行修复。我在将他的解决方案封装在函数中时遇到了问题(继续上面的代码):

func <- function(dt) {if (!truelength(dt)) setDT(dt)}
func2 <- function(dt) {if (!truelength(dt)) alloc.col(dt)}
test2 <- readRDS("test.rds")
truelength(test2)
#[1] 0
truelength(func(test2))
#[1] 100
truelength(test2)
#[1] 0
truelength(func2(test2))
#[1] 100
truelength(test2)
#[1] 0

所以看起来函数内部的本地副本已被正确修改,但引用版本却没有。为什么不呢?

最佳答案

Is this a pointer issue ala this issue, like serializing a data.table destroys the over-allocated pointers?

是,从磁盘加载会将外部指针设置为 NULL。我们将不得不再次超额分配。

Is there a simple way to restore them?

是的。您可以测试 truelength() data.table 的,如果是 0 ,然后使用setDT()alloc.col()就在上面。

truelength(test2) # [1] 0
if (!truelength(test2))
    setDT(test2)
truelength(test2) # [1] 100

foobar(test2, "new")
test2[]
#    id val new
# 1:  a   1   1
# 2:  b   2   1

这可能应该作为常见问题解答(不记得在那里看到过)。
已经在 FAQ在警告消息部分。

关于r - 在函数内通过引用向 data.table 添加新列并不总是有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28078640/

相关文章:

r - 具有挑战性的载体修饰

r - Shiny 的复选框组更改框的大小

r - 错误 : Value of SET_STRING_ELT() must be a 'CHARSXP' not a 'character' in dplyr group_by

r - 代码优化 - data.table,当前具有多个引用的 for 循环被优化为 data.table

r - 具有 613 列调查数据的稀疏 132MB 文件上的 fread segfault

r - 如何使用by将所有列暴露给data.table的子集并将其暴露给该函数?

python - rpy2 中的错误 - 没有(非缺失)观察结果

r - 如何通过变量将参数传递到 data.table[J()]

R:data.table 比较行集

滚动平均值/标准差(随条件变化)