如何使用由外部变量命名的列使用 tidyverse mutate 减去两列

How to subtract two columns using tidyverse mutate with columns named by external variables

我想动态分配要相互减去的列。我看了一圈,看起来我需要使用 all_of,也许 across (, )。我可以让它对变异短语中的一个变量(例如 mutate(y = all_of(x)))起作用,但我似乎无法使用两个变量进行简单的计算。这是我想要做的事情的简化示例:

var1 <- c("Sepal.Length")
var2 <- c("Sepal.Width")

result <- iris %>%
  mutate(calculation = all_of(var1) - all_of(var2))

我们可以使用 .data 将列子集化为向量。 all_of/any_ofacross 一起使用以遍历列

library(dplyr)
iris %>%
  mutate(calculation = .data[[var1]] - .data[[var2]])%>%
  head

-输出

Sepal.Length Sepal.Width Petal.Length Petal.Width Species calculation
1          5.1         3.5          1.4         0.2  setosa         1.6
2          4.9         3.0          1.4         0.2  setosa         1.9
3          4.7         3.2          1.3         0.2  setosa         1.5
4          4.6         3.1          1.5         0.2  setosa         1.5
5          5.0         3.6          1.4         0.2  setosa         1.4
6          5.4         3.9          1.7         0.4  setosa         1.5

或者也可以使用cur_data()

iris %>%
    head %>%
    mutate(calculation = cur_data()[[var1]] - cur_data()[[var2]])

-输出

 Sepal.Length Sepal.Width Petal.Length Petal.Width Species calculation
1          5.1         3.5          1.4         0.2  setosa         1.6
2          4.9         3.0          1.4         0.2  setosa         1.9
3          4.7         3.2          1.3         0.2  setosa         1.5
4          4.6         3.1          1.5         0.2  setosa         1.5
5          5.0         3.6          1.4         0.2  setosa         1.4
6          5.4         3.9          1.7         0.4  setosa         1.5

或者另一种选择是传递 across 中的两个变量,然后传递 reduce-

library(purrr)
iris %>%
   head %>%
   mutate(calculation = reduce(across(all_of(c(var1, var2))), `-`))

-输出

Sepal.Length Sepal.Width Petal.Length Petal.Width Species calculation
1          5.1         3.5          1.4         0.2  setosa         1.6
2          4.9         3.0          1.4         0.2  setosa         1.9
3          4.7         3.2          1.3         0.2  setosa         1.5
4          4.6         3.1          1.5         0.2  setosa         1.5
5          5.0         3.6          1.4         0.2  setosa         1.4
6          5.4         3.9          1.7         0.4  setosa         1.5

或者可以转换为 symbol 并计算 (!!)

iris %>% 
   head %>% 
   mutate(calculation = !! rlang::sym(var1) - !! rlang::sym(var2))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species calculation
1          5.1         3.5          1.4         0.2  setosa         1.6
2          4.9         3.0          1.4         0.2  setosa         1.9
3          4.7         3.2          1.3         0.2  setosa         1.5
4          4.6         3.1          1.5         0.2  setosa         1.5
5          5.0         3.6          1.4         0.2  setosa         1.4
6          5.4         3.9          1.7         0.4  setosa         1.5

或者如果我们想在 across 中使用 all_of,只需将列子集设为 [[

iris %>% 
   head %>% 
   mutate(calculation = across(all_of(var1))[[1]] - 
                         across(all_of(var2))[[1]])
Sepal.Length Sepal.Width Petal.Length Petal.Width Species calculation
1          5.1         3.5          1.4         0.2  setosa         1.6
2          4.9         3.0          1.4         0.2  setosa         1.9
3          4.7         3.2          1.3         0.2  setosa         1.5
4          4.6         3.1          1.5         0.2  setosa         1.5
5          5.0         3.6          1.4         0.2  setosa         1.4
6          5.4         3.9          1.7         0.4  setosa         1.5

我们需要子集的原因是,默认情况下,across 将在 .names 不存在时更新原始列。 calculation 将是具有单列的 data.frame

out <- iris %>%
    head %>% 
    mutate(calculation = across(all_of(var1)) -
           across(all_of(var2)))
out
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length
1          5.1         3.5          1.4         0.2  setosa          1.6
2          4.9         3.0          1.4         0.2  setosa          1.9
3          4.7         3.2          1.3         0.2  setosa          1.5
4          4.6         3.1          1.5         0.2  setosa          1.5
5          5.0         3.6          1.4         0.2  setosa          1.4
6          5.4         3.9          1.7         0.4  setosa          1.5

str(out)
data.frame':    6 obs. of  6 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1
 $ calculation :'data.frame':   6 obs. of  1 variable:
  ..$ Sepal.Length: num  1.6 1.9 1.5 1.5 1.4 1.5

我们可以使用 get 访问变量名称存储在字符串中的变量值(感谢 akrun 的协助):

iris %>% 
    mutate(calculation = get(var1) - get(var2)) 
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species calculation
          <dbl>       <dbl>        <dbl>       <dbl> <fct>         <dbl>
 1          5.1         3.5          1.4         0.2 setosa          1.6
 2          4.9         3            1.4         0.2 setosa          1.9
 3          4.7         3.2          1.3         0.2 setosa          1.5
 4          4.6         3.1          1.5         0.2 setosa          1.5
 5          5           3.6          1.4         0.2 setosa          1.4
 6          5.4         3.9          1.7         0.4 setosa          1.5
 7          4.6         3.4          1.4         0.3 setosa          1.2
 8          5           3.4          1.5         0.2 setosa          1.6
 9          4.4         2.9          1.4         0.2 setosa          1.5
10          4.9         3.1          1.5         0.1 setosa          1.8
# ... with 140 more rows