【问题标题】:mutate_if, summarize_at etc coerce data.table to data.framemutate_if、summarize_at 等强制 data.table 到 data.frame
【发布时间】:2019-10-02 08:23:42
【问题描述】:

似乎有一些dplyr 函数,包括mutate_ifmutate_allmutate_at 等强制data.table 输入到data.frame。这似乎是一种奇怪的行为,尽管它记录在 ?mutate_all 中(在“价值”下,它说“data.frame” - 但它不会强制将 tibbles 转换为 data.frames。)

require(dplyr)
require(data.table)
data("iris")
dt <- as.data.table(iris)
class(dt)
#[1] "data.table" "data.frame"
class(mutate_if(dt, is.numeric, as.numeric))
#[1] "data.frame"

但是,小标题不会发生这种情况:

tb <- as_tibble(iris)
class(tb)
#[1] "tbl_df"     "tbl"        "data.frame"
class(mutate_if(tb, is.numeric, as.numeric))
#[1] "tbl_df"     "tbl"        "data.frame"

有什么方法可以维护 data.table,还是每次我使用一个作用域 mutate 函数时都需要强制使用 as.data.table

【问题讨论】:

  • 根据文档,dplyr 函数尝试返回与输入相同类型的对象。由于data.table 不是基类,所以它返回data.frame
  • tbl_df 也不是基类。
  • dplyr 旨在与 tibbles 一起使用。
  • 我从未测试过这个,但也许检查this package
  • 感谢@DavidArenburg。 dtplyr 包似乎需要一点点温柔、关爱——我尝试安装它并重试我的 reprex,但我得到的只是错误。我实际上认为 data.table 作为后端是内置在 dplyr 中的。

标签: r dplyr data.table tibble


【解决方案1】:

如果您想尝试其他方法, 我最近发布了table.express 包, 它使用许多dplyr 和自定义动词来构建data.table 表达式。

链接的小插图提供了详细的解释, 但有一些例子:

library(data.table)
library(table.express)

data("iris")
DT <- as.data.table(iris)

# mutate_all (modification by reference does not print)
DT %>%
  mutate_sd(everything(), as.integer)

# mutate_if
DT %>%
  mutate_sd(~ is.numeric(.x), as.integer)

# mutate_at
DT %>%
  mutate_sd(contains("."), ~ .x * 1.5)

# transmute_all
DT %>%
  transmute_sd(everything(), as.integer)

# transmute_if
DT %>%
  transmute_sd(~ is.numeric(.x), as.integer)

# transmute_at
DT %>%
  transmute_sd(contains("."), as.integer)

请注意mutate_sd 默认通过引用修改, 因此,如果您愿意,请在示例之间重新定义 DT

此外,从 0.3.0 版开始, 您将无法同时加载table.expressdtplyr, 因为它们为许多 dplyr 泛型定义了相同的 data.table 方法。

【讨论】:

  • 这似乎是狗b*llocks。我喜欢这种语法,它的好处是将类似 dplyr 的语法与您使用 data.table 作为后端的一些透明度相结合。
【解决方案2】:

您的问题可能没有令人满意的答案,但这些包装函数可以让您不必每次都转换回数据表。

如果您不想在每个脚本或项目中包含这些内容,并且不想将它们放在您的.Rprofile 中,您甚至可以用它们制作一个很小的包。这非常简单。

mutate_all <- function(.tbl, ...) {
  if ("data.table" %in% class(.tbl)) {
    .tbl %>% mutate_all(...) %>% as.data.table()
  } else {
    .tbl %>% mutate_all(...)
  }
}
mutate_if <- function(.tbl, ...) {
  if ("data.table" %in% class(.tbl)) {
    .tbl %>% mutate_if(...) %>% as.data.table()
  } else {
    .tbl %>% mutate_if(...)
  }
}
mutate_at <- function(.tbl, ...) {
  if ("data.table" %in% class(.tbl)) {
    .tbl %>% mutate_at(...) %>% as.data.table()
  } else {
    .tbl %>% mutate_at(...)
  }
}
transmute_all <- function(.tbl, ...) {
  if ("data.table" %in% class(.tbl)) {
    .tbl %>% transmute_all(...) %>% as.data.table()
  } else {
    .tbl %>% transmute_all(...)
  }
}
transmute_if <- function(.tbl, ...) {
  if ("data.table" %in% class(.tbl)) {
    .tbl %>% transmute_if(...) %>% as.data.table()
  } else {
    .tbl %>% transmute_if(...)
  }
}
transmute_at <- function(.tbl, ...) {
  if ("data.table" %in% class(.tbl)) {
    .tbl %>% transmute_at(...) %>% as.data.table()
  } else {
    .tbl %>% transmute_at(...)
  }
}

【讨论】:

  • 这似乎是唯一的出路。现在,我决定通过为 mutate 等定义新方法来做同样的事情,如下所示: mutate.data.table
  • @BjaRule 你认为这是公认的答案吗?只是把松散的东西绑起来。
  • 我投了赞成票,因为认为这是一个不错的解决方法,但实际上并没有解决问题。如果 dtplyr 有效,那将是公认的答案。
【解决方案3】:

您是否尝试过使用

df %>%
mutate_if(yourmutate) %>%
data.table()

您的框架将同时是data.tabledata.frame

按照你的例子:

require(dplyr)
require(data.table)
data("iris")
dt <- as.data.table(iris)
class(dt)
#
dt <- mutate_if(dt, is.numeric, as.numeric) %>% data.table()
class(dt)

【讨论】:

    猜你喜欢
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多