【问题标题】:Concatenate column names in one column conditional on using mutate, across and case_when以使用 mutate、cross 和 case_when 为条件将列名连接在一列中
【发布时间】:2021-08-17 23:22:50
【问题描述】:

我想:

  1. 使用acrosscase_when 检查A1-A3 列是否== 1
  2. 连接 A1-A3 == 1 和的列的列名
  3. 用串联的列名改变一个新列

我的数据框:

df <- tribble(
~ID,    ~A1,    ~A2,    ~A3,
1, 0, 1, 1, 
2, 0, 1, 1, 
3, 1, 1, 1, 
4, 1, 0, 1, 
5, 0, 1, 0)

期望的输出:

# A tibble: 5 x 5
     ID    A1    A2    A3 New_Col 
  <dbl> <dbl> <dbl> <dbl> <chr>   
1     1     0     1     1 A2 A3   
2     2     0     1     1 A2 A3   
3     3     1     1     1 A1 A2 A3
4     4     1     0     1 A1 A3   
5     5     0     1     0 A2   

到目前为止我已经尝试过:

df %>% 
  rowwise() %>% 
  mutate(New_Col = across(A1:A3, ~ case_when(. == 1 ~ paste0("colnames(.)", collapse = " "))))

不工作输出:

     ID    A1    A2    A3 New_Col$A1  $A2         $A3        
  <dbl> <dbl> <dbl> <dbl> <chr>       <chr>       <chr>      
1     1     0     1     1 NA          colnames(.) colnames(.)
2     2     0     1     1 NA          colnames(.) colnames(.)
3     3     1     1     1 colnames(.) colnames(.) colnames(.)
4     4     1     0     1 colnames(.) NA          colnames(.)
5     5     0     1     0 NA          colnames(.) NA   

我想学什么:

  1. 是否可以使用across 跨多个列检查条件
  2. 如果是,case_when 的 ~ 之后的部分如何获取特定的列名
  3. 在使用mutateacrosscase_when 而不是像这里那样的 3 之后,我怎样才能只得到一列。

我以为我已经能够掌握这项任务,但不知怎的,我失去了它......

【问题讨论】:

    标签: r dplyr across


    【解决方案1】:

    要将acrosscase_when 一起使用,您可以这样做 -

    library(dplyr)
    library(tidyr)
    
    df %>% 
      mutate(across(A1:A3, ~case_when(. == 1 ~ cur_column()), .names = 'new_{col}')) %>%
      unite(New_Col, starts_with('new'), na.rm = TRUE, sep = ' ')
    
    #    ID    A1    A2    A3 New_Col 
    #  <dbl> <dbl> <dbl> <dbl> <chr>   
    #1     1     0     1     1 A2 A3   
    #2     2     0     1     1 A2 A3   
    #3     3     1     1     1 A1 A2 A3
    #4     4     1     0     1 A1 A3   
    #5     5     0     1     0 A2      
    

    across 创建 3 个名为 new_A1new_A2new_A3 的新列,如果值为 1,则使用列名,否则为 NA。使用unite,我们将三列合并为一列New_col


    我们也可以使用rowwisec_across -

    df %>% 
      rowwise() %>% 
      mutate(New_Col = paste0(names(.[-1])[c_across(A1:A3) == 1], collapse = ' '))
    

    【讨论】:

    • Ronak,我们可以在这里直接使用 cur_column 来代替 names() 吗?
    • 您的意思是rowwisegroup_by ID 对吗?我认为我们不能这样做,因为 cur_column 只能在 across 中使用。
    • 是的,它只返回这个错误。感谢您的解释:)
    【解决方案2】:

    没有rowwise/across,你也可以使用cur_data()获得相同的结果

    df %>% group_by(ID) %>%
      mutate(new_col = paste0(names(df[-1])[as.logical(cur_data())], collapse = ' '))
    
    # A tibble: 5 x 5
    # Groups:   ID [5]
         ID    A1    A2    A3 new_col 
      <dbl> <dbl> <dbl> <dbl> <chr>   
    1     1     0     1     1 A2 A3   
    2     2     0     1     1 A2 A3   
    3     3     1     1     1 A1 A2 A3
    4     4     1     0     1 A1 A3   
    5     5     0     1     0 A2 
    

    a . 代替 df 内部 mutate 也可以

    df %>% group_by(ID) %>%
      mutate(new_col = paste0(names(.[-1])[as.logical(cur_data())], collapse = ' '))
    

    【讨论】:

    • Awesome Anil ji and Ronak,有一个问题,这里cur_data是每个组,即使每个组超过1行也可以吗?因为我尝试了as.logical(df[-1]) 并期待TRUEFALSE 的DF,但得到了这个错误:Error: 'list' object cannot be coerced to type 'logical'。还有cur_datacur_group有什么区别
    • 嗨@KarthikS,你可以叫我Anil,看一些解释herecur_data 返回当前数据(当然是分组的),cur_group 代表分组键。所以cur_data 将在这里返回二进制值,cur_group 将返回 id。希望这很清楚
    【解决方案3】:

    使用base R

    df$New_Col <- apply(df[-1], 1, \(x) paste(names(x)[as.logical(x)], collapse=' '))
    df$New_Col
    #[1] "A2 A3"    "A2 A3"    "A1 A2 A3" "A1 A3"    "A2"  
    

    或使用tidyverse

    library(dplyr)
    library(purrr)
    library(stringr)
    df %>%
       mutate(New_Col = across(A1:A3, ~ c('', cur_column())[. + 1] ) %>% 
                           invoke(str_c, .))
    

    【讨论】:

      【解决方案4】:

      还涉及purrr 的一个选项可能是:

      df %>%
       mutate(New_Col = pmap_chr(across(-ID), 
                                 ~ paste(names(c(...))[which(c(...) == 1)], collapse = " ")))
      
           ID    A1    A2    A3 New_Col 
        <dbl> <dbl> <dbl> <dbl> <chr>   
      1     1     0     1     1 A2 A3   
      2     2     0     1     1 A2 A3   
      3     3     1     1     1 A1 A2 A3
      4     4     1     0     1 A1 A3   
      5     5     0     1     0 A2 
      

      【讨论】:

        猜你喜欢
        • 2023-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-16
        • 2021-04-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多