【问题标题】:Unnest list and concatenate in RR中的非嵌套列表和连接
【发布时间】:2020-03-31 07:18:17
【问题描述】:

我希望在tibble 中取消嵌套(展平?)和连接字符串(逗号分隔)。示例数据:

library(tidyverse)

tibble(person = c("Alice", "Bob", "Mary"), 
          score = list(c("Red", "Green", "Blue"), c("Orange", "Green", "Yellow"), "Blue"))

# A tibble: 3 x 2
  person score    
  <chr>  <list>   
1 Alice  <chr [3]>
2 Bob    <chr [3]>
3 Mary   <chr [1]>

预期输出:

tibble(person = c("Alice", "Bob", "Mary"),
       score = c("Red, Green, Blue", "Orange, Green, Yellow", "Blue" ))

# A tibble: 3 x 2
  person score                
  <chr>  <chr>                
1 Alice  Red, Green, Blue     
2 Bob    Orange, Green, Yellow
3 Mary   Blue   

我怀疑有一个非常简洁的tidyverse 解决方案,但经过大量搜索后我无法找到答案;我怀疑我使用了错误的搜索词(未嵌套/连接)。 首选tidyverse 解决方案。谢谢。

【问题讨论】:

    标签: r tidyverse


    【解决方案1】:

    你可以这样做:

    library(dplyr)
    library(purrr)
    
    df %>%
      mutate(score = map_chr(score, toString))
    
    # A tibble: 3 x 2
      person score                
      <chr>  <chr>                
    1 Alice  Red, Green, Blue     
    2 Bob    Orange, Green, Yellow
    3 Mary   Blue                
    

    如果您有多个列表列,您可以这样做:

    df <- tibble(person = c("Alice", "Bob", "Mary"), 
           score1 = list(c("Red", "Green", "Blue"), c("Orange", "Green", "Yellow"), "Blue"),
           score2 = rev(list(c("Red", "Green", "Blue"), c("Orange", "Green", "Yellow"), "Blue")))
    
    df %>%
      mutate_if(is.list, ~ map_chr(.x, toString))
    
    # A tibble: 3 x 3
      person score1                score2               
      <chr>  <chr>                 <chr>                
    1 Alice  Red, Green, Blue      Blue                 
    2 Bob    Orange, Green, Yellow Orange, Green, Yellow
    3 Mary   Blue                  Red, Green, Blue     
    

    【讨论】:

      【解决方案2】:

      一个简单的方法是unnest长格式的数据并按组折叠它。

      library(dplyr)
      
      df %>%
        tidyr::unnest(score) %>%
        group_by(person) %>%
        summarise(score = toString(score))
      
      # person score                
      #  <chr>  <chr>                
      #1 Alice  Red, Green, Blue     
      #2 Bob    Orange, Green, Yellow
      #3 Mary   Blue        
      

      其他选项是rowwise

      df %>% rowwise() %>% mutate(score = toString(score))
      

      【讨论】:

      • 感谢您的快速响应,这看起来不错!也许我应该提出一个全新的问题,但是;我如何将您上面的方法概括为tibble 中的 all 列上的unnest(),它们是列表?例如如果我的 df 是 100 列宽和 12 列是列表,我怎么能拉出这些列并将它们发送到 toString()
      • @Simon 在这种情况下我认为rowwise 解决方案使用mutate_at 更好,选择vars 中的所有列并应用函数df %&gt;% rowwise() %&gt;% mutate_at(vars(starts_with('score')), toString)
      • 有没有一种方法可以只选择列表中的列?在较大的 df 中,可能很难提前知道哪些列是列表(无需手动浏览每一列并做笔记)。使用starts_with 假设您提前知道所有列表列的名称。谢谢!
      • @Simon 是的,你可以使用mutate_if df %&gt;% rowwise() %&gt;% mutate_if(is.list, toString)
      【解决方案3】:

      基础R解决方案1:

      df$score <- sapply(df$score, toString)
      

      基础 R 解决方案 2:

      df$score <- unlist(lapply(df$score, paste, collapse = ", "))
      

      数据:

      df <- tibble(person = c("Alice", "Bob", "Mary"), 
             score = list(c("Red", "Green", "Blue"), c("Orange", "Green", "Yellow"), "Blue"))
      

      【讨论】:

        【解决方案4】:

        这是(最近的)Tidyverse 的一种万能方法,不会干扰分组:

        df %>% mutate(across(where(is.list), ~ sapply(., toString)))
        

        【讨论】:

          猜你喜欢
          • 2019-07-13
          • 1970-01-01
          • 2022-10-14
          • 1970-01-01
          • 1970-01-01
          • 2014-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多