使用plyr / dplyr / purrr向数据框添加多个列的方法

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

建立

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

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

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

方法1:使用rowwise和mutate分别添加列

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来调用每一行上的函数.但它很笨重,需要维护一个无用的列.

方法3:splat

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

df_out3 <- splat(foobar)(df)

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

方法4: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")

purrr中的by_row函数消除了对唯一id列的需要,但此操作未并行化.

方法5:pmap_df

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

这是我发现的最佳选择. pmap系列函数也接受匿名函数来应用于参数.我相信pmap_df会将df转换为列表然后返回,所以可能会有性能损失.

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

我错过了任何好的或更好的选择吗?我描述的方法有什么问题吗?

最佳答案 如何使用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的并行化潜力.

点赞