如何引用一个在函数中创建的列,并使用walrus操作符:=

uqjltbpv  于 2023-02-17  发布在  其他
关注(0)|答案(3)|浏览(105)

我正在尝试创建一个函数,我想引用之前在函数中使用{{}}和:=创建的列。如何引用“{{col}}_d”列?

library(tidyverse)

data <- tibble(
    a = seq(1,10),
    b = sample(c("a", "b", "c"), 10, replace = T),
    c = rnorm(10, 100, 10)
    )

data_func <- function(df, col) {
    df %>% 
        group_by({{col}}) %>% 
        mutate(
            "{{col}}_d" := a * c,
            "{{col}}_e" := "{{col}}_d" * 10
        )
}

data %>% 
    data_func(b)
#> Error in `mutate()`:
#> ℹ In argument: `b_e = "{{col}}_d" * 10`.
#> ℹ In group 1: `b = "a"`.
#> Caused by error in `"{{col}}_d" * 10`:
#> ! non-numeric argument to binary operator

#> Backtrace:
#>      ▆
#>   1. ├─data %>% data_func(b)
#>   2. ├─global data_func(., b)
#>   3. │ └─... %>% ...
#>   4. ├─dplyr::mutate(...)
#>   5. ├─dplyr:::mutate.data.frame(...)
#>   6. │ └─dplyr:::mutate_cols(.data, dplyr_quosures(...), by)
#>   7. │   ├─base::withCallingHandlers(...)
#>   8. │   └─dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
#>   9. │     └─mask$eval_all_mutate(quo)
#>  10. │       └─dplyr (local) eval()
#>  11. └─base::.handleSimpleError(...)
#>  12.   └─dplyr (local) h(simpleError(msg, call))
#>  13.     └─rlang::abort(message, class = error_class, parent = parent, call = error_call)

创建于2023年2月12日,使用reprex v2.0.2
我希望先前创建的列将用于添加的下一个新列。

ghhaqwfi

ghhaqwfi1#

下面是引用动态列的一种方法:

library(tidyverse)
library(rlang)

data <- tibble(
  a = seq(1,10),
  b = sample(c("a", "b", "c"), 10, replace = T),
  c = rnorm(10, 100, 10)
)

data_func <- function(df, col) {
  col_nm <- rlang::englue("{{ col }}_d") 
  
  df %>%
    group_by({{ col }}) %>%
    mutate("{{ col }}_d" := a * c,
           "{{ col }}_e" := !! sym(col_nm) * 10
           )
    
}

data %>% 
  data_func(b)
#> # A tibble: 10 × 5
#> # Groups:   b [3]
#>        a b         c    b_d    b_e
#>    <int> <chr> <dbl>  <dbl>  <dbl>
#>  1     1 b      75.6   75.6   756.
#>  2     2 a     104.   208.   2082.
#>  3     3 b     113.   340.   3398.
#>  4     4 a      92.3  369.   3690.
#>  5     5 a      92.7  464.   4637.
#>  6     6 c      99.1  594.   5944.
#>  7     7 a      96.1  673.   6725.
#>  8     8 a     107.   854.   8536.
#>  9     9 b      95.4  859.   8589.
#> 10    10 a     106.  1061.  10608.

另一种方法是使用.data

data_func <- function(df, col) {
  col_nm <- rlang::englue("{{ col }}_d") 
  
  df %>%
    group_by({{ col }}) %>%
    mutate("{{ col }}_d" := a * c,
           "{{ col }}_e" := .data[[col_nm]] * 10
           )
    
}

创建于2023年2月13日,使用reprex v2.0.2

wi3ka0sx

wi3ka0sx2#

请使用!!sym沿着substitute尝试以下代码

data_func <- function(df, col) {
col <- deparse(substitute(col))
 col2 <- paste0(col,'_d') 
 col3 <- paste0(col,'_e') 
 
  df %>% 
    group_by(!!sym(col)) %>% 
    mutate(
      !!sym(col2) := a * c,
      !!sym(col3) :=  !!sym(col2) * 10
    )
}

data %>% data_func(b)

创建于2023年2月12日,使用reprex v2.0.2

# A tibble: 10 × 5
# Groups:   b [3]
       a b         c    b_d    b_e
   <int> <chr> <dbl>  <dbl>  <dbl>
 1     1 c      99.3   99.3   993.
 2     2 b      89.6  179.   1793.
 3     3 a     122.   365.   3648.
 4     4 c     105.   419.   4193.
 5     5 b      96.4  482.   4822.
 6     6 b      84.2  505.   5051.
 7     7 c     125.   875.   8755.
 8     8 a     113.   906.   9055.
 9     9 a     111.   999.   9987.
10    10 a     105.  1048.  10483.
qco9c6ql

qco9c6ql3#

我们建议使用englue()创建字符串,然后将其与.data一起使用,以从当前组切片中创建列的子集:

data |>
  mutate(
    "{{col}}_d" := a * c,
    "{{col}}_e" := .data[[englue("{{col}}_d")]] * 10
  )

或等同于:

col_d <- englue("{{col}}_d")

# Note the normal `{` glue interpolation on the first LHS:
data |>
  mutate(
    "{col_d}" := a * c,
    "{{col}}_e" := .data[[col_d]] * 10
  )

参见https://rlang.r-lib.org/reference/englue.html

相关问题