dplyrを使ったdata.frameの前処理を関数化する
表題の通り,dplyr使って前処理する際に,それを関数化する方法のメモ.ユースケースとしては,ちょっとだけ条件変えてデータフレーム自体を何度か出し直すってとき用.
関数
まるっとフィルタ用のconditionと,select用のvariablesを引数で渡します*1.ポイントは,filterではなくfilter_とアンスコが付いていること.これは,この処理がNon-Standard Evaluation*2で評価してはいけないからです.
preprocess = function(df, condition, variables) { df %>% filter_(condition) %>% select_(variables) }
呼び出し側
呼び出し側は,条件文をquote()に入れて渡します.selectで使う変数の方は,c()で包んでリストにしておく必要あり.
> res = preprocess(iris, + quote(Species=='virginica'), + quote(c(Sepal.Length, Sepal.Width))) > nrow(res) [1] 50 > head(res) Sepal.Length Sepal.Width 1 6.3 3.3 2 5.8 2.7 3 7.1 3.0 4 6.3 2.9 5 6.5 3.0 6 7.6 3.0
これで前処理スッキリ,再利用ブラボー.
おまけ
ちょっと違うアプローチでいうと,以下のようなのもあります*3.
直に指定
preprocess = function(x, column, fn) { fn(x[,column]) }
> preprocess(iris, 'Sepal.Length', max) [1] 7.9
subsetを使う
preprocess = function(df, condition) { e = substitute(condition) r = eval(e, df, parent.frame()) subset(df, r) }
> res = preprocess(iris, Sepal.Length > 7.0) > nrow(res) [1] 12 > head(res) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 103 7.1 3.0 5.9 2.1 virginica 106 7.6 3.0 6.6 2.1 virginica 108 7.3 2.9 6.3 1.8 virginica 110 7.2 3.6 6.1 2.5 virginica 118 7.7 3.8 6.7 2.2 virginica 119 7.7 2.6 6.9 2.3 virginica > ||<
*1:参考: Passing strings as arguments in dplyr verbs - Stack Overflow
*2:NSEについては R - NSEとは何か - Qiitaとか, dplyrのなんたら_eachを効率的に使う - 東京で尻を洗うとか, NSE(Non-Standard Evaluation)について - 東京で尻を洗うの記述が詳しいです.大元は Non-standard evaluationなので,こちらを読むのが良さげです.
*3:参考: r - Pass a data.frame column name to a function - Stack Overflow