【问题标题】:How to deal with NSE and usemethodNSE如何处理及使用方法
【发布时间】:2017-03-18 22:21:21
【问题描述】:

看看这个“简单”的功能:

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

有什么想法吗?

【问题讨论】:

  • 我没有收到错误,第三个“测试”返回与第一个相同。除非您的函数提供 iris 对象作为环境,否则我不希望 R 能够找到列名。
  • @42- 你试试这个:test(Sepal.Length,Petal.Width,iris) ?
  • 是的,但 Sepal.Length 不是搜索路径上的 R 名称。它是iris 的一个属性,带有一个字符值。
  • @42- 错误不是test(Sepal.Length~Petal.Width,iris) 而是test(Sepal.Length,Petal.Width,iris),我知道为什么我有错误(因为NSE),我只想找到一个“不错”的使用方式带有 UseMethod 的 NSE。

标签: r nse


【解决方案1】:

很难想出一个解决方案,因为你没有在这里指定你的最终游戏,但我想我同意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"

或:

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感兴趣

【讨论】:

    【解决方案2】:

    我找到了一个解决方案,但很棘手......

    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)
    

    【讨论】:

      【解决方案3】:

      我会更满意:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多