4

カスタム関数を使用して、できれば並列化を使用して、一度に複数の列を追加してデータ フレームを変更する必要があることがよくあります。以下は、私がすでにこれを行う方法を知っている方法です。

設定

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

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

2 つの新しい列 と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))

これは、各行に対して 2 つの関数呼び出しと の 2 つの「高価な」計算が必要になるため、適切な解決策ではありません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")

purrrby_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)


良いまたはより良いオプションがありませんか?私が説明した方法に懸念はありますか?

4

1 に答える 1