読者です 読者をやめる 読者になる 読者になる

About connecting the dots.

statistics/machine learning adversaria.

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