防止不使用选项创建data.table自动索引的简单方法(datatable.auto.index = FALSE)

Ben*_*Ben 1 r data.table

我有一些像

library(data.table)  # v 1.12.3

foo <- data.table(x = sample(letters, 10^6, replace = T), y = 1)
foo[x == "a", y := 0]
indices(foo)  # x
Run Code Online (Sandbox Code Playgroud)

如您所见,索引是在column上自动创建的x。在这种情况下,我不希望创建索引。我知道我可以用类似的方法来预防

options(datatable.auto.index = FALSE)
foo[x == "a", y := 0]
options(datatable.auto.index = TRUE)
Run Code Online (Sandbox Code Playgroud)

但这似乎是糟糕的设计,因为

  1. 这是凌乱的代码
  2. 如果foo[x == "a", y := 0]出现错误,将不会重新打开自动索引

这里有更好的选择foo[x == "a", y := 0, autoindex = FALSE]吗?

另外,我想我可以允许创建索引,然后用删除它,setindex(foo, NULL)但是我担心这会增加性能成本。另外,它看起来比应该的还杂乱。

Fra*_*ank 5

对于像您的示例这样的情况,我认为最好让data.table来做:

library(data.table)  # v 1.12.3 IN DEVELOPMENT built 2019-07-29 22:08:45 UTC
foo <- data.table(x = sample(letters, 10^8, replace = T), y = 1)

# allow optimization (forder, store order as index, bmerge value)
foo1 = copy(foo)
system.time({
  foo1[x == "a", y := 0]
})
stopifnot(length(indices(foo1)) > 0)
#    user  system elapsed 
#    1.43    0.39    0.56 

# disable optimization, hacky
foo2 = copy(foo)
system.time({
  foo2[(x == "a"), y := 0]
})
stopifnot(length(indices(foo2)) == 0)
#    user  system elapsed 
#    0.47    0.01    0.49 

# disable optimization, properly
foo2 = copy(foo)
system.time({
  options(datatable.auto.index = FALSE)
  foo[x == "a", y := 0]
  options(datatable.auto.index = TRUE)
})
stopifnot(length(indices(foo2)) == 0)
#    user  system elapsed 
#    0.48    0.00    0.49 

# disable optimization, from @Oliver in comments
foo2 = copy(foo)
system.time({
  foo2[which(x == "a"), y := 0]
})
stopifnot(length(indices(foo2)) == 0)
#    user  system elapsed 
#    0.54    0.03    0.50 
Run Code Online (Sandbox Code Playgroud)

其他评论:

  • 括号(x == "a")可防止data.table解析器识别优化的子集是适当的。有关使用的优化的详细信息,请打开verbose=TRUE参数。
  • 我认为上述额外费用很小,而在后续查询中的好处也很大:

    system.time({
      foo1[x == "b", y := 0]
    })
    #    user  system elapsed 
    #    0.17    0.12    0.25 
    
    Run Code Online (Sandbox Code Playgroud)
  • 也许对于其他自动索引查询,时间差会比这种情况大。

  • 除了计算时间之外,索引可能还占用一些空间(存储表的行号的排列?),但是我怀疑在大多数情况下是否值得摆弄。

  • 嗯,在R changelog上,我只看到关于x [x!= 0]特殊情况的改进说明。“感谢Tomas Kalibera的补丁,x [x!= 0]现在通常比x [which(x!= 0)](在x没有NA的情况下,两者是等效的。” (2认同)
  • 它不应该是等效的,因为which(x!= 0)必须先分配逻辑(length(x()),然后再分配integer(sum(x!= 0)))。当x == 0时,只会分配逻辑(长度(x))。T / F比率越大,我们越接近“哪种”方式的两倍的内存需求。相关https://github.com/Rdatatable/data.table/issues/3663 (2认同)