R - Можно ли развернуть список-столбец, который содержит пропущенные (NA) значения? - PullRequest
1 голос
/ 10 июня 2019

В таблице ниже приведен список-столбец 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]> 

Я хотел бы удалить этот столбец и затем распространить результат в широкий формат с тремя столбцами - type, lttr и mth:

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

Ответы [ 2 ]

1 голос
/ 10 июня 2019

Можно было бы преобразовать все в 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]>

Это может быть расширено до произвольного числа элементов

1 голос
/ 10 июня 2019

Как насчет unnest с tbl, group_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]>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...