LoginSignup
20
24

More than 5 years have passed since last update.

NSEとは何か

Posted at

NSEとは何か

@dichikaさんによる素晴らしdplyrの紹介。
http://d.hatena.ne.jp/dichika/20141027

Non Standard Evaluation (NSE)とは、関数内部から、その関数を呼び出した時の引数のじゃなくて表現式そのものを、
関数の中での処理に利用しようという引数評価の方法です。

ある関数が引数を扱うとき、普通は興味あるのはその引数の
ところがRでは関数内部で、関数に与えられた引数の表現式を知ることができる。別にRに限った話じゃないけど。

以下のf()(通常評価)とg()(NSE)の違いを見れば一目瞭然で、

f = function(i, j, k) {
  print(i)
  print(j)
  print(k)
  }

g = function(i, j, k) {
  print(substitute(i))
  print(substitute(j))
  print(substitute(k))
}


x = "orz"

f(i = 1, j = mean, k = x) 
## [1] 1
## function (x, ...) 
## UseMethod("mean")
## <bytecode: 0x7ff59bbb6ce0>
## <environment: namespace:base>
## [1] "orz"
g(i = 1, j = mean, k = x) 
## [1] 1
## mean
## x

この引数に対するg()的な評価のしかたをNon Standard Evaluation (NSE)と呼ぶのである。

どう使うかというと、一般的にはデータフレームとかリストとかのデータを与えて、その要素を指定する状況が多分、圧倒的におおい。
例えば、

# Standard evaluation
m = function(d, i) {
  d[[i]]
  }

m(mtcars, "vs")
##  [1] 0 0 1 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1
m(mtcars, vs)
## Error in (function(x, i, exact) if (is.matrix(i)) as.matrix(x)[[i]] else .subset2(x, :  オブジェクト 'vs' がありません

# NSE
n = function(d, i) {
  d[[deparse(substitute(i))]]
  }

n(mtcars, "vs")
## NULL
n(mtcars, vs)
##  [1] 0 0 1 1 0 1 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 1 0 0 0 1

何がオトクかというと、引数に変数名を与えるときに""で囲わなくてよい、とか、まあ色いろあるんだけど、あんまり気にしないでいいと思う。
subset()subsetとかをNSEじゃない方法で与えるとか、結構面倒かも。

@dichika さんの元記事の例

# NSE
iris %>% group_by(Species) %>% summarise_each(funs(min, mean, median, max), Sepal.Width)
## Error in eval(expr, envir, enclos):  関数 "%>%" を見つけることができませんでした

# ふつー評価
iris %>% group_by(Species) %>% summarise_each_(funs(min, mean, median, max), "Sepal.Width")
## Error in eval(expr, envir, enclos):  関数 "%>%" を見つけることができませんでした

列名を変数で与えたいときなんかはふつー評価でやる。


以下余談。RではこのNSEが実に多用されているのである。

例えばsubset

subset(mtcars, subset = disp == max(disp))
##                     mpg cyl disp  hp drat   wt  qsec vs am gear carb
## Cadillac Fleetwood 10.4   8  472 205 2.93 5.25 17.98  0  0    3    4

ここでdisp == max(disp)というのは引数の値ではなくて表現式で、
これを呼び出し元で評価しても失敗する。
なぜならdispなんていうオブジェクトはどこにも無いからで、それはmtcarsの中にしかない。
つまり、これは失敗する。

cond = disp == max(disp); subset(mtcars, subset = cond)
## Error in eval(expr, envir, enclos):  オブジェクト 'disp' がありません
## Error in eval(expr, envir, enclos):  オブジェクト 'cond' がありません

ちょっと凝ったことしてプロミス化しても

delayedAssign("cond", disp == max(disp))
subset(mtcars, subset = cond)
## Error in eval(expr, envir, enclos):  オブジェクト 'disp' がありません

無駄。

ちなみにsubsetの列選択とか、もう無茶苦茶な感じがするが、これはこれで便利である。

head(subset(mtcars, select = c(mpg, wt:am)))
##                    mpg    wt  qsec vs am
## Mazda RX4         21.0 2.620 16.46  0  1
## Mazda RX4 Wag     21.0 2.875 17.02  0  1
## Datsun 710        22.8 2.320 18.61  1  1
## Hornet 4 Drive    21.4 3.215 19.44  1  0
## Hornet Sportabout 18.7 3.440 17.02  0  0
## Valiant           18.1 3.460 20.22  1  0
20
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
24