R 强制列表列表到数据框架,但在列表列中保留*部分*元素

R 强制列表列表到数据框架,但在列表列中保留*部分*元素,r,tibble,R,Tibble,我正在寻找一种方法来可靠地将列表结构强制为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() 因为“model”列中的l

我正在寻找一种方法来可靠地将列表结构强制为
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()
因为“model”列中的
lm
对象在转换中得到矢量化。但是,将模型包装在
列表中
会得到预期的结果:

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()

有没有办法防止
数据帧
在转换为
tible
时将对象矢量化?如果不是,我可以使用什么替代方法?

一个我不太满意但可能有助于指导讨论的选项: 检查列表结构中每个元素的类型,如果它们是非原子元素或具有多个元素,则将它们包装在列表中:

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()
不确定这有多强大,可能也很慢


编辑

另一个选项,我在来自的链接中找到:

但是,这一次只对一个“列”有效,并且还要求您知道要在列表中包装的列的名称


如果
as_tible_row
得到实现,这可能是首选的解决方案。

这里有一个选项与
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>

你能解释一下你的答案中转置的用法吗?
transpose
将把相同名称的元素放在一起,我知道了,很有趣。您的解决方案重塑列表,然后
取消列出原子元素,而另一个解决方案
列出非原子元素。基准测试表明您的方法明显更快。
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>
ex$model <- list(ex$model)
as_tibble(ex)