我应该使用哪个rlang函数评估胶字符串作为变量名称?

发布于 2025-02-11 05:24:27 字数 899 浏览 0 评论 0 原文

假设我想创建一个函数,要在 dplyr :: mutate()中,并且在其中添加一个变量名称,并且在该函数中,它将在变量名称中提取特定模式给定并创建一个新的变量名称,就像是这样的:

library(rlang)
library(dplyr)
library(stringr)
library(glue)

myfun <- function(var) {
  y <- str_remove(ensym(var), "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  if_else(var > 6 | other_var > 3, 1, 0) # What rlang function do I need to apply to other_var here?
}

我遇到的问题是如何使用rlang工具在数据框架内评估新的变量名称“ ether_var”,以便当我进行调用时下面,它将查看 iris $ sepal.length iris $ petal.length 中的数据?

mutate(iris, test = myfun(Sepal.Length))

编辑:下面解决了我的直接问题,但我觉得有一种更优雅的方法:

myfun <- function(df, x) {
  y <- str_remove(ensym(x), "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  if_else(x > 6 | df[[other_var]] > 3, 0, 1) 
}

mutate(iris, test = myfun(iris, Sepal.Length))

Suppose that I want to create a function to be used within dplyr::mutate(), and in which I feed a variable name, and within the function, it will extract a particular pattern in the variable name given and create a new variable name out of it, like so:

library(rlang)
library(dplyr)
library(stringr)
library(glue)

myfun <- function(var) {
  y <- str_remove(ensym(var), "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  if_else(var > 6 | other_var > 3, 1, 0) # What rlang function do I need to apply to other_var here?
}

The problem I'm running into, is how do I use rlang tools to evaluate the new variable name "other_var" within the data frame, such that when I make the call below, it would look at the data within iris$Sepal.Length and iris$Petal.Length?

mutate(iris, test = myfun(Sepal.Length))

EDIT: The following solves my immediate problem, but I feel like there's a more elegant way:

myfun <- function(df, x) {
  y <- str_remove(ensym(x), "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  if_else(x > 6 | df[[other_var]] > 3, 0, 1) 
}

mutate(iris, test = myfun(iris, Sepal.Length))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

送舟行 2025-02-18 05:24:27

您可以使用环境并调用 eval_tidy()

这使用 caller_env(n = 1)

myfun <- function(var) {
  
  .var <- enexpr(var)
  var_name <- as_name(.var)
  
  y <- str_remove(var_name, "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  .expr <- parse_expr(glue("if_else({var_name} > 6 | {other_var} > 3, 1, 0)"))

  eval_tidy(.expr, env = caller_env(n = 1))
}

这将抓取 var 作为quosuse并使用该环境,如果您从原始突变呼叫中嵌套了函数,这可能很有用。

myfun <- function(var) {
  
  .var <- enquo(var)
  var_name <- as_name(.var)
  
  y <- str_remove(var_name, "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  .expr <- parse_expr(glue("if_else({var_name} > 6 | {other_var} > 3, 1, 0)"))
  .quo <- new_quosure(.expr, quo_get_env(.var))
  
  eval_tidy(.quo)
}

You can use the environment and call eval_tidy().

This uses caller_env(n = 1):

myfun <- function(var) {
  
  .var <- enexpr(var)
  var_name <- as_name(.var)
  
  y <- str_remove(var_name, "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  .expr <- parse_expr(glue("if_else({var_name} > 6 | {other_var} > 3, 1, 0)"))

  eval_tidy(.expr, env = caller_env(n = 1))
}

This grabs the var as a quosure and uses that environment, which could be useful if you had nested functions down from the original mutate call.

myfun <- function(var) {
  
  .var <- enquo(var)
  var_name <- as_name(.var)
  
  y <- str_remove(var_name, "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  .expr <- parse_expr(glue("if_else({var_name} > 6 | {other_var} > 3, 1, 0)"))
  .quo <- new_quosure(.expr, quo_get_env(.var))
  
  eval_tidy(.quo)
}
蹲墙角沉默 2025-02-18 05:24:27

获取数据

library(dplyr)
library(rlang)
library(stringr)
myfun <- function(var) {
  dat <- cur_data_all()
  y <- as_string(ensym(var))
  other_var <- str_c("Petal.", str_remove(y, '^.*\\.'))
  +(!((dat[[y]] > 6)|(dat[[other_var]] > 3)))
 
  }

我们可以使用 CUR_DATA_ALL() -testing

> head(mutate(iris, test = myfun(Sepal.Length)))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species test
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
5          5.0         3.6          1.4         0.2  setosa    1
6          5.4         3.9          1.7         0.4  setosa    1

We could get the data with cur_data_all()

library(dplyr)
library(rlang)
library(stringr)
myfun <- function(var) {
  dat <- cur_data_all()
  y <- as_string(ensym(var))
  other_var <- str_c("Petal.", str_remove(y, '^.*\\.'))
  +(!((dat[[y]] > 6)|(dat[[other_var]] > 3)))
 
  }

-testing

> head(mutate(iris, test = myfun(Sepal.Length)))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species test
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
5          5.0         3.6          1.4         0.2  setosa    1
6          5.4         3.9          1.7         0.4  setosa    1
離殇 2025-02-18 05:24:27

您可以使用 rlang :: Caller_env (或 parent.frame.frame.frame )从其呼叫环境中获取变量,以避免 rlang 依赖关系(如果需要))和获取 IT。从那里您只需使用新变量运行所需的代码:

myfun <- function(x) {
  y <- paste0("Petal.", stringr::str_remove(substitute(x), "^.*\\."))
  other_var <- get(y, rlang::caller_env())
  dplyr::if_else(x > 6 | other_var > 3, 0, 1)
}

tibble::tibble(dplyr::mutate(iris, test = myfun(Sepal.Length)))
#> # A tibble: 150 x 6
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species  test
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
#>  1          5.1         3.5          1.4         0.2 setosa      1
#>  2          4.9         3            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
#>  5          5           3.6          1.4         0.2 setosa      1
#>  6          5.4         3.9          1.7         0.4 setosa      1
#>  7          4.6         3.4          1.4         0.3 setosa      1
#>  8          5           3.4          1.5         0.2 setosa      1
#>  9          4.4         2.9          1.4         0.2 setosa      1
#> 10          4.9         3.1          1.5         0.1 setosa      1
#> # ... with 140 more rows

在2022-06-28上由(v2.0.1)

更新更多 rlang 面向方案:

myfun <- function(x) {
  var_in <- rlang::enexpr(x)
  other_var <- rlang::sym(paste0("Petal.", stringr::str_remove(var_in, "^.*\\.")))
  rlang::eval_tidy(rlang::quo(dplyr::if_else(!!var_in > 6 | !!other_var > 3, 0, 1)), rlang::caller_env())
}
tibble::tibble(dplyr::mutate(iris, test = myfun(Sepal.Length)))
#> # A tibble: 150 x 6
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species  test
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
#>  1          5.1         3.5          1.4         0.2 setosa      1
#>  2          4.9         3            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
#>  5          5           3.6          1.4         0.2 setosa      1
#>  6          5.4         3.9          1.7         0.4 setosa      1
#>  7          4.6         3.4          1.4         0.3 setosa      1
#>  8          5           3.4          1.5         0.2 setosa      1
#>  9          4.4         2.9          1.4         0.2 setosa      1
#> 10          4.9         3.1          1.5         0.1 setosa      1
#> # ... with 140 more rows

在2022-06-29上创建的

You can fetch the variable from its call environment with rlang::caller_env (or parent.frame to avoid rlang dependency if that is desired) and get it. From there you just run the code you want with the new variable:

myfun <- function(x) {
  y <- paste0("Petal.", stringr::str_remove(substitute(x), "^.*\\."))
  other_var <- get(y, rlang::caller_env())
  dplyr::if_else(x > 6 | other_var > 3, 0, 1)
}

tibble::tibble(dplyr::mutate(iris, test = myfun(Sepal.Length)))
#> # A tibble: 150 x 6
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species  test
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
#>  1          5.1         3.5          1.4         0.2 setosa      1
#>  2          4.9         3            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
#>  5          5           3.6          1.4         0.2 setosa      1
#>  6          5.4         3.9          1.7         0.4 setosa      1
#>  7          4.6         3.4          1.4         0.3 setosa      1
#>  8          5           3.4          1.5         0.2 setosa      1
#>  9          4.4         2.9          1.4         0.2 setosa      1
#> 10          4.9         3.1          1.5         0.1 setosa      1
#> # ... with 140 more rows

Created on 2022-06-28 by the reprex package (v2.0.1)

Update more rlang oriented solution:

myfun <- function(x) {
  var_in <- rlang::enexpr(x)
  other_var <- rlang::sym(paste0("Petal.", stringr::str_remove(var_in, "^.*\\.")))
  rlang::eval_tidy(rlang::quo(dplyr::if_else(!!var_in > 6 | !!other_var > 3, 0, 1)), rlang::caller_env())
}
tibble::tibble(dplyr::mutate(iris, test = myfun(Sepal.Length)))
#> # A tibble: 150 x 6
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species  test
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
#>  1          5.1         3.5          1.4         0.2 setosa      1
#>  2          4.9         3            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
#>  5          5           3.6          1.4         0.2 setosa      1
#>  6          5.4         3.9          1.7         0.4 setosa      1
#>  7          4.6         3.4          1.4         0.3 setosa      1
#>  8          5           3.4          1.5         0.2 setosa      1
#>  9          4.4         2.9          1.4         0.2 setosa      1
#> 10          4.9         3.1          1.5         0.1 setosa      1
#> # ... with 140 more rows

Created on 2022-06-29 by the reprex package (v2.0.1)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文