【问题标题】:R - tidyr - mutate and spread multiple columnsR - tidyr - 变异和传播多列
【发布时间】:2020-01-19 10:58:43
【问题描述】:

我在 R 中有以下数据框

my_df_test <- data.frame(V1 = c(1,2,1), V2 = c("A","B","A"), V3 = c("S1", "S1", "S2"), V4 = c("x","x","x"), V5 = c("y","y","y"), V6 = c("A", "B", "C"), V7 = c("D","E","F"))

my_df_test
  V1 V2 V3 V4 V5 V6 V7
1  1  A S1  x  y  A  D
2  2  B S1  x  y  B  E
3  1  A S2  x  y  C  F

现在我想检查 V1 和 V2 中的值组合是否在 df 中多次出现。在我的示例中,my_df 第 1 行和第 3 行具有相同的值“1 A”和“1 A”。如果发生这种情况,我想要以下输出:

> my_df_test

   V1 V2     V3 V4 V5  V6_S1   V6_S2   V7_S1   V7_S2
 1  1  A S1, S2  x  y      A       C       D       F
 2  2  B     S1  x  y      B      NA       E      NA

所以基本上有两件事发生了变化:

  • V3 现在包含 df 中所有行的值,其中 V1 和 V2 中的值相同。它们用','分隔
  • 新的 V6 和 V7 列包含这些列的原始值

其余列和值应保持不变。

当只有 1 个类似“V6”的列时,我的代码可以工作。但是,当有多个时,这将不再起作用。

my_df_test %>%
    group_by(V1, V2) %>%
    mutate(new = paste0("V6_", V3), V3 = toString(V3)) %>%
    spread(new, V6)

所以我的问题是我的代码应该如何适应变异和传播多个列?

【问题讨论】:

    标签: r tidyr


    【解决方案1】:

    您可以使用在最近的tidyr 1.0.0 release 中添加的新pivot_wider() 而不是spread()。它有一个values_from 参数,允许您一次指定多个列:

    library(dplyr)
    library(tidyr)
    
    my_df_test %>% 
      group_by(V1, V2) %>% 
      mutate(new = V3, V3 = toString(V3)) %>% 
      pivot_wider(
        names_from  = new,
        values_from = c(V6, V7)
      )
    #> # A tibble: 2 x 9
    #> # Groups:   V1, V2 [4]
    #>      V1 V2    V3     V4    V5    V6_S1 V6_S2 V7_S1 V7_S2
    #>   <dbl> <fct> <chr>  <fct> <fct> <fct> <fct> <fct> <fct>
    #> 1     1 A     S1, S2 x     y     A     C     D     F    
    #> 2     2 B     S1     x     y     B     <NA>  E     <NA>
    

    reprex package (v0.3.0) 于 2019 年 9 月 18 日创建

    【讨论】:

      【解决方案2】:

      gather 列在一起,更改key 值,然后更改spread

      library(dplyr)
      library(tidyr)
      
      my_df_test %>%
        gather(key, value, V6, V7) %>%
        mutate(key = paste(key, V3, sep = "_")) %>%
        group_by(V1, V2) %>%
        mutate(V3 = toString(unique(V3))) %>%
        spread(key, value)
      
      #     V1 V2    V3     V4    V5    V6_S1 V6_S2 V7_S1 V7_S2
      #  <dbl> <fct> <chr>  <fct> <fct> <chr> <chr> <chr> <chr>
      #1     1 A     S1, S2 x     y     A     C     D     F    
      #2     2 B     S1     x     y     B     NA    E     NA  
      

      【讨论】:

        【解决方案3】:

        另一个选项是在使用 pivot_wider 之后 unite V3 列。我首先将所有因子列转换为字符,因为 unite 不适用于因子。

        my_df_test %>% 
          mutate_if(is.factor, as.character) %>% 
          pivot_wider(names_from = 'V3', values_from = c(V3, V6:V7)) %>% 
          unite(V3, starts_with('V3'), sep = ', ', na.rm = TRUE)
        
        # # A tibble: 2 x 9
        #      V1 V2    V4    V5    V3     V6_S1 V6_S2 V7_S1 V7_S2
        #   <dbl> <chr> <chr> <chr> <chr>  <chr> <chr> <chr> <chr>
        # 1     1 A     x     y     S1, S2 A     C     D     F    
        # 2     2 B     x     y     S1     B     NA    E     NA  
        

        【讨论】: