问题
I am looking for a way to reliably coerce a list structure to a data.frame
or tibble
while maintaining one or more columns as list columns. Consider the following list structure:
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))
This does not work as intended:
lapply(ex, as_data_frame) %>% bind_rows()
Because the lm
object in the "model" column gets vectorized in the conversion. However, wrapping the model in list
gets the expected result:
ex2 = list(label = "A", number = 1L, model = list(lm(y ~ x, data = d)))
as_data_frame(ex2)
Unfortunately, I have a use case where I don't know beforehand whether a given column is a list or not. I am working with a function that outputs something like this:
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()
Is there a way to prevent data_frame
from vectorizing an object in the transformation to a tibble
? If not, what alternative approach could I use?
回答1:
Here is one option with 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>
For the first case, make the 'model' as a list
and then use as_tibble
ex$model <- list(ex$model)
as_tibble(ex)
回答2:
One option that I'm not super happy with, but might help guide the discussion: Check the types of each element the list structure and wrap them in a list if they are non-atomic or have more than 1 element:
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()
Not sure how robust this is, and probably slow too.
EDIT
Another option, which I found in an old dplyr issue linked from a related tibble issue:
library (purr)
ex3 = map(ex3, ~ as_list(extract(., "model"))
However, this only works on one "column" at a time, and also requires you to know the name of the column you want to wrap in a list.
If as_tibble_row
gets implemented, that will probably be the preferred solution.
来源:https://stackoverflow.com/questions/49701573/coerce-list-of-lists-to-data-frame-but-maintain-some-elements-in-list-columns