r语言 - 在函数中将列名作为变量传递的最佳整洁实践

  • 本文关键字:变量 最佳 r语言 函数 r tidyeval
  • 更新时间 :
  • 英文 :


我将一个标题传递给用户定义的函数,其中列名是变量。在研究了这个,这个,还有这个之后,我得到了下面这个函数。我的目标是在R包中包含一个等价的函数。我的问题是,虽然这个函数有效,但在dplyr/tidyval/tidyverse世界中是否有更正确的最佳实践?

library(tidyverse)
dat0 <- tibble( a = seq(as.Date('2022-02-10'), as.Date('2022-03-01'), by = "5 days")
, b = seq(10,40,10))
myCalc <- function(data, dateIn, numIn, yearOut, numOut) {
data <- data %>%
mutate(.
, {{yearOut}} := lubridate::year(.data[[dateIn]])
, {{numOut}} := 10 * .data[[numIn]]
) %>%
filter(.
, .data[[numOut]] > 250
)
}
dat2 <- myCalc(dat0
, dateIn  = "a"
, numIn   = "b"
, yearOut = "c"
, numOut  = "d")
dat2
# A tibble: 2 × 4
a              b     c     d
<date>     <dbl> <dbl> <dbl>
1 2022-02-20    30  2022   300
2 2022-02-25    40  2022   400

既然您已经使用了花括号{{运算符,那么您可以在函数中进一步实现带引号的参数:

myCalc <- function(data, dateIn, numIn, yearOut, numOut) {
data <- data %>%
mutate(.
, {{yearOut}} := lubridate::year({{ dateIn }})
, {{numOut}} := 10 * {{ numIn }}
) %>%
filter(.
, {{ numOut }} > 250
)

return(data)
}

你对字符串的使用确实有效(例如.data[[dateIn]],在你的例子中计算为.data[["a"]])。正如@r2evans在评论中提到的,差异真正出现在函数调用期间。

这个函数可以这样调用(注意参数中没有引号):

dat2 <- myCalc(dat0, 
dateIn  = a,
numIn   = b,
yearOut = c,
numOut  = d)

您可以阅读更多关于?rlang::`nse-defuse`?rlang::`nse-force`的内容。还有一篇关于这个主题的文章。