【问题标题】:dplyr concat columns stored in variable (mutate and non standard evaluation)dplyr concat 列存储在变量中(变异和非标准评估)
【发布时间】:2017-06-18 08:48:10
【问题描述】:

我想根据变量cols_to_concat连接数据框中任意数量的列

df <- dplyr::data_frame(a = letters[1:3], b = letters[4:6], c = letters[7:9])
cols_to_concat = c("a", "b", "c")

要使用cols_to_concat 这个特定值达到预期结果,我可以这样做:

df %>% 
  dplyr::mutate(concat = paste0(a, b, c))

但我需要概括一下,使用有点像这样的语法

# (DOES NOT WORK)
df %>% 
  dplyr::mutate(concat = paste0(cols))

如果合适,我想使用 dplyr 0.7.0 的新 NSE approach,但无法找出正确的语法。

【问题讨论】:

    标签: r nse dplyr


    【解决方案1】:

    如果您想坚持这些包和原则,您可以只使用tidyverse 执行此操作。您可以使用来自tidyr 包的mutate()unite_() 来实现。

    使用mutate()

    library(dplyr)
    df <- tibble(a = letters[1:3], b = letters[4:6], c = letters[7:9])
    cols_to_concat <- c("a", "b", "c")
    
    df %>% mutate(new_col = do.call(paste0, .[cols_to_concat]))
    
    # A tibble: 3 × 4
          a     b     c new_col
      <chr> <chr> <chr>   <chr>
    1     a     d     g     adg
    2     b     e     h     beh
    3     c     f     i     cfi
    

    使用unite_()

    library(tidyr)
    df %>% unite_(col='new_col', cols_to_concat, sep="", remove=FALSE)
    
    # A tibble: 3 × 4
      new_col     a     b     c
    *   <chr> <chr> <chr> <chr>
    1     adg     a     d     g
    2     beh     b     e     h
    3     cfi     c     f     i
    

    2020 年 7 月编辑

    dplyr 1.0.0 开始,across()c_across() 似乎正在替换下划线动词(例如 unite_)和范围变体,例如 mutate_if()mutate_at()mutate_all()。下面是使用该约定的示例。不是最简洁的,但仍然是一个承诺更具可扩展性的选项。

    使用c_across()

    library(dplyr)
    
    df <- tibble(a = letters[1:3], b = letters[4:6], c = letters[7:9])
    cols_to_concat <- c("a", "b", "c")
    
    df %>% 
      rowwise() %>% 
      mutate(new_col = paste0(c_across(all_of(cols_to_concat)), collapse=""))
    #> # A tibble: 3 x 4
    #> # Rowwise: 
    #>   a     b     c     new_col
    #>   <chr> <chr> <chr> <chr>  
    #> 1 a     d     g     adg    
    #> 2 b     e     h     beh    
    #> 3 c     f     i     cfi
    

    reprex package (v0.3.0) 于 2020-07-08 创建

    【讨论】:

      【解决方案2】:

      你可以从rlang试试syms

      library(dplyr)
      packageVersion('dplyr')
      #[1] ‘0.7.0’
      df <- dplyr::data_frame(a = letters[1:3], b = letters[4:6], c = letters[7:9])
      cols_to_concat = c("a", "b", "c")
      
      library(rlang)
      cols_quo <- syms(cols_to_concat)
      df %>% mutate(concat = paste0(!!!cols_quo))
      
      # or
      df %>% mutate(concat = paste0(!!!syms(cols_to_concat)))
      
      # # A tibble: 3 x 4
      #       a     b     c concat
      #   <chr> <chr> <chr>  <chr>
      # 1     a     d     g    adg
      # 2     b     e     h    beh
      # 3     c     f     i    cfi
      

      【讨论】:

        【解决方案3】:

        您可以执行以下操作:

        library(dplyr)
        
        df <- dplyr::data_frame(a = letters[1:3], b = letters[4:6], c = letters[7:9])
        
        cols_to_concat = lapply(list("a", "b", "c"), as.name)
        
        q <- quos(paste0(!!! cols_to_concat))
        
        df %>% 
          dplyr::mutate(concat = !!! q)
        

        【讨论】:

        • 经过进一步的实验,上面的代码可以工作——虽然我必须承认,我不确定我是否完全理解它。如果有更好的方法,请添加另一个答案,我会接受...
        • 是的,有很多简单的方法可以实现这一点,例如df$concat &lt;- do.call(paste0, df[cols_to_concat]),但不幸的是,现在所有的事情都必须通过该死的 dplyr 来实现,所以祝你在那里的任务好运。
        • 谢谢 - 我确实尝试过 do.call,但无法弄清楚。我没有意识到你可以给它一个 df,但仔细想想,很明显,因为 df 只是一个列表。这显然是比 tidyverse 答案更好的解决方案。
        • tidyverse 提供了一个方便的粘贴功能,称为unite(),但也可以在mutate 中使用do.callpaste0。我已经提供了这两种解决方案作为答案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-12
        • 2017-10-27
        • 2015-03-10
        • 1970-01-01
        • 1970-01-01
        • 2020-09-17
        相关资源
        最近更新 更多