将数据框传递给函数中的mutate

10
我可以帮助您翻译以下内容,这是关于IT技术的内容。为了使用dplyr的mutate函数处理数据框和它的列,我需要编写一个函数。
以下是示例:
multifun <- function(dataf,vari){
 mutate(dataf,newvar=vari*2)
}

multifun(mtcars,gear)

这个函数的问题在于变量“gear”不是一个被识别的对象。更具体地说,我收到了以下错误信息:

Error in mutate_impl(.data, named_dots(...), environment()) object 'gear' not found

这是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如何在不同的环境中查找所需的变量。


看看这里提出的解决方案是否有所帮助:https://dev59.com/gmEh5IYBdhLWcg3w9nlj - konvas
4个回答

4

这对我来说看起来相当丑陋,但似乎是可行的。基本上,我尝试使用 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

4

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

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

multifun(mtcars,"gear")

再次考虑@Ananda的建议,你也可以这样做

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

multifun(mtcars, gear)

2
如果你想使用一个未引用的值作为第二个参数的输入,也可以添加一行vari <- deparse(substitute(vari))。我不知道我是否会认为这是一个hack。对我来说,它比我的更可读 - 我只是发布一个答案,看看它是否帮助我理解错误的environment()部分。 - A5C1D2H2I1M1N2O1R2T1
这似乎确实是最简单的解决方案。但是,如果我们有多个变量,或者这些变量出现在复杂的代码中,所有的解决方案似乎都会导致冗长的代码。无论如何,感谢所有的回答。 - Robert
看起来,如果代码很复杂或涉及数据框中的许多变量,则最简洁的解决方案可能是在函数调用中指定变量的来源,如上所示,即 multifun(mtcars,mtcars$gear),或者在函数定义中明确地“硬编码”齿轮变量,就像这篇文章中所述。 - Robert

3

使用 dplyr 0.7.0,现在可以通过tidyeval实现:

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

multifun(mtcars,gear)

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


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

2

或者

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

multifun1(mtcars,"gear") 

为了使用未加引号的值,最好使用@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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接