【问题标题】:R - Is it possible to unnest a list-column that contains missing (NA) values?R - 是否可以取消嵌套包含缺失 (NA) 值的列表列?
【发布时间】:2019-10-24 10:50:10
【问题描述】:

下面的小标题有一个列表列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]>

【问题讨论】:

  • 您的预期输出包含 3 个新列,其中包含 maxrange 值以及所有 NAs ?
  • 是的,这可能吗?

标签: r dplyr tidyr data-manipulation unnest


【解决方案1】:

一种选择是将所有内容都转换为tibble,这样在unnesting 时结构将是相同的,而不是手动子集

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]>

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

【讨论】:

  • 感谢您指出所有行的结构必须相同。错误消息非常清楚该要求,但我没有想到使用您建议的解决方法,即为 NA 行执行enframe(list(nm1 = .x))
【解决方案2】:

unnesttblgroup_bytype 然后用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]>

【讨论】:

  • 感谢@Ronak 提供的解决方法,我不知道会这样使用summarise
猜你喜欢
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 2019-11-10
  • 1970-01-01
  • 2017-10-02
  • 2019-09-09
  • 1970-01-01
  • 2023-04-06
相关资源
最近更新 更多