dplyr,data.table和setDT交互问题

时间:2016-10-10 17:08:05

标签: r data.table dplyr

这是一个更大规模的问题的简化版本。 目标是使用data.table结构和dplyr命令更快地对多列进行排序和分组。

正确的版本如下:

library(dplyr)
library(data.table)
library(dtplyr)
library(lubridate)

# data set
dt = data.frame(id = c("a","b", "a"),
                date = ymd(c("2016-01-03","2016-01-02","2016-01-01")),
                value = c(10,5,9), stringsAsFactors = F)

# process to get the id of the largest value
(setDT(dt, key=c("id","value")) %>% select(id,value) %>% arrange(desc(value)) %>% slice(1))$id -> picked_id

# return all rows of this id
dt %>% filter(id %in% picked_id)

# id          date value
# 1:  a 2016-01-01     9
# 2:  a 2016-01-03    10

但是当我尝试在我的脚本中的不同位置使用setDT时,我得到了不同的结果:

dt = data.frame(id = c("a","b", "a"),
                date = ymd(c("2016-01-03","2016-01-02","2016-01-01")),
                value = c(10,5,9), stringsAsFactors = F)

(dt %>% select(id,value) %>% setDT(., key=c("id","value")) %>% arrange(desc(value)) %>% slice(1))$id -> picked_id

dt %>% filter(id %in% picked_id)

#   id       date value
# 1  a 2016-01-03     9
# 2  a 2016-01-02    10

显然,对于这个简单的任务,还有其他更容易理解的脚本,但我想了解为什么会出现此问题。

1 个答案:

答案 0 :(得分:6)

您无法安全地混合(i)通过引用修改为(ii)dplyr链的data.table函数,该dplyr链旨在永远不会通过引用进行修改。看看这里发生了什么:

library(dplyr)
library(data.table)
library(dtplyr)
library(lubridate)

dt = data.frame(id = c("a","b", "a"),
                date = ymd(c("2016-01-03","2016-01-02","2016-01-01")),
                value = c(10,5,9), stringsAsFactors = FALSE)

dt


  id       date value
1  a 2016-01-03    10
2  b 2016-01-02     5
3  a 2016-01-01     9


dt %>% select(id,value) %>% setDT(., key=c("id","value"))

dt


  id       date value
1  a 2016-01-03     9
2  a 2016-01-02    10
3  b 2016-01-01     5

所以select ed列已被setDT调用修改。您可以将此视为dtplyr的select实施中的错误或OP的滥用。无论如何,我会一次坚持使用一个范例(就个人而言,我只是使用带有magrittr的data.table而且从未遇到过这些问题)。目前,您可以在链中添加copy

dt %>% select(id,value) %>% copy %>% setDT(., key=c("id","value"))

但我想你需要在整个地方做到这一点。