【问题标题】:Match comments to value with dplyr gather使用 dplyr 将评论与值匹配
【发布时间】:2019-08-08 16:11:38
【问题描述】:

我有一些样品已经过各种不同水质参数的测试。每个参数都有两列:一个值和关于该值的注释。我想将参数收集成长格式,但我想将关于它们的 cmets 保存在不同的列中。我尝试使用两个收集语句,但这并不能保留值和注释列之间的关系。

我知道评论栏总是紧挨着价值栏的右侧,但我不知道如何利用这一点。

library(tidyverse)
#> Warning: package 'tidyverse' was built under R version 3.5.2
#> Warning: package 'ggplot2' was built under R version 3.5.3
#> Warning: package 'tibble' was built under R version 3.5.2
#> Warning: package 'tidyr' was built under R version 3.5.3
#> Warning: package 'readr' was built under R version 3.5.3
#> Warning: package 'purrr' was built under R version 3.5.3
#> Warning: package 'dplyr' was built under R version 3.5.3
#> Warning: package 'stringr' was built under R version 3.5.2
#> Warning: package 'forcats' was built under R version 3.5.2
my_df <- tibble(time_taken = 1:4, a = seq(2, 8, by = 2), a_comment = rep("Comment about A!", 4), b = seq(-8, -2, by = 2), b_comment = rep("Comment about B?", 4))
my_df
#> # A tibble: 4 x 5
#>   time_taken     a a_comment            b b_comment       
#>        <int> <dbl> <chr>            <dbl> <chr>           
#> 1          1     2 Comment about A!    -8 Comment about B?
#> 2          2     4 Comment about A!    -6 Comment about B?
#> 3          3     6 Comment about A!    -4 Comment about B?
#> 4          4     8 Comment about A!    -2 Comment about B?

my_attempt <- my_df %>% 
  gather(key = "key", value = "value", a, b) %>%
  gather(key = "comment_key", value = "comment", a_comment, b_comment)

my_attempt
#> # A tibble: 16 x 5
#>    time_taken key   value comment_key comment         
#>         <int> <chr> <dbl> <chr>       <chr>           
#>  1          1 a         2 a_comment   Comment about A!
#>  2          2 a         4 a_comment   Comment about A!
#>  3          3 a         6 a_comment   Comment about A!
#>  4          4 a         8 a_comment   Comment about A!
#>  5          1 b        -8 a_comment   Comment about A!
#>  6          2 b        -6 a_comment   Comment about A!
#>  7          3 b        -4 a_comment   Comment about A!
#>  8          4 b        -2 a_comment   Comment about A!
#>  9          1 a         2 b_comment   Comment about B?
#> 10          2 a         4 b_comment   Comment about B?
#> 11          3 a         6 b_comment   Comment about B?
#> 12          4 a         8 b_comment   Comment about B?
#> 13          1 b        -8 b_comment   Comment about B?
#> 14          2 b        -6 b_comment   Comment about B?
#> 15          3 b        -4 b_comment   Comment about B?
#> 16          4 b        -2 b_comment   Comment about B?

desired <- tibble(time_taken = rep(1:4, 2), 
                  variable = c(rep("a", 4), rep("b", 4)), 
                  value = c(seq(2, 8, by = 2), c(seq(-8, -2, by = 2))),
                  comment = c(rep("Comment about a!", 4), rep("Comment about b?", 4)))

desired
#> # A tibble: 8 x 4
#>   time_taken variable value comment         
#>        <int> <chr>    <dbl> <chr>           
#> 1          1 a            2 Comment about a!
#> 2          2 a            4 Comment about a!
#> 3          3 a            6 Comment about a!
#> 4          4 a            8 Comment about a!
#> 5          1 b           -8 Comment about b?
#> 6          2 b           -6 Comment about b?
#> 7          3 b           -4 Comment about b?
#> 8          4 b           -2 Comment about b?

reprex package (v0.2.1) 于 2019 年 8 月 8 日创建

【问题讨论】:

    标签: r dplyr tidyr


    【解决方案1】:

    我们可以使用dev 版本的tidyr 来做到这一点

    library(tidyr) #'0.8.3.9000'
    library(dplyr)
    names(my_df)[-1] <- c('value_1', 'comment_1', 'value_2', 'comment_2')
    pivot_longer(my_df, -time_taken, names_to = c(".value", "group"), names_sep = "_")
    

    或根据“评论”更改names

    nm2 <- c("value", 'comment')[grepl("comment", names(my_df)[-1]) + 1]
    names(my_df)[-1] <- paste0(nm2, '_', ave(seq_along(nm2), nm2, FUN = seq_along))
    

    上面的名称是手动更改的,但可以自动更改

    nm1 <- unique(str_remove(names(my_df)[-1], "_.*"))
    my_df %>% 
      rename_at(vars(matches("^(a|b)$")), ~ str_c("value_", seq_along(.))) %>%
      rename_at(vars(matches('comment')), ~str_c("comment_", seq_along(.))) %>% 
      pivot_longer(-time_taken, names_to = c(".value", "variable"), names_sep="_") %>%
      mutate(variable = nm1[as.integer(variable)]) %>%
      arrange(variable)
    # A tibble: 8 x 4
    #  time_taken variable value comment         
    #       <int> <chr>    <dbl> <chr>           
    #1          1 a            2 Comment about A!
    #2          2 a            4 Comment about A!
    #3          3 a            6 Comment about A!
    #4          4 a            8 Comment about A!
    #5          1 b           -8 Comment about B?
    #6          2 b           -6 Comment about B?
    #7          3 b           -4 Comment about B?
    #8          4 b           -2 Comment about B?
    

    【讨论】:

    • 由于一些版本控制/权限问题,我无法在我的计算机上启动并运行它,但这看起来很干净。
    【解决方案2】:

    您可以使用 splitbind_rows 做到这一点

    my_df[-1] %>% 
      split.default(substr(names(.), 1, 1)) %>% 
      map(rename_all, ~ c('value', 'comment')) %>% 
      bind_rows(.id = 'variable') %>% 
      mutate(time_taken = rep_len(my_df$time_taken, nrow(.)))
    
    # # A tibble: 8 x 4
    #   variable value comment          time_taken
    #   <chr>    <dbl> <chr>                 <int>
    # 1 a            2 Comment about A!          1
    # 2 a            4 Comment about A!          2
    # 3 a            6 Comment about A!          3
    # 4 a            8 Comment about A!          4
    # 5 b           -8 Comment about B?          1
    # 6 b           -6 Comment about B?          2
    # 7 b           -4 Comment about B?          3
    # 8 b           -2 Comment about B?          4
    

    【讨论】:

    • 这对我有用。唯一的弱点是它假定不同的值列在 n 个字符之前具有唯一名称(这里只有一个字符,但我将其更改为两个)。除此之外,它很干净。
    • 是的,还假设列对 (value, comment) 总是以相同的顺序 (never comment, value)
    【解决方案3】:

    我认为它需要双连接。首先,我将稍微修改您的数据,以便为每个 ab 设置不同的 cmets:

    my_df <- tibble(time_taken = 1:4, a = seq(2, 8, by = 2), b = seq(-8, -2, by = 2)) %>%
      mutate(a_comment = paste("Comment about A!", a), b_comment = paste("Comment about B?", b))
    my_df
    # # A tibble: 4 x 5
    #   time_taken     a     b a_comment          b_comment          
    #        <int> <dbl> <dbl> <chr>              <chr>              
    # 1          1     2    -8 Comment about A! 2 Comment about B? -8
    # 2          2     4    -6 Comment about A! 4 Comment about B? -6
    # 3          3     6    -4 Comment about A! 6 Comment about B? -4
    # 4          4     8    -2 Comment about A! 8 Comment about B? -2
    

    一种解决方案:

    my_df %>%
      select(-a_comment, -b_comment) %>%
      gather(k, v, -time_taken) %>%
      left_join(transmute(my_df, k = "a", v = a, a_comment), by = c("k", "v")) %>%
      left_join(transmute(my_df, k = "b", v = b, b_comment), by = c("k", "v")) %>%
      mutate(comment = coalesce(a_comment, b_comment)) %>%
      select(-a_comment, -b_comment)
    # # A tibble: 8 x 4
    #   time_taken k         v comment            
    #        <int> <chr> <dbl> <chr>              
    # 1          1 a         2 Comment about A! 2 
    # 2          2 a         4 Comment about A! 4 
    # 3          3 a         6 Comment about A! 6 
    # 4          4 a         8 Comment about A! 8 
    # 5          1 b        -8 Comment about B? -8
    # 6          2 b        -6 Comment about B? -6
    # 7          3 b        -4 Comment about B? -4
    # 8          4 b        -2 Comment about B? -2
    

    【讨论】:

      【解决方案4】:

      这是另一种方法。我只是将值和 cmets 合并,然后收集到 long,最后从它们的 cmets 中拆分值。

      my_df %>%
        unite(a, a, a_comment) %>%
        unite(b, b, b_comment) %>%
        gather(letter, vals, a, b) %>%
        separate(vals, into = c("value", "comment"), sep = "_") %>%
        type_convert
      
      #> # A tibble: 8 x 4
      #>   time_taken letter value comment         
      #>        <int> <chr>  <dbl> <chr>           
      #> 1          1 a          2 Comment about A!
      #> 2          2 a          4 Comment about A!
      #> 3          3 a          6 Comment about A!
      #> 4          4 a          8 Comment about A!
      #> 5          1 b         -8 Comment about B?
      #> 6          2 b         -6 Comment about B?
      #> 7          3 b         -4 Comment about B?
      #> 8          4 b         -2 Comment about B?
      

      【讨论】:

        猜你喜欢
        • 2022-09-26
        • 2012-12-23
        • 1970-01-01
        • 1970-01-01
        • 2013-12-31
        • 2014-04-14
        • 1970-01-01
        • 1970-01-01
        • 2020-11-02
        相关资源
        最近更新 更多