【问题标题】:passing data frame to mutate within function传递数据帧以在函数内变异
【发布时间】:2014-08-27 16:20:46
【问题描述】:

我想在一个函数中传递一个数据框及其列以由 dplyr 的 mutate 处理。

这是一个例子

multifun <- function(dataf,vari){
 mutate(dataf,newvar=vari*2)
}

multifun(mtcars,gear)

这个函数的问题是变量'gear'不是一个可识别的对象。更具体地说,我得到了错误

mutate_impl(.data, named_dots(...), environment()) 对象中的错误 找不到“齿轮”

这是 dplyr 的 mutate 正在寻找相关变量的环境的问题。

我明白了

multifun(mtcars,mtcars$gear)

会给我想要的答案,即

    mpg  cyl  disp  hp   drat  wt   qsec  vs am   gear carb newvar
1  21.0   6   160.0 110  3.90 2.620 16.46  0  1    4    4      8
2  21.0   6   160.0 110  3.90 2.875 17.02  0  1    4    4      8
3  22.8   4   108.0  93  3.85 2.320 18.61  1  1    4    1      8

但我想看看是否有办法避免在函数调用中引用数据框中使用的每个变量。

我也知道从函数调用中取出 mutate 是没有问题的。也就是说,mutate(mtcars,newvar=gear*2) 完成了这项工作。但是,我试图了解 dplyr 的 mutate 在放置在函数中时如何在不同环境中寻找有问题的变量。

【问题讨论】:

标签: r dplyr


【解决方案1】:

看看@Anandas 的解决方案,这似乎是最简单的 hack

multifun <- function(dataf, vari){   
dataf <- mutate(dataf, newvar = dataf[, vari]*2);   
return(dataf) 
}

multifun(mtcars,"gear")

再次考虑@Anandas 的建议,您也可以这样做

multifun <- function(dataf, vari){  
  vari <- deparse(substitute(vari))
  dataf <- mutate(dataf, newvar = dataf[, vari]*2)   
  return(dataf) 
}

multifun(mtcars, gear)

【讨论】:

  • 如果您想使用不带引号的值作为第二个参数的输入,还可以添加一行 vari &lt;- deparse(substitute(vari))。我不知道我是否会认为这是一个黑客行为。对我来说,它比我的更具可读性——我只是发布一个答案,看看它是否有助于我理解错误的 environment() 部分。
  • 这确实似乎是最简单的。如果不是只有一个变量,而是有很多变量,或者如果这些变量出现在复杂的代码中,那么似乎所有的解决方案都会导致冗长的代码。无论如何感谢所有的答案。
  • 看来,如果代码很复杂或者它涉及数据框中的许多变量,那么最不冗长的解决方案可能是在函数调用中指定变量的来源,如上所述,即@987654326 @,或者简单地“硬编码”函数定义中的齿轮变量,如this post
【解决方案2】:

这对我来说真的很难看,但似乎有效。基本上,我尝试使用get,但它似乎不知道在哪里看,所以我指定了环境。

multifun <- function(dataf, vari){
  vari <- deparse(substitute(vari))
  mutate(dataf, newvar = get(vari, envir = as.environment(dataf)) * 2)
}

输出:

multifun(mtcars, gear)
#                      mpg cyl  disp  hp drat    wt  qsec vs am gear carb newvar
# Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4      8
# Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4      8
# Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1      8
# <<<SNIP>>>
# Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6     10
# Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8     10
# Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2      8

【讨论】:

    【解决方案3】:

    或者

    multifun1 <- function(dataf, vari){
    eval(substitute(mutate(dataf, newvar=vari*2), list(vari=as.name(vari))))
    }
    
    multifun1(mtcars,"gear") 
    

    要使用unquoted 值,最好使用@Ananda Mahto 的建议

    multifun1 <- function(dataf, vari){
    vari <- deparse(substitute(vari))
    eval(substitute(mutate(dataf, newvar=vari*2), list(vari=as.name(vari))))
    }
    
    multifun1(mtcars,gear)
    

    【讨论】:

    • 是的。这也有效。请注意,在您的回答和我的帖子中,我都稍微编辑了代码,因为分配了 dataf
    • @罗伯特。感谢您的编辑。我注意到了,但忘记编辑了。
    【解决方案4】:

    使用dplyr 0.7.0,现在可以使用 tidyeval 来完成:

    multifun <- function(dataf,vari){
      mutate(dataf,newvar = UQ(enquo(vari))*2)
    }
    
    multifun(mtcars,gear)
    

    enquo 引用引用函数参数的符号并将其与调用函数的环境捆绑到一个quosure中。然后可以使用UQ!! 取消引用quosure 并立即在mutate 内对其进行评估。

    【讨论】:

      猜你喜欢
      • 2022-01-21
      • 2022-01-08
      • 1970-01-01
      • 2020-01-01
      • 2019-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      相关资源
      最近更新 更多