我正在寻找一种方法,可以将列表结构可靠地强制转换为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
?如果没有,我可以使用哪种替代方法?
答案 0 :(得分:2)
以下是final
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
答案 1 :(得分:0)
我不满意的一个选项,但可能有助于指导讨论: 检查列表结构中每个元素的类型,如果它们是非原子的或具有多个元素,则将它们包装在列表中:
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()
不确定这是多么强大,也可能很慢。
编辑
我在old dplyr issue链接的related tibble issue中找到的另一个选项:
library (purr)
ex3 = map(ex3, ~ as_list(extract(., "model"))
然而,这仅适用于一个&#34;列&#34;一次,并且还要求您知道要在列表中包装的列的名称。
如果实施as_tibble_row
,那可能是首选解决方案。