Closed5

[R] このコードなんで動くの?

kitta65kitta65

このコードなんで動くの?

iris |> dplyr::select(Sepal.Length) |> sum() #876.5

irisというデータセットについて、がく辺の長さの合計を求めているというのは分かる。
ただ、最近Rを触っていない自分はこう思ってしまう。

  • iris Sepal.Length なんて変数を定義した覚えがない
  • sum() って 0 だよな
kitta65kitta65

再現性を担保するために書いておくと rocker/verse:4.1.2 って docker イメージで動作確認している。

kitta65kitta65

まず iris なんだけれど、これは datasets という package の一部らしい。
だから datasets::iris という使い方もできる。

ここまではよいのだが、じゃあなぜ iris のみで使えるのか?
どうも最初から datasets package がロードされてしまっているようだ。

print(.packages())
# [1] "stats"     "graphics"  "grDevices" "utils"     "datasets"  "methods"   "base"

ということはもちろん明示的にアンロードすることもできる。

detach("package:datasets", unload=TRUE)
iris # Error: object 'iris' not found
kitta65kitta65

次に sum() なんだけれど、少し簡略化して以下のコードについて考えてみる。

1:5 |> sum()

|> はパイプ演算子で、左項の値を右項の関数呼び出しの引数として扱うもの。
それは分かるんだけれど sum() って評価されると 0 だよな。

sum() # 0

じゃあこう書いてもいいということか(違う)。

1:5 |> 0 # Error: The pipe operator requires a function call as RHS

要するに評価のタイミングがピンと来ていないんだよな。
Stack Overflowquote() してみなって助言があったから従ってみる。

quote(1:5 |> sum()) # sum(1:5)

これが何を意味しているかっていうと、値が評価されるよりも前に sum(1:5) に変換されているということ。

kitta65kitta65

残る疑問点は dplyr::select(Sepal.Length) だけ。
もちろん Sepal.Length なんていう変数は定義されていない。

Sepal.Length
# Error: object 'Sepal.Length' not found

おそらくさっきの |>sum() の件と同じく、評価のタイミングが問題なのだろうという気はする。
深入りしない程度に dplyr::select のコードを見てくると、渡された Sepal.Length などはすぐに評価されないよう expr() で包んで後続の処理に渡されている。

https://github.com/tidyverse/dplyr/blob/1d17672a54305170dc75c251f8ae69a85c0bea37/R/select.R#L66

今回の調べものはこれくらいにしておくけれど、Rって奥が深いのね。

このスクラップは2ヶ月前にクローズされました