R - 是否可以取消嵌套包含缺失 (NA) 值的 list-column?

R - Is it possible to unnest a list-column that contains missing (NA) values?

下面的小标题有一个 list-column property,其中包含一些缺失值:

library(tidyverse)

tbl = tibble(type = c('scale', 'range', 'min', 'max'), 
         property = list(list(lttr = letters, mth = month.name), NA) %>% 
           rep(., 2))
# A tibble: 4 x 2
  type  property  
  <chr> <list>    
1 scale <list [2]>
2 range <lgl [1]> 
3 min   <list [2]>
4 max   <lgl [1]> 

我想取消嵌套此列,然后将结果展开为具有三列的宽格式 - typelttrmth:

tbl = tibble(type = c('scale', 'range', 'min', 'max'), 
             property = list(list(lttr = letters, mth = month.name), NA) %>% 
               rep(., 2)) %>% 
  mutate(property = map_if(property, is_list, enframe)) %>% 
  unnest(property) %>%
  spread(name, value)

但是,unnest 调用会引发以下错误:

Error: Each column must either be a list of vectors or a list of data frames [property]

我在 Git 上遇到了一个类似的问题,要求 unnest 支持 NULL 值但没有提及 NAs。函数文档中似乎也没有任何与缺失有关的参数,但我可能是错的。

如果过滤掉 NAs,管道将按预期工作:

tbl = tibble(type = c('scale', 'range', 'min', 'max'), 
             property = list(list(lttr = letters, mth = month.name), NA) %>% 
               rep(., 2)) %>% 
  mutate(property = map_if(property, is_list, enframe)) %>% 
  filter(!is.na(property)) %>% # drop_na() and na_omit not working not sure why
  unnest(property) %>%
  spread(name, value)

tbl
# A tibble: 2 x 3
  type  lttr       mth       
  <chr> <list>     <list>    
1 min   <chr [26]> <chr [12]>
2 scale <chr [26]> <chr [12]>

如何 unnesting tblgroup_by type 然后使用 summarise 创建新列?

library(dplyr)
library(tidyr)

tbl %>%
  unnest() %>%
  group_by(type) %>%
  summarise(lttr = property[1L], 
            mth = property[2L])

#  type  lttr       mth       
#  <chr> <list>     <list>    
#1 max   <NULL>     <NULL>    
#2 min   <chr [26]> <chr [12]>
#3 range <NULL>     <NULL>    
#4 scale <chr [26]> <chr [12]>

一个选项是将所有内容都转换为 tibble,这样 unnest 结构在整个过程中都是相同的,而不是手动设置子集

library(tidyverse)
tbl %>%
    mutate(property = map(property, ~ if(!is.list(.x))
        enframe(list(nm1 = .x)) else enframe(.x))) %>%
    unnest %>% 
    spread(name, value) %>%
    select(type, lttr, mth)
# A tibble: 4 x 3
#  type  lttr       mth       
#  <chr> <list>     <list>    
#1 max   <NULL>     <NULL>    
#2 min   <chr [26]> <chr [12]>
#3 range <NULL>     <NULL>    
#4 scale <chr [26]> <chr [12]>

OP 示例中的问题是 NA 行与其他行相比的结构差异。当我们 filter 他们出来时,结构是相同的,问题得到解决


我们还可以检查另一个示例,其中 list 个元素的数量大于 2。

tbl1 <- tibble(type = c('scale', 'range', 'min', 'max'), 
      property = list(list(lttr = letters, mth = month.name, 
       val1 = rnorm(12), val2 = runif(12)), NA) %>% 
        rep(., 2))

tbl1 %>% 
   mutate(property = map(property, ~ if(!is.list(.x)) enframe(list(nm1 = .x)) 
          else enframe(.x))) %>% 
   unnest %>%
   spread(name, value) %>%
   select(-nm1)
# A tibble: 4 x 5
#  type  lttr       mth        val1       val2      
#  <chr> <list>     <list>     <list>     <list>    
#1 max   <NULL>     <NULL>     <NULL>     <NULL>    
#2 min   <chr [26]> <chr [12]> <dbl [12]> <dbl [12]>
#3 range <NULL>     <NULL>     <NULL>     <NULL>    
#4 scale <chr [26]> <chr [12]> <dbl [12]> <dbl [12]>

这可以扩展到任意数量的元素