我有一些像
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)
但这似乎是糟糕的设计,因为
foo[x == "a", y := 0]出现错误,将不会重新打开自动索引这里有更好的选择foo[x == "a", y := 0, autoindex = FALSE]吗?
另外,我想我可以允许创建索引,然后用删除它,setindex(foo, NULL)但是我担心这会增加性能成本。另外,它看起来比应该的还杂乱。
对于像您的示例这样的情况,我认为最好让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)也许对于其他自动索引查询,时间差会比这种情况大。
除了计算时间之外,索引可能还占用一些空间(存储表的行号的排列?),但是我怀疑在大多数情况下是否值得摆弄。