2016-10-10 116 views
2

这是一个问题在一个更大的规模非常简化的版本。 的目的是使用data.table结构和更快的排序和多个列分组dplyr命令。dplyr,data.table和setDT互动问题

正确的版本如下:

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 

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

+0

两个'dt'变量不定义相同的数据帧。如果我使用一个,我会得到一致的结果。 –

回答

6

你不能安全地混合(我)data.table的功能,通过参考到步骤(ii)一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编列已被setDT通话修改。您可以将其视为dtplyr的实现select中的错误或OP的滥用。无论如何,我会一次坚持一个范式(个人而言,我只是用magrittr使用data.table,从来没有遇到这些问题)。现在,您可以将copy添加到您的链条,

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

但我猜你需要做这一切的地方。

+0

感谢您的信息。基本上这是我的错误。我错误地认为dtplyr软件包能够解决这些问题。 – AntoniosK

+0

我不相信你的答案(还)。你的链的例子不会保存/打印结果,它会更新'select()'输出,但不会分配给新的变量,因为'select()'结果不会保存到任何变量中。关于'copy'也不确定,参见:'dt%>%select(id,value)%>%setDT(。,key = c(“id”,“value”)) - > ans1; dt%>%select(id,value)%>%copy%>%setDT(。,key = c(“id”,“value”)) - > ans2; all.equal(ans1,ans2)'。 – jangorecki

+0

@jangorecki我不认为你的例子有效。第一个已经修改了'dt',所以第二个没有机会使用原来的'dt'。我的建议不保存与''​​3210或'=',但我猜OP可以计算如何做到这一点,还是你的意思是别的东西,结果呢? – Frank