メモ:dplyrがStandard evaluationをdeprecatedにしようとしている理由

追記(2017/3/25):


追記(2017/4/7):

やはり「NSEをdeprecatedに」というのは間違いなのでタイトル修正しました。すみません。


だいぶ昔にこんな文章を書きました。

notchained.hatenablog.com

が、今、dplyrのNSEの文章を見ると

Non-standard evaluation is now handled with the tidy evaluation framework. Please see vignette(“programming”). (https://github.com/hadley/dplyr/blob/356146c1b5da3adc985454e0348b9d24dd74b8af/vignettes/nse.Rmd

と書かれています。いったい何が…。

dplyrの欠点

その理由は、Programming with dplyr(まだ執筆中)というvignetteに書かれています。ここで持ち出されている「tidyeval」という概念はまだいろいろ揺れ動いていますが、問題意識自体はなるほどなあと思ったので先んじて紹介します。

引数は参照透過ではない

Most dplyr arguments are not referentially transparent.

参照透過でない、というのはつまり、このvignetteに例が上がっていますが、

filter(df, my_var == 1)

というのを

var <- my_var
filter(df, var == 1)

とは書けないということです。これはdplyr初心者がよく陥る間違いであるようです。

解釈が一意に定まらない

dplyr code is ambiguous.

これは、

filter(df, x == y)

というコードがあったとして、グローバル環境にxy変数があるかないかによって、以下のいずれかを表す可能性があります。

df[df$x == df$y, ]
df[df$x == y, ]
df[x == df$y, ]
df[x == y, ]

これは、文脈抜きにはどれが正しいか判別できないし、エラーになるべきはずがxyといった列名と同じ変数がたまたまグローバル環境にあることによってエラーにならない、といったことも起こってしまいます。

rlangの対応

これに対して、lazyevalパッケージの後継であるrlangパッケージは、以下のような対応を検討しています。

注:rlangのインターフェースはまだまだ発展途上なので、これは今後大幅に変化すると思います。ここに書いたことはすぐに古くなるのであまり信用しないでください

!!:=

これは某株式会社の公式アカウントが解説してくださるとの風の噂なので、ここではあまり触れません。mutate()であれば以下のようにできます。

var <- "my_var"
mutate(iris, !!var := 1)

filter()はどうやるかよくわかりませんでした。たぶんこんな感じじゃないかと思ったんですがうまく動かなかったのでやはり某公式アカウントに見せ場を譲ります。

var <- "Species"
filter(iris, !! ~var == "virginica")

追記(2017/3/25):rlang::sym

var <- rlang::sym("Species")
filter(iris, (!! var) == "virginica")

.data

これは単純で、xというシンボルがdplyrの関数中に出てきたときにそれがdfの列xなのかグローバル変数xなのか分かりませんでしたが、.data$xとすることで前者を明示できる、ということです。つまり、

filter(df, x == y)

は、

filter(df, .data$x == .data$y)

とすることで、データフレームdfが列xyを持たない場合は、グローバル環境に同名の変数があるかないかに関わらずエラーになります。パッケージ中でdplyrを使う場合はこういう感じに.dataを明示すべきでしょう。

まとめ

dplyrはけっこう変更が入ります。備えよう。

というとやばい変更ばっかり入る感じがしますが、Windowsユーザは喜んだ方がいいです。非ASCII文字の扱いが劇的に改善しています。

github.com

github.com

話している内容はあんまり理解できないんですが、西欧言語圏の人がここまで非ASCII文字の扱いに対して深く議論をして改善していくのには、最大限の敬意を表したい気持ちでいます。ほんとに、足を向けて眠れません。ありがたや。