【问题标题】:Ways to add multiple columns to data frame using plyr/dplyr/purrr使用 plyr/dplyr/purrr 向数据框添加多列的方法
【发布时间】:2016-11-19 01:51:14
【问题描述】:

我经常需要使用自定义函数一次通过额外的几列来改变数据框,最好使用并行化。以下是我已经知道如何做到这一点的方法。

设置

library(dplyr)
library(plyr)
library(purrr)
library(doMC)
registerDoMC(2)

df <- data.frame(x = rnorm(10), y = rnorm(10), z = rnorm(10))

假设我想要两个新列,foocol = x + ybarcol = (x + y) * 100,但这些实际上是在自定义函数中完成的复杂计算。

方法一:分别使用rowwisemutate添加列

foo <- function(x, y) return(x + y)
bar <- function(x, y) return((x + y) * 100)

df_out1 <- df %>% rowwise() %>% mutate(foocol = foo(x, y), barcol = bar(x, y))

这不是一个好的解决方案,因为它需要对每一行进行两次函数调用和两次“昂贵”的x + y 计算。它也没有并行化。

方法2:欺骗ddply进入行操作

df2 <- df
df2$id <- 1:nrow(df2)

df_out2 <- ddply(df2, .(id), function(r) {
  foocol <- r$x + r$y
  barcol <- foocol * 100
  return(cbind(r, foocol, barcol))
}, .parallel = T)

在这里,我通过拆分我刚刚创建的唯一 id 列来欺骗 ddply 在每一行上调用一个函数。但是,它很笨重,并且需要维护一个无用的列。

方法三:splat

foobar <- function(x, y, ...) {
  foocol <- x + y
  barcol <- foocol * 100
  return(data.frame(x, y, ..., foocol, barcol))
}

df_out3 <- splat(foobar)(df)

我喜欢这个解决方案,因为您可以在自定义函数中引用 df 的列(如果需要,可以是匿名的)而无需数组理解。但是,此方法没有并行化。

方法四:by_row

df_out4 <- df %>% by_row(function(r) {
  foocol <- r$x + r$y
  barcol <- foocol * 100
  return(data.frame(foocol = foocol, barcol = barcol))
}, .collate = "cols")

来自purrrby_row 函数消除了对唯一id 列的需要,但此操作不是并行化的。

方法五:pmap_df

df_out5 <- pmap_df(df, foobar)
# or equivalently...
df_out5 <- df %>% pmap_df(foobar)

这是我找到的最佳选择。 pmap 系列函数也接受匿名函数以应用于参数。不过,我相信 pmap_df 会将 df 转换为列表并返回,所以可能会影响性能。

这也有点烦人,我需要在函数定义function(x, y, ...) 中引用我计划用于计算的所有列,而不是仅仅为行对象引用function(r)


我是否缺少任何好的或更好的选择?我描述的方法有什么问题吗?

【问题讨论】:

  • 你真的不应该加载plyr 之后加载dplyr。它给出了一个你应该听的警告。
  • 您可以使用purrr::invoke 及其变体,例如invoke(foobar, df)(相当于do.call(foobar, df))。但是,如果您需要引用哪些列传递给哪些参数,或者您可以默默地犯错,这通常是一件好事。
  • 除非我遗漏了什么,否则方法 1 不需要rowwise()

标签: r dataframe dplyr plyr purrr


【解决方案1】:

使用data.table怎么样?

library(data.table)

foo <- function(x, y) return(x + y)
bar <- function(x, y) return((x + y) * 100)

dt <- as.data.table(df)

dt[, foocol:=foo(x,y)]
dt[, barcol:=bar(x,y)]

data.table 库非常快,并且至少有一些 some 的并行化潜力。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多