Привести список списков к data_frame, но сохранить *некоторые* элементы в столбцах списка

Я ищу способ надежно привязать структуру списка к data.frame или tibble, сохраняя при этом один или несколько столбцов в качестве столбцов списка. Рассмотрим следующую структуру списка:

d = data.frame(x = 1:10, y = 1.5*(1:10) + rnorm(10))
ex = list(label = "A", number = 1L, model = lm(y ~ x, data = d))

Это не работает так, как задумано:

lapply(ex, as_data_frame) %>% bind_rows()

Потому что объект lm в столбце «модель» векторизуется при преобразовании. Однако обертывание модели в list дает ожидаемый результат:

ex2 = list(label = "A", number = 1L, model = list(lm(y ~ x, data = d)))
as_data_frame(ex2)

К сожалению, у меня есть вариант использования, когда я заранее не знаю, является ли данный столбец списком или нет. Я работаю с функцией, которая выводит что-то вроде этого:

ex3 = list(
  list(label = "A", number = 1L, model = lm(y ~ x, data = d)),
  list(label = "B", number = 1L, model = lm(y ~ x + 0, data = d))
)
# won't work properly
lapply(ex3, as_data_frame) %>% bind_rows()

Есть ли способ предотвратить векторизацию объекта data_frame при преобразовании в tibble? Если нет, то какой альтернативный подход я мог бы использовать?


person mikeck    schedule 06.04.2018    source источник


Ответы (2)


Вот один вариант с tidyverse

library(tidyverse)
ex3 %>% 
 transpose %>% 
 map_if(~all(lengths(.) == 1), unlist) %>% 
 as_tibble
# A tibble: 2 x 3
#  label number model   
#   <chr>  <int> <list>  
#1 A          1 <S3: lm>
#2 B          1 <S3: lm>

В первом случае создайте «модель» как list, а затем используйте as_tibble.

ex$model <- list(ex$model)
as_tibble(ex)
person akrun    schedule 07.04.2018
comment
Можете ли вы объяснить использование transpose в своем ответе? - person mikeck; 08.04.2018
comment
transpose соберет элементы с одинаковыми именами вместе - person akrun; 09.04.2018
comment
Я вижу, интересно. Ваше решение меняет форму списка, а затем unlists атомарные элементы, тогда как другое решение lists неатомарные элементы. Сравнительный анализ показывает, что ваш метод значительно быстрее. - person mikeck; 09.04.2018

Один вариант, который мне не очень нравится, но может помочь в обсуждении: проверьте типы каждого элемента структуры списка и оберните их в список, если они не являются атомарными или имеют более 1 элемента:

listify = function(x) {
  if(length(x) > 1L || !is.atomic(x))
    list(x)
  else
    x
}
lapply(ex3, function(x) as_data_frame(lapply(x, listify))) %>% bind_rows()

Не уверен, насколько это надежно, и, вероятно, тоже медленно.


ИЗМЕНИТЬ

Еще один вариант, который я нашел в старом выпуске dplyr, связанном с связанная проблема с текстом:

library (purr)
ex3 = map(ex3, ~ as_list(extract(., "model"))

Однако это работает только с одним «столбцом» за раз, а также требует, чтобы вы знали имя столбца, который вы хотите обернуть в список.

Если as_tibble_row будет реализовано, это, вероятно, будет предпочтительным решением.

person mikeck    schedule 06.04.2018