将列表列表强制为 data_frame,但在列表列中保留*一些*元素
Coerce list of lists to data_frame, but maintain *some* elements in list columns
我正在寻找一种方法来可靠地将列表结构强制转换为 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
对象在转换中被向量化。但是,将模型包装在 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
?如果没有,我可以使用什么替代方法?
一个我不太满意的选项,但可能有助于指导讨论:
检查列表结构中每个元素的类型,如果它们是 non-atomic 或超过 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()
不确定这有多稳健,也可能很慢。
编辑
我在 old dplyr issue linked from a related tibble issue:
中找到的另一个选项
library (purr)
ex3 = map(ex3, ~ as_list(extract(., "model"))
但是,这一次只能对一个 "column" 有效,并且还需要您知道要包含在列表中的列的名称。
如果 as_tibble_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>
对于第一种情况,将'model'设为list
,然后使用as_tibble
ex$model <- list(ex$model)
as_tibble(ex)
我正在寻找一种方法来可靠地将列表结构强制转换为 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
对象在转换中被向量化。但是,将模型包装在 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
?如果没有,我可以使用什么替代方法?
一个我不太满意的选项,但可能有助于指导讨论: 检查列表结构中每个元素的类型,如果它们是 non-atomic 或超过 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()
不确定这有多稳健,也可能很慢。
编辑
我在 old dplyr issue linked from a related tibble issue:
中找到的另一个选项library (purr)
ex3 = map(ex3, ~ as_list(extract(., "model"))
但是,这一次只能对一个 "column" 有效,并且还需要您知道要包含在列表中的列的名称。
如果 as_tibble_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>
对于第一种情况,将'model'设为list
,然后使用as_tibble
ex$model <- list(ex$model)
as_tibble(ex)