我经常需要使用自定义函数一次性通过多个列来改变数据框,最好使用并行化。以下是我已经知道如何执行此操作的方法。
设置
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)
在这里,我通过拆分我刚刚创建的唯一ddply
列,欺骗id
来调用每一行上的函数。但它很笨重,需要维护一个无用的列。
方法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
转换为列表然后返回,所以可能会有性能损失。
我还需要在函数定义function(x, y, ...)
中引用我计划用于计算的所有列而不仅仅是行对象的function(r)
,这也有点烦人。
我错过了任何好的或更好的选择吗?对我描述的方法有任何顾虑吗?
答案 0 :(得分: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个并行化的潜力。