2

如果我运行以下简单示例,我会得到预期的输出:

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

dt1 <- lazy_dt(data.table(a = 1:5, b = 6:10))
dt2 <- lazy_dt(data.table(a = letters[1:5], b = 6:10))

dt1 %>%
  left_join(
    dt2,
    by = "b"
  ) %>%
  as.data.table()
>     b a.x a.y
> 1:  6   1   a
> 2:  7   2   b
> 3:  8   3   c
> 4:  9   4   d
> 5: 10   5   e

请注意,使用添加和后缀a的标准dplyr格式正确管理冲突的列。.x.y

但是,如果我现在尝试删除其中一列:

dt1 %>%
  left_join(
    dt2,
    by = "b"
  ) %>%
  select(
    -a.y
  ) %>%
  as.data.table()
> Error in is_character(x) : object 'a.y' not found

有趣的是,如果我尝试选择其中一a列 ( select(a.x)),我会得到相同的错误,但是...select(a)

dt1 %>%
  left_join(
    dt2,
    by = "b"
  ) %>%
  select(
    a
  ) %>%
  as.data.table()
>    a.b
> 1:   1
> 2:   2
> 3:   3
> 4:   4
> 5:   5

其中选定的列是明确的dt1$a,但由于某种原因,给定的列名是a.b。(如果我尝试select(a.b),我会得到同样的object not found错误)。

同时,如果我尝试 drop a,两a列都会被删除:

dt1 %>%
  left_join(
    dt2,
    by = "b"
  ) %>%
  select(
    -a
  ) %>%
  as.data.table()
>     b
> 1:  6
> 2:  7
> 3:  8
> 4:  9
> 5: 10

那么,如何select在表具有冲突(而不是连接)列的连接中使用?

编辑:

正如一些答案中提到的,我显然可以在选择之前执行惰性评估,这很有效。但是,它会引发警告(因为我想将我的对象保留为 a data.table,而不是 a data.frame)所以它似乎不是预期的方法:

dt1 %>%
  left_join(
    dt2,
    by = "b"
  ) %>%
  as.data.table() %>%
  select(
    -a.x
  )
>     b a.y
> 1:  6   a
> 2:  7   b
> 3:  8   c
> 4:  9   d
> 5: 10   e
> Warning message:
> You are using a dplyr method on a raw data.table, which will call the data 
> frame implementation, and is likely to be inefficient.
> * 
> * To suppress this message, either generate a data.table translation with
> * `lazy_dt()` or convert to a data frame or tibble with
> * `as.data.frame()`/`as_tibble()`.
4

3 回答 3

2

关键是dtplyr使用惰性求值。更多在这里https://dtplyr.tidyverse.org/,但关键是:

与之前的版本相比,这个版本的 dtplyr 是一个完整的重写,只关注使用lazy_dt() 触发的惰性求值。这意味着在您使用 as.data.table()、as.data.frame() 或 as_tibble() 明确请求之前,不会执行任何计算。

在您的示例中,这意味着在选择之前尚未评估连接,它们正在被翻译并等待评估。翻译机制允许 dtplyr 更有效地将多个动词组合成一个动作。(更多关于翻译的信息:https ://dtplyr.tidyverse.org/articles/translation.html )

有几种方法可以解决这个问题。最简单的方法是使用as.data.frame().

dt1 %>%
  left_join(
    dt2,
    by = "b"
  ) %>%
  as.data.frame() %>%
  select(-a.y)

另一种方法是获取 data.table 对象,然后使用data.table语法对列进行子集化。

于 2019-11-19T16:49:15.440 回答
1

显然,left_join不适用于data.table但可以使用data.frame(我以前不知道)。

因此,一种解决方案可能是:

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

dt1 <- lazy_dt(data.table(a = 1:5, b = 6:10))
dt2 <- lazy_dt(data.table(a = letters[1:5], b = 6:10))

as.data.frame(dt1) %>%
  left_join(as.data.frame(dt2), by = "b") %>%
  select(-a.y) %>%
  as.data.table()
于 2019-11-19T16:46:08.213 回答
0

这是当前版本 (1.0.0) 中的一个错误dtplyr,但现在已在开发版本中修复。

于 2019-12-26T12:50:53.097 回答