【问题标题】:Order by multiple columns using non-standard evaluation使用非标准评估按多列排序
【发布时间】:2019-11-07 21:44:17
【问题描述】:

假设我想使用多列并使用非标准演变来订购data.frame。我可能有一个看起来像这样的函数

my_order <- function(data, ...) {
  with(data, order(...))
}

使用此函数时出现错误,因为我的列未在 with 的上下文中进行评估。

my_order(mtcars, mpg, cyl)
# Error in order(...) : object 'mpg' not found 

注意:我不想使用 dplyr::arrange() 来解决这个问题,因为它会添加依赖项。

【问题讨论】:

    标签: r non-standard-evaluation


    【解决方案1】:

    一种选择是将表达式包装成eval.parent(substitute(...))

    my_order <- function( data, ... ) {
      eval.parent(substitute( with(data, order(...)) ))
    }
    
    my_order( mtcars, cyl, mpg )
    # [1] 32 21  3  9  8 27 26 19 28 18 20 11  6 10 30  1  2  4 15 16 24  7 17 31 14
    # [26] 23 22 29 12 13  5 25
    

    请注意,我们使用eval.parent() 而不是eval(),因为eval/substitute combo doesn't play well with nested functionseval.parent() 技巧已将 proposed by @MoodyMudskipper 作为解决此问题的一种方式,并允许我们在其他函数中无缝使用 my_order(),包括 magrittr 管道:

    mtcars %>% my_order(cyl)
    # [1]  3  8  9 18 19 20 21 26 27 28 32  1  2  4  6 10 11 30  5  7 12 13 14 15 16
    # [26] 17 22 23 24 25 29 31
    

    【讨论】:

    • 有一点需要注意,如果你使用带句点的参数,比如.data,这种方法似乎不起作用。
    • @nathaneastwood:我无法复制这个问题。对我来说,使用 .datadata 一样有效。
    • 因此,当您尝试将my_order() 与管道结合使用时似乎会发生这种情况,并且与变量的名称无关。所以mtcars %&gt;% my_order(cyl)会给出错误,例如。
    • @nathaneastwood:好的,我知道问题出在哪里。请查看更新后的答案。
    【解决方案2】:

    这是使用基数 R 传递未解析符号的一种方法

    my_order <- function(data, ...) {
      dots <- substitute(...())
      with(data, do.call("order", as.list(dots)))
    }
    my_order(mtcars, mpg, cyl)
    

    基本上我们使用替代来捕获符号名称,然后使用do.call 将它们注入到对order 的调用中。

    您可以考虑重新编写对函数的调用并更改评估环境

    my_order <- function(data, ...) {
      call <-match.call()
      call[[1]] <- quote(order)
      call[2] <- NULL
      eval(call, data, parent.frame())
    }
    my_order(mtcars, mpg, cyl)
    

    【讨论】:

    • 是的,这是完美的。我在玩do.call 并不能完全正确(我有do.call(order, list(with(data, ...))) 几乎就在那里)。顺便说一句,你可以做do.call(order, as.list(dots)),我相信它可能比引用订单稍微快一点。谢谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-18
    • 1970-01-01
    相关资源
    最近更新 更多