カスタム関数を使用して、好ましくは並列化を使用して複数の列を追加してデータフレームを一度に変更する必要があることがよくあります。以下は私がすでにこれを行う方法を知っている方法です。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))
セットアップは、私は2つの新しい列、foocol = x + y
とbarcol = (x + y) * 100
をしたいと仮定しますが、これらは実際にはカスタム関数で行われ、複雑な計算であることを。
方法1:それは、各行のための2つの関数呼び出しとx + y
の2「高価」な計算を必要とするため、別々に列を追加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:行方向の操作にトリック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:purrrから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")
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(r)
の代わりに関数定義function(x, y, ...)
の計算に使用する予定のすべての列を参照する必要があります。
良いか良いオプションがありますか?私が記述した方法に懸念はありますか?
本当に 'dplyr'を読み込んだ後に' plyr' *を読み込むべきではありません。それはあなたが聞くべきであるという警告を出します。 – Gregor
あなたは 'purrr :: invoke'とその変種で遊ぶことができます。 'invoke(foobar、df)'( 'do.call(foobar、df)'と同じです)。ただし、どの列をどのパラメータに渡すかを参照する必要がある場合は、実際には良いことですが、静かに間違いを犯すこともできます。 – alistaire
何かが欠けていない限り、方法1は 'rowwise()'を必要としません。 –