【问题标题】:Mutate multiple variable to create multiple new variables变异多个变量以创建多个新变量
【发布时间】:2018-07-31 13:47:05
【问题描述】:

假设我有一个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】:

    因为您正在对列名进行操作,所以您需要使用 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()将被弃用(source1 & source2),需要改用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
    

    编辑 2dplyr 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
    

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

    【讨论】:

    猜你喜欢
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 2020-07-05
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    相关资源
    最近更新 更多