【问题标题】:dplyr, data.table and setDT interaction issuedplyr、data.table 和 setDT 交互问题
【发布时间】:2016-10-10 17:08:04
【问题描述】:

这是一个规模更大的问题的非常简化的版本。 目标是使用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

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

【问题讨论】:

  • 这两个dt 变量没有定义同一个数据框。如果我使用一个,我会得到一致的结果。

标签: r data.table dplyr


【解决方案1】:

您不能安全地将 (i) 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

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

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

但我想你需要在所有地方都这样做。

【讨论】:

  • 感谢您的信息。基本上是我的错。我错误地认为 dtplyr 包能够解决这些问题。
  • 我不相信你的回答(还)。您的链示例不会保存/打印结果,它会更新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 我认为您的示例行不通。第一个已经修改了dt,所以第二个没有机会使用原始的dt。我的建议没有用<-->= 保存结果,但我想 OP 可以知道如何做到这一点,或者你的意思是别的什么?
  • @AntoniosK 也许是为了解决这些问题。您可以在 dtplyr 问题跟踪器上询问以澄清。我不太确定。
  • @Frank 不,它没有,我看到运行这些命令后有class(dt) # [1] "data.frame"setDT 更新到位,但不是 dt,只是未存储在任何地方的 select() 输出。
猜你喜欢
  • 2014-06-15
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 2016-08-08
  • 2015-04-08
  • 2017-06-15
  • 1970-01-01
相关资源
最近更新 更多