改变多个变量以创建多个新变量

问题描述 投票:0回答:1

假设我有一个

tibble
,我需要在其中获取多个变量并将它们转变为新的多个新变量。

作为示例,这是一个简单的小标题:

tb <- tribble(
  ~x, ~y1, ~y2, ~y3, ~z,
  1,2,4,6,2,
  2,1,2,3,3,
  3,6,4,2,1
)

我想从名称以“y”开头的每个变量中减去变量 z,并将结果变异为 tb 的新变量。另外,假设我不知道我有多少个“y”变量。我希望该解决方案能够很好地适应

tidyverse
/
dplyr
工作流程。

本质上,我不明白如何将多个变量变异为多个新变量。我不确定在这种情况下您是否可以使用

mutate
?我已经尝试过
mutate_if
,但我认为我没有正确使用它(并且我收到错误):

tb %>% mutate_if(starts_with("y"), funs(.-z))

#Error: No tidyselect variables were registered

提前致谢!

r dplyr tidyverse tidyselect
1个回答
31
投票

更新

dplyr
1.0.0+
across()
功能,进一步简化了此任务

基本用法

across()
有两个主要论点:

  • 第一个参数
    .cols
    选择要操作的列。 它使用整洁的选择(如
    select()
    ),因此您可以通过以下方式选择变量 位置、名称和类型。
  • 第二个参数
    .fns
    是要应用于的函数或函数列表 每列。这也可以是 purrr 风格的公式(或公式列表) 就像
    ~ .x / 2
    。 (这个参数是可选的,如果你只想 获取底层数据;你会看到该技术用于
    vignette("rowwise")
    。)
# Control how the names are created with the `.names` argument which 
# takes a [glue](http://glue.tidyverse.org/) spec:
tb %>% 
  mutate(
    across(starts_with("y"), ~ .x - z, .names = "mod_{col}")
  )
#> # A tibble: 3 x 8
#>       x    y1    y2    y3     z mod_y1 mod_y2 mod_y3
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2      0      2      4
#> 2     2     1     2     3     3     -2     -1      0
#> 3     3     6     4     2     1      5      3      1

tb %>% 
  mutate(
    across(num_range(prefix = "y", range = 1:3), ~ .x - z, .names = "mod_{col}")
  )
#> # A tibble: 3 x 8
#>       x    y1    y2    y3     z mod_y1 mod_y2 mod_y3
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2      0      2      4
#> 2     2     1     2     3     3     -2     -1      0
#> 3     3     6     4     2     1      5      3      1

### Multiple functions
tb %>% 
  mutate(
    across(c(matches("x"), contains("z")), ~ max(.x, na.rm = TRUE), .names = "max_{col}"),
    across(c(y1:y3), ~ .x - z, .names = "mod_{col}")
  )
#> # A tibble: 3 x 10
#>       x    y1    y2    y3     z max_x max_z mod_y1 mod_y2 mod_y3
#>   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2     3     3      0      2      4
#> 2     2     1     2     3     3     3     3     -2     -1      0
#> 3     3     6     4     2     1     3     3      5      3      1

被取代的方法

因为您正在对列名称进行操作,所以需要使用

mutate_at
而不是
mutate_if
,后者使用列中的值

tb %>% mutate_at(vars(starts_with("y")), funs(. - z))
#> # A tibble: 3 x 5
#>       x    y1    y2    y3     z
#>   <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1     1     0     2     4     2
#> 2     2    -2    -1     0     3
#> 3     3     5     3     1     1

要创建新列,我们可以为

funs

命名,而不是覆盖现有列
# add suffix
tb %>% mutate_at(vars(starts_with("y")), funs(mod = . - z))
#> # A tibble: 3 x 8
#>       x    y1    y2    y3     z y1_mod y2_mod y3_mod
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2      0      2      4
#> 2     2     1     2     3     3     -2     -1      0
#> 3     3     6     4     2     1      5      3      1

# remove suffix, add prefix
tb %>%
  mutate_at(vars(starts_with("y")),  funs(mod = . - z)) %>%
  rename_at(vars(ends_with("_mod")), funs(paste("mod", gsub("_mod", "", .), sep = "_")))
#> # A tibble: 3 x 8
#>       x    y1    y2    y3     z mod_y1 mod_y2 mod_y3
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2      0      2      4
#> 2     2     1     2     3     3     -2     -1      0
#> 3     3     6     4     2     1      5      3      1

编辑:在

dplyr 0.8.0
或更高版本中,
funs()
将被弃用(source1source2),需要使用
list()
代替

tb %>% mutate_at(vars(starts_with("y")), list(~ . - z))
#> # A tibble: 3 x 5
#>       x    y1    y2    y3     z
#>   <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1     1     0     2     4     2
#> 2     2    -2    -1     0     3
#> 3     3     5     3     1     1

tb %>% mutate_at(vars(starts_with("y")), list(mod = ~ . - z))
#> # A tibble: 3 x 8
#>       x    y1    y2    y3     z y1_mod y2_mod y3_mod
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2      0      2      4
#> 2     2     1     2     3     3     -2     -1      0
#> 3     3     6     4     2     1      5      3      1

tb %>%
  mutate_at(vars(starts_with("y")),  list(mod = ~ . - z)) %>%
  rename_at(vars(ends_with("_mod")), list(~ paste("mod", gsub("_mod", "", .), sep = "_")))
#> # A tibble: 3 x 8
#>       x    y1    y2    y3     z mod_y1 mod_y2 mod_y3
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>
#> 1     1     2     4     6     2      0      2      4
#> 2     2     1     2     3     3     -2     -1      0
#> 3     3     6     4     2     1      5      3      1

reprex 包于 2018 年 10 月 29 日创建(v0.2.1)

© www.soinside.com 2019 - 2024. All rights reserved.