【问题标题】:r User-Defined Function Arguments - what can be defined as the argument?r 用户定义的函数参数 - 什么可以定义为参数?
【发布时间】:2020-06-06 03:59:32
【问题描述】:

我正在尝试编写与 SAS 中的宏执行类似任务的 R 函数,例如

  1. 过程变量
  2. 命名一个新变量
  3. 命名一个新的数据框

我已经尝试了一些使用内置 df "iris" 和 dplyr 的基本功能,如下所示。

函数 f3 和 f4 尝试接收变量名并对其进行处理。错误消息是“错误:找不到对象'物种'”和“在 mean.default(var) 中:参数不是数字或逻辑:返回 NA”。

函数 f5 和 f6 尝试命名新变量或新 df。运行函数后,新变量或 df 以参数名称命名。

f7 尝试使用函数命名变量的一部分。

library(dplyr)

data(iris)
view(iris)

### Char Variable
f3 <- function(var){
      iris %>% filter(var == "setosa")
}
f3(Species)

f4 <- function(var){
      iris %>% summarise(
            avg = mean(var)
      )
}
f4("Sepal.Length")

### Variable Name
f5 <- function(name){
      iris %>% 
            mutate(name = 1)
}
f5("newname")

### df Name
f6 <- function(dfname){
      dfname <- iris 
}
f6("newdf")

f7 <- function(name){
      test <- iris %>% 
            mutate(
                  v_name = 1
            )
}
f7("1")

【问题讨论】:

  • 如果要在全局环境中分配新对象,请在 f6 中使用 assign(dfname, iris, envir = .GlobalEnv)

标签: r function dplyr arguments user-defined-functions


【解决方案1】:

使用tidyverse,如果我们不带引号传递,它可以转换为quosure(rlang::enquo)并评估(!!),这是使用{{}} curly-curly 运算符完成的

f3 <- function(var){
  iris %>%
       filter({{var}} == "setosa")
 }
f3(Species)
#    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#1           5.1         3.5          1.4         0.2  setosa
#2           4.9         3.0          1.4         0.2  setosa
#3           4.7         3.2          1.3         0.2  setosa
#4           4.6         3.1          1.5         0.2  setosa
#5           5.0         3.6          1.4         0.2  setosa
#...

f4 也可以用同样的方式来处理未引用的

f4 <- function(var){
  iris %>% 
      summarise(
        avg = mean({{var}})
      )
   }

f4(Sepal.Length)
#     avg
#1 5.843333

如果打算传递带引号或不带引号的,请使用 ensym 转换为符号并计算 (!!)

 f4 <- function(var){
  iris %>% 
    summarise(
        avg = mean(!! rlang::ensym(var))
   )
 }
 f4(Sepal.Length)
 #       avg
 #1 5.843333
 f4("Sepal.Length")
 #     avg
 #1 5.843333

对于f7,我们可以使用:=

library(stringr)
f7 <- function(name){
  iris %>% 
        mutate(
              !!str_c("v_", name) := 1
        )
 }

f7("1")
#      Sepal.Length Sepal.Width Petal.Length Petal.Width    Species v_1
#1            5.1         3.5          1.4         0.2     setosa   1
#2            4.9         3.0          1.4         0.2     setosa   1
#3            4.7         3.2          1.3         0.2     setosa   1
#4            4.6         3.1          1.5         0.2     setosa   1
#...

或者f5

f5 <- function(name){
  iris %>% 
        mutate(!! name := 1)
 }
f5("newname")
#     Sepal.Length Sepal.Width Petal.Length Petal.Width    Species newname
#1            5.1         3.5          1.4         0.2     setosa       1
#2            4.9         3.0          1.4         0.2     setosa       1
#3            4.7         3.2          1.3         0.2     setosa       1
#4            4.6         3.1          1.5         0.2     setosa       1
# ..

注意:如果我们将&lt;- 作为最后一个返回语句,则需要将其分配给一个对象或用() 包装以打印输出,即(f5("newname"))

f6assign 一个对象,这可以通过 assign 完成

f6 <- function(dfname){
   assign(dfname, value = iris, envir = .GlobalEnv) 
 }
f6("newdf")
head(newdf, 2)
#  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#1          5.1         3.5          1.4         0.2  setosa
#2          4.9         3.0          1.4         0.2  setosa

【讨论】:

  • 谢谢! f3 和 f4 完美运行!但是 curly-curly 运算符不适用于其余功能。