2016-07-15 2 views
4

カスタム関数を使用して、好ましくは並列化を使用して複数の列を追加してデータフレームを一度に変更する必要があることがよくあります。以下は私がすでにこれを行う方法を知っている方法です。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 + ybarcol = (x + y) * 100をしたいと仮定しますが、これらは実際にはカスタム関数で行われ、複雑な計算であることを。

方法1:それは、各行のための2つの関数呼び出しとx + yの2「高価」な計算を必要とするため、別々に列を追加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)) 

を使用してこれは良い解決策ではありません。それも並列化されていません。

方法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_dfdfをリストに変換して戻っていると信じていますが、パフォーマンスが低下する可能性があります。

行オブジェクトの代わりにfunction(r)の代わりに関数定義function(x, y, ...)の計算に使用する予定のすべての列を参照する必要があります。


良いか良いオプションがありますか?私が記述した方法に懸念はありますか?

+2

本当に 'dplyr'を読み込んだ後に' plyr' *を読み込むべきではありません。それはあなたが聞くべきであるという警告を出します。 – Gregor

+1

あなたは 'purrr :: invoke'とその変種で遊ぶことができます。 'invoke(foobar、df)'( 'do.call(foobar、df)'と同じです)。ただし、どの列をどのパラメータに渡すかを参照する必要がある場合は、実際には良いことですが、静かに間違いを犯すこともできます。 – alistaire

+0

何かが欠けていない限り、方法1は 'rowwise()'を必要としません。 –

答えて

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可能性を秘めています。

関連する問題