【问题标题】:repeated mutate in tidyverse在tidyverse中重复变异
【发布时间】:2018-07-14 10:35:09
【问题描述】:

考虑以下 tibble 和以下向量:

library(tidyverse)
a <- tibble(val1 = 10:15, val2 = 20:25)
params <- 1:3

我还有一个函数myfun,它接受一个任意长度的向量和一个整数作为输入,并返回一个相同长度的向量。出于演示目的,您可以考虑

myfun <- function(x, k) dplyr::lag(x, k)

我想创建以下内容:对于 a 中的每一列和 params 中的每个元素,我想创建一个由 myfun(col, params[i]) 给出的新列。 在上面的玩具示例中,例如可以这样实现:

a %>% mutate_at(1:2, funs(run1 = myfun), k = params[1]) %>% 
  mutate_at(1:2, funs(run2 = myfun), k = params[2]) %>% 
  mutate_at(1:2, funs(run3 = myfun), k = params[3]) 

有没有更优雅的方法来做到这一点?如果 params 很长,那么这个解决方案就变得不可行。当然可以使用 for 循环来做到这一点,但我认为在 tidyverse 中可能有一个解决方案(也许使用purrr::map?)

谢谢!

【问题讨论】:

    标签: r dplyr tidyverse


    【解决方案1】:

    这是一个使用 tidyverse 的解决方案:

    library(tidyverse)
    a <- tibble(val1 = 10:15, val2 = 20:25)
    params <- 1:3
    
    #set the column names, add leading zeroes based om max(params)
    run_names <- paste0("run", formatC(params, width = nchar(max(params)), flag = "0"))
    
    #what functions to perform
    lag_functions <- setNames(paste("dplyr::lag( ., ", params, ")"), run_names)
    #perfporm functions 
    a %>% mutate_at(vars(1:2), funs_(lag_functions ))
    
    # # A tibble: 6 x 8
    #    val1  val2 val1_run1 val2_run1 val1_run2 val2_run2 val1_run3 val2_run3
    #   <int> <int>     <int>     <int>     <int>     <int>     <int>     <int>
    # 1    10    20        NA        NA        NA        NA        NA        NA
    # 2    11    21        10        20        NA        NA        NA        NA
    # 3    12    22        11        21        10        20        NA        NA
    # 4    13    23        12        22        11        21        10        20
    # 5    14    24        13        23        12        22        11        21
    # 6    15    25        14        24        13        23        12        22
    

    【讨论】:

      【解决方案2】:

      data.table 中的重复滞后更容易做到,因为shift 可以采用ns 的向量

      library(data.table)
      # create a vector of new column names
      nm1 <- paste0(rep(names(a), each = length(params)),  '_run', params) 
      # get the `shift` of the Subset of Data.table (`.SD`)
      # by default type is "lag"
      # assign the output to the column names created earlier
      setDT(a)[, (nm1)  := shift(.SD, n = params)]    a
      #   val1 val2 val1_run1 val1_run2 val1_run3 val2_run1 val2_run2 val2_run3
      #1:   10   20        NA        NA        NA        NA        NA        NA
      #2:   11   21        10        NA        NA        20        NA        NA
      #3:   12   22        11        10        NA        21        20        NA
      #4:   13   23        12        11        10        22        21        20
      #5:   14   24        13        12        11        23        22        21
      #6:   15   25        14        13        12        24        23        22
      

      或者使用tidyverseparse_exprs

      library(tidyverse)
      library(rlang)
      # create a string with `rep` and `paste`
      nm2 <- glue::glue('lag({rep(names(a), each = length(params))}, n = {rep(params, length(a))})') %>% paste(., collapse=";")
      # convert string to expression with parse_exprs and evaluate (`!!!`)
      a %>% 
         mutate(!!! parse_exprs(nm2)) %>%
         rename_at(-(1:2), ~nm1)
      # A tibble: 6 x 8
      #   val1  val2 val1_run1 val1_run2 val1_run3 val2_run1 val2_run2 val2_run3
      #  <int> <int>     <int>     <int>     <int>     <int>     <int>     <int>
      #1    10    20        NA        NA        NA        NA        NA        NA
      #2    11    21        10        NA        NA        20        NA        NA
      #3    12    22        11        10        NA        21        20        NA
      #4    13    23        12        11        10        22        21        20
      #5    14    24        13        12        11        23        22        21
      #6    15    25        14        13        12        24        23        22
      

      【讨论】:

      • 感谢您的回答。然而,函数延迟仅用于演示目的。
      • @Cettt 好的,如果您需要一般情况,可以使用parse_exprs。即library(rlang);e2 = "vs + am ; am +vs"; mtcars %&gt;% mutate(!!!parse_exprs(e2))
      • @Cett 具体的例子用lage2 &lt;- "dplyr::lag(vs, 1); dplyr::lag(am, 1); dplyr::lag(vs, 2); dplyr::lag(am, 2)";mtcars %&gt;% mutate(!!! parse_exprs(e2))
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-22
      • 2022-10-14
      • 1970-01-01
      • 2018-12-08
      • 2020-01-27
      • 1970-01-01
      相关资源
      最近更新 更多