【问题标题】:How to unnest a list containing data frames如何取消嵌套包含数据框的列表
【发布时间】:2019-09-09 21:18:54
【问题描述】:

我正在尝试扩展包含数据框列表的嵌套列。它们要么是NULL,要么是 1 行乘 n 列,所以目标只是将 n 列添加到 tibble。 (NULL 列表项最好扩展到NAs)。

我尝试了几种解决方案,包括来自this answer 的解决方案。

输出的目标是包含以下列的扁平小标题: full_address, address, location.x, location.y, score, attributes.StreetName, attributes.Match_addr.

require(tidyverse)
#> Loading required package: tidyverse

df <- structure(list(full_address = c("2379 ADDISON BLVD, HIGH POINT, NC 27262", 
                                "1751 W LEXINGTON AVE, HIGH POINT, NC 27262", "2514 WILLARD DAIRY RD, HIGH POINT, NC 27265", 
                                "126 MARYWOOD DR, HIGH POINT, NC 27265", "508 EDNEY RIDGE RD, GREENSBORO, NC 27408"
), json = list(NULL, NULL, structure(list(address = "2514 WILLARD DAIRY", 
                                          location = structure(list(x = -79.9766181813648, y = 36.0477204695356), class = "data.frame", row.names = 1L), 
                                          score = 92.8, attributes = structure(list(StreetName = "WILLARD DAIRY", 
                                                                                    Match_addr = "2514 WILLARD DAIRY"), class = "data.frame", row.names = 1L)), class = "data.frame", row.names = 1L), 
               structure(list(address = "126 MARYWOOD, HIGH POINT", location = structure(list(
                 x = -80.0202617159213, y = 36.0077059145502), class = "data.frame", row.names = 1L), 
                 score = 97.24, attributes = structure(list(StreetName = "MARYWOOD", 
                                                            Match_addr = "126 MARYWOOD, HIGH POINT"), class = "data.frame", row.names = 1L)), class = "data.frame", row.names = 1L), 
               structure(list(address = "508 EDNEY RIDGE RD", location = structure(list(
                 x = -79.840872836677, y = 36.1105523384593), class = "data.frame", row.names = 1L), 
                 score = 100L, attributes = structure(list(StreetName = "EDNEY RIDGE", 
                                                           Match_addr = "508 EDNEY RIDGE RD"), class = "data.frame", row.names = 1L)), class = "data.frame", row.names = 1L))), class = c("tbl_df", 
                                                                                                                                                                                          "tbl", "data.frame"), row.names = c(NA, -5L))

df
#> # A tibble: 5 x 2
#>   full_address                                json                
#>   <chr>                                       <list>              
#> 1 2379 ADDISON BLVD, HIGH POINT, NC 27262     <NULL>              
#> 2 1751 W LEXINGTON AVE, HIGH POINT, NC 27262  <NULL>              
#> 3 2514 WILLARD DAIRY RD, HIGH POINT, NC 27265 <data.frame [1 × 4]>
#> 4 126 MARYWOOD DR, HIGH POINT, NC 27265       <data.frame [1 × 4]>
#> 5 508 EDNEY RIDGE RD, GREENSBORO, NC 27408    <data.frame [1 × 4]>


df %>% unnest(json)
#> Error: Argument 2 can't be a list containing data frames


df %>% map(unlist) %>% as_data_frame()
#> Warning: `as_data_frame()` is deprecated, use `as_tibble()` (but mind the new semantics).
#> This warning is displayed once per session.
#> Tibble columns must have consistent lengths, only values of length one are recycled:
#> * Length 5: Column `full_address`
#> * Length 18: Column `json`

df %>%
  mutate_if(is.list, simplify_all) %>%    # flatten each list element internally 
  unnest() 
#> Error: Argument 2 can't be a list containing data frames

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

【问题讨论】:

  • 你在列表中有一些 NULL 元素。您希望预期输出如何
  • 不适用。谢谢,我会把它添加到我的问题中。
  • 试试df %&gt;% mutate(json = map(json, ~ if(is.null(.x)) data.frame(StreetName = NA_character_, Match_addr = NA_character_) else .x)),但我不清楚预期的输出
  • 你想cbind 嵌套数据帧到主数据帧,所以你会得到 1 个正常的、未嵌套的数据帧 colnames = c(full_address, address, location.x ...
  • 是的,@divibisan 是正确的。我已将此添加到问题中。

标签: r dplyr tidyverse tidyr purrr


【解决方案1】:

其中一个问题是每列中有嵌套的 data.frame

library(tidyverse)
df %>% 
   mutate(json = map(json, ~ if(is.null(.x)) 
    tibble(attributes.StreetName = NA_character_, attributes.Match_addr =  NA_character_) 
    else do.call(data.frame, c(.x, stringsAsFactors = FALSE)))) %>% 
    unnest
# A tibble: 5 x 7
#  full_address                     attributes.StreetNa… attributes.Match_ad… address           location.x location.y score
#  <chr>                            <chr>                <chr>                <chr>                  <dbl>      <dbl> <dbl>
#1 2379 ADDISON BLVD, HIGH POINT, … <NA>                 <NA>                 <NA>                    NA         NA    NA  
#2 1751 W LEXINGTON AVE, HIGH POIN… <NA>                 <NA>                 <NA>                    NA         NA    NA  
#3 2514 WILLARD DAIRY RD, HIGH POI… WILLARD DAIRY        2514 WILLARD DAIRY   2514 WILLARD DAI…      -80.0       36.0  92.8
#4 126 MARYWOOD DR, HIGH POINT, NC… MARYWOOD             126 MARYWOOD, HIGH … 126 MARYWOOD, HI…      -80.0       36.0  97.2
#5 508 EDNEY RIDGE RD, GREENSBORO,… EDNEY RIDGE          508 EDNEY RIDGE RD   508 EDNEY RIDGE …      -79.8       36.1 100  

或使用map_if

f1 <- function(dat) {
  dat %>% 
        flatten

   }

f2 <- function(dat) {
      tibble(attributes.StreetName = NA_character_, 
             attributes.Match_addr =  NA_character_)
     }

df %>%
    mutate(json = map_if(json, is.data.frame, f1, .else = f2)) %>% 
    unnest
# A tibble: 5 x 7
#  full_address                     attributes.StreetNa… attributes.Match_ad… address           score location.x location.y
#  <chr>                            <chr>                <chr>                <chr>             <dbl>      <dbl>      <dbl>
#1 2379 ADDISON BLVD, HIGH POINT, … <NA>                 <NA>                 <NA>               NA         NA         NA  
#2 1751 W LEXINGTON AVE, HIGH POIN… <NA>                 <NA>                 <NA>               NA         NA         NA  
#3 2514 WILLARD DAIRY RD, HIGH POI… WILLARD DAIRY        2514 WILLARD DAIRY   2514 WILLARD DAI…  92.8      -80.0       36.0
#4 126 MARYWOOD DR, HIGH POINT, NC… MARYWOOD             126 MARYWOOD, HIGH … 126 MARYWOOD, HI…  97.2      -80.0       36.0
#5 508 EDNEY RIDGE RD, GREENSBORO,… EDNEY RIDGE          508 EDNEY RIDGE RD   508 EDNEY RIDGE … 100        -79.8       36.1

【讨论】:

  • @jzadra 作为 cmets 中提到的 divisiban,您希望如何将列命名为 esp 以用于 .
  • 我只是将它们更改为 attributes.Match_addrattributes.StreetName 以匹配 do.call 的输出。
猜你喜欢
  • 2019-11-10
  • 2016-12-16
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2020-05-10
  • 2021-11-06
  • 2021-08-07
  • 2018-07-10
相关资源
最近更新 更多