【问题标题】:data.table modifies parent environment / weird behavior with setDTdata.table 使用 setDT 修改父环境/奇怪的行为
【发布时间】:2019-02-09 18:09:54
【问题描述】:

因此,如果我使用现有向量的 data.frame 和 setDT 构建我的 data.table,原始向量会在父环境中被修改:

a <- 1:2 / 2
x <- 1:10 / 2
y <- 11/2
dt <- data.frame(a, x, y)
setDT(dt)
dt[ , cond := a == 1]
dt[(cond), c("x", "y") := list(y, x)]
x
#[1] 0.5 5.5 1.5 5.5 2.5 5.5 3.5 5.5 4.5 5.5

对于信息,我使用 R 3.5.1 和 data.table 1.11.4

如果我使用 data.table 构造函数而不是 data.frame + setDT 它不会修改向量 x。

a <- 1:2 / 2
x <- 1:10 / 2
y <- 11/2
dt <- data.table(a, x, y)
dt[ , cond := a == 1]
dt[(cond), c("x", "y") := list(y, x)]
x
#[1] 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0

有人能解释一下我发生了什么吗?如果这是一个错误?

干杯

EDIT1:刚刚在 github 上发现了这个相关问题 https://github.com/Rdatatable/data.table/issues/2683

EDIT2:嫌疑人显然是“通过引用复制”,因此向量 x 和 dt$x 的内存地址相同,因此它修改了 data.table 之外的向量。我原以为 data.frame 创建会复制...

> a <- 1:2 / 2
> x <- 1:10 / 2
> y <- 11/2
> dt <- setDT(as.data.frame(list(a = a, x = x, y = y)))
> dt[ , cond := a == 1]
> dt[(cond), c("x", "y") := list(y, x)]
> x
[1] 0.5 5.5 1.5 5.5 2.5 5.5 3.5 5.5 4.5 5.5
> address(dt$x)
[1] "0xadd8fe8"
> address(x)
[1] "0xadd8fe8"

【问题讨论】:

  • 也很奇怪(我认为)如果xy 是整数(x &lt;- 1:10L;y &lt;- 11L)那么原来的x 没有被修改!
  • @Jeff 我试过你的例子,我确实看到x 也在那里被修改。 Fwiw,我有时会使用这个“功能”,例如z = 1:3; setDT(list(z))[2, V1 := 99L][]; z。我认为它之前已作为错误提交,但我现在无法在问题跟踪器上找到它。

标签: r data.table


【解决方案1】:

setDT 通过引用修改输入对象。如果用作输入的对象本身是通过执行浅拷贝(而不是深拷贝)创建的,那么在使用 data.table 中的:=set() 时,所有此类对象都将被修改。

data.frame() 似乎在创建时尽可能创建输入对象的浅表副本以提高效率。所以address(df$x)address(x) 是相同的。这是可以接受的,因为 R 会执行修改时复制。

您可以通过直接创建 data.tables 来避免此类情况。相反,如果直接给你一个 data.frame 对象,而你不知道它是如何创建的,最好使用copy()。 HTH。

【讨论】:

    猜你喜欢
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    相关资源
    最近更新 更多