假设以下列表:
x <- list(list(q = 1880L, properties = list(), last_Import_Date = "2024-09-16"),
list(q = 1888L, properties = list(list(a = "x", b = "y")), last_Import_Date = "2024-09-16"),
list(q = 1890L, properties = list(list(a = "x", b = "y")), last_Import_Date = "2024-09-16"))
我想将此列表转换为数据框(按行)。通常,dplyr::bind_rows
效果很好。但是,我的列表中有一些元素有时为空(“属性”),在这种情况下 bind_rows 会失败,因为它只保留那些不为空的行。
有人能解释一下这是为什么吗?
有没有什么 (简短的) 解决方法?我目前正在使用相当丑陋的解决方法,使用 list2DF,然后转置,然后转换为数据框,然后分配名称。
错误的结果(仅保留非空属性):
x |>
bind_rows()
# A tibble: 2 × 3
q properties last_Import_Date
<int> <list> <chr>
1 1888 <named list [2]> 2024-09-16
2 1890 <named list [2]> 2024-09-16
更新:我需要一些额外的帮助来解除这种特殊的“属性”列的嵌套。使用unnest_longer
将导致删除 NULL 行的相同“错误”,而使用 unnest_wider 需要一些额外的解决方法来修复名称。
最佳答案
3
bind_rows
vctrs::data_frame
底层使用。事实证明vctrs::data_frame
,当存在长度为 0 的元素时(即 list(0)、interger(0)、character(0) 等),会创建空数据框:
vctrs::data_frame(!!!list(q = 1880L, properties = list(), last_Import_Date = "2024-09-16"),.name_repair="unique")
[1] q properties last_Import_Date
<0 rows> (or 0-length row.names)
vctrs::data_frame(a=list("a"),b= integer(0))
[1] a b
<0 rows> (or 0-length row.names)
vctrs::data_frame(a=list(),b= 1)
[1] a b
<0 rows> (or 0-length row.names)
另一种方法是使用vctrs::vec_rbind
:
vctrs::vec_rbind(!!!x)
q properties last_Import_Date
1 1880 NULL 2024-09-16
2 1888 x, y 2024-09-16
3 1890 x, y 2024-09-16
3
-
您说到点子上了!解决方法又好又简单,+1!
– -
我应该更清楚地说明我需要修复/解决方法的地方,即如何轻松地取消嵌套这样的列(“属性”)。将更新我的帖子。
– -
对于接受哪个答案,@G.Grothendieck 和 ThomasIsCoding 很难做出决定,但我决定接受这个答案,因为它回答了我最初的问题(即为什么 bind_rows 会失败)。如果可以的话,我会接受所有答案,因为它们提供了有价值的信息和解决方案。
–
|
bind_rows
1)如果您像这样预先和之后处理输入,bind_rows将起作用:
library(dplyr)
x |> lapply(unlist) |> bind_rows() |> type.convert(as.is = TRUE)
## # A tibble: 3 × 4
## q last_Import_Date properties.a properties.b
## <int> <chr> <chr> <chr>
## 1 1880 2024-09-16 <NA> <NA>
## 2 1888 2024-09-16 x y
## 3 1890 2024-09-16 x y
2) 转置转置x
然后删除中的额外列表层properties
允许我们使用hoist
提升a
和b
从中使用properties
。
library(purrr)
library(tidyr)
x |>
transpose() |>
list2DF() |>
transform(properties = lapply(properties, unlist)) |>
hoist(properties, "a", "b")
## q a b last_Import_Date
## 1 1880 <NA> <NA> 2024-09-16
## 2 1888 x y 2024-09-16
## 3 1890 x y 2024-09-16
3) 基数 R如果的列表列properties
足够,则此双重迭代仅使用基数 R:
Map(\(z) sapply(x, "[[", z), names(x[[1]])) |> list2DF()
## q properties last_Import_Date
## 1 1880 NULL 2024-09-16
## 2 1888 x, y 2024-09-16
## 3 1890 x, y 2024-09-16
4)rrapply rrapply
可以直接创建数据框:
library(rrapply)
rrapply(x, how = "bind")
## q last_Import_Date properties.1.a properties.1.b
## 1 1880 2024-09-16 <NA> <NA>
## 2 1888 2024-09-16 x y
## 3 1890 2024-09-16 x y
|
更新
如果您想使用unnest
而不删除中的空条目properties
,您应该指定选项keep_empty = TRUE
(基于)
vctrs::vec_rbind(!!!x) %>%
unnest(cols = everything(), keep_empty = TRUE)
由此得出
# A tibble: 3 × 3
q properties last_Import_Date
<int> <list> <chr>
1 1880 <NULL> 2024-09-16
2 1888 <named list [2]> 2024-09-16
3 1890 <named list [2]> 2024-09-16
其基本 R 等价关系可能是
list2DF(
lapply(
as.data.frame(do.call(rbind, x)),
\(v) unlist(replace(v, lengths(v) == 0, list(list(NULL))), FALSE)
)
)
由此得出
q properties last_Import_Date
1 1880 NULL 2024-09-16
2 1888 x, y 2024-09-16
3 1890 x, y 2024-09-16
结构如下
'data.frame': 3 obs. of 3 variables:
$ q : int 1880 1888 1890
$ properties :List of 3
..$ : NULL
..$ :List of 2
.. ..$ a: chr "x"
.. ..$ b: chr "y"
..$ :List of 2
.. ..$ a: chr "x"
.. ..$ b: chr "y"
$ last_Import_Date: chr "2024-09-16" "2024-09-16" "2024-09-16"
较旧(快速修复)
这是一个基本的 R 快速修复
> as.data.frame(do.call(rbind, x))
q properties last_Import_Date
1 1880 NULL 2024-09-16
2 1888 x, y 2024-09-16
3 1890 x, y 2024-09-16
它的结构如下
> as.data.frame(do.call(rbind, x)) %>% str()
'data.frame': 3 obs. of 3 variables:
$ q :List of 3
..$ : int 1880
..$ : int 1888
..$ : int 1890
$ properties :List of 3
..$ : list()
..$ :List of 1
.. ..$ :List of 2
.. .. ..$ a: chr "x"
.. .. ..$ b: chr "y"
..$ :List of 1
.. ..$ :List of 2
.. .. ..$ a: chr "x"
.. .. ..$ b: chr "y"
$ last_Import_Date:List of 3
..$ : chr "2024-09-16"
..$ : chr "2024-09-16"
..$ : chr "2024-09-16"
2
-
谢谢!我应该更清楚我需要修复/解决方法的地方,即如何轻松地取消嵌套这样的列(“属性”)。我会更新我的帖子。
– -
@deschen 请检查更新是否符合您的要求
–
|
|