Как бороться с NSE и usemethod

Взгляните на эти «простые» функции:

test <- function(x,...){
    UseMethod("test",x)
}

test.default<-function(x,y,data){
  message("default")
  print(deparse(substitute(x)))
  print(deparse(substitute(y)))
  print(deparse(substitute(data)))
  print(match.call())
}

test.formula <- function(x,...){
  message("formula")
  print(deparse(substitute(x)))
  print(match.call())
}

Всё хорошо

data(iris)
test.formula(Sepal.Length~Petal.Width,iris)
test.default(Sepal.Length,Petal.Width,iris)
test(Sepal.Length~Petal.Width,iris)

Кроме этого:

test(Sepal.Length,Petal.Width,iris)

Из-за NSE: object 'Sepal.Length' not found

Есть идеи ?


r nse
person Vincent Guyader    schedule 18.03.2017    source источник
comment
Я не получаю ошибку, и третий тест возвращает то же самое, что и первый. Я бы не ожидал, что R сможет найти имя столбца, если только ваша функция не предоставила объект iris в качестве среды.   -  person IRTFM    schedule 19.03.2017
comment
@42- ты попробуешь это : test(Sepal.Length,Petal.Width,iris) ?   -  person Vincent Guyader    schedule 19.03.2017
comment
Да, но Sepal.Length не является именем R в пути поиска. Это атрибут iris с символьным значением.   -  person IRTFM    schedule 19.03.2017
comment
@42- ошибка не с test(Sepal.Length~Petal.Width,iris), а с test(Sepal.Length,Petal.Width,iris), я знаю, почему у меня ошибка (из-за NSE), я просто хочу найти хороший способ использовать NSE с UseMethod.   -  person Vincent Guyader    schedule 19.03.2017


Ответы (3)


Нелегко не найти решение, потому что вы не указали здесь свою конечную цель, но я думаю, что согласен с 42- в том, что отправка S3 может не быть инструментом. Возможно, вы ищете lazyeval::lazy_dots

library("lazyeval")
tezt <- function(data, ... ){
  dots <- lazyeval::lazy_dots(...)
  dots
}

Вы отдаете ... lazy_dots, а потом можете с этим разобраться.

str( tezt(iris, Sepal.Length, Petal.Width) )
#> List of 2
#>  $ :List of 2
#>   ..$ expr: symbol Sepal.Length
#>   ..$ env :<environment: 0x7fedb11bb720> 
#>   ..- attr(*, "class")= chr "lazy"
#>  $ :List of 2
#>   ..$ expr: symbol Petal.Width
#>   ..$ env :<environment: 0x7fedb11bb720> 
#>   ..- attr(*, "class")= chr "lazy"
#>  - attr(*, "class")= chr "lazy_dots"

or:

str( tezt(iris, Sepal.Length ~ Petal.Width) )
#> List of 1
#>  $ :List of 2
#>   ..$ expr: language Sepal.Length ~ Petal.Width
#>   ..$ env :<environment: 0x7fedb11bb720> 
#>   ..- attr(*, "class")= chr "lazy"
#>  - attr(*, "class")= chr "lazy_dots"

Также вас может заинтересовать hadley/rlang.

person Romain Francois    schedule 19.03.2017

Я нашел решение, но сложное...

tryCatch.W.E <- function(expr)
   {
         W <- NULL
         w.handler <- function(w){ # warning handler
        W <<- w
        invokeRestart("muffleWarning")
           }
         list(value = withCallingHandlers(tryCatch(expr, error = function(e) e),
                                                                 warning = w.handler),
                     warning = W)
     }

test <- function(x, ...) {

  if (inherits(tryCatch.W.E(x)$value,"error")) { 

    return(test.default(x,...))
    }

  UseMethod("test", x)
}

test.default <- function(x, y, data) {
  message("default")
  print(deparse(substitute(x)))
  print(deparse(substitute(y)))
  print(deparse(substitute(data)))
  print(match.call())
}

test.formula <- function(x, ...) {
  message("formula")
  print(deparse(substitute(x)))
  print(match.call())
}
test.formula(Sepal.Length ~ Petal.Width, iris)
test.default(Sepal.Length, Petal.Width, iris)
test(Sepal.Length ~ Petal.Width, iris)

Теперь это нормально:

test(Sepal.Length, Petal.Width, iris)
person Vincent Guyader    schedule 18.03.2017

Меня бы больше устроило:

require(ggplot2)

test <- aes
test(Sepal.Length, Petal.Width, iris)
#    
* x -> Sepal.Length
* y -> Petal.Width
*   -> iris

Проблема с использованием отправки S3 заключается в том, что для «голого» Sepal.Length нет значения и, следовательно, нет класса. Функция aes не использует диспетчеризацию S3, а сразу переходит к match.call()[-1].

person IRTFM    schedule 18.03.2017