含空properties子列表时bind_rows失效原因、修复及unnest问题求助
问题背景
先给出示例数据:
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()转换为数据框时,原本期望得到3行数据,但实际仅保留了2行(丢失了properties为空的第一行):
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
原因分析
bind_rows()默认会过滤掉所有元素均为空的子列表(此处properties = list()是完全空的列表)。它的核心逻辑是对齐列结构,当某一行的某个列对应的子列表没有任何元素时,会被判定为"无效"行自动丢弃——这是处理不规则列表的默认行为,但在需要保留空行的场景下就会出现问题。
简洁修复方法
方法1:用purrr::map_dfr配合tibble::as_tibble
逐个将子列表转为tibble后再合并,能完整保留所有行,包括含空列表的行:
library(purrr) library(tibble) map_dfr(x, as_tibble)
输出结果:
# A tibble: 3 × 3 q properties last_Import_Date <int> <list> <chr> 1 1880 <list [0]> 2024-09-16 2 1888 <named list [2]> 2024-09-16 3 1890 <named list [2]> 2024-09-16
方法2:手动补全空列表结构
如果需要让bind_rows()识别空列表的结构,可以给空的properties补充与其他行一致的空命名列表:
library(dplyr) x_fixed <- x |> map(function(row) { if (length(row$properties) == 0) { row$properties <- list(list(a = NA, b = NA)) } row }) x_fixed |> bind_rows()
这种方法适合后续需要展开properties列的场景,提前统一结构能避免后续处理的麻烦。
补充问题:展开properties列的解决方法
问题场景
使用unnest_longer()时会丢失空行,unnest_wider()需要额外处理命名问题。
解决方法1:统一结构后展开
先确保所有properties的结构一致(空行补全为含NA的结构),再进行展开操作:
library(dplyr) library(tidyr) # 补全空列表结构 x_fixed <- x |> map(function(row) { if (length(row$properties) == 0) { row$properties <- list(list(a = NA, b = NA)) } row }) # 合并后展开 x_fixed |> bind_rows() |> unnest_longer(properties) |> unnest_wider(properties)
输出结果:
# A tibble: 3 × 3 q a b last_Import_Date <int> <chr> <chr> <chr> 1 1880 NA NA 2024-09-16 2 1888 x y 2024-09-16 3 1890 x y 2024-09-16
解决方法2:使用unnest()的keep_empty参数
直接用tidyr::unnest()并设置keep_empty = TRUE,无需提前补全结构即可保留空行:
library(tidyr) x |> map_dfr(as_tibble) |> unnest(properties, keep_empty = TRUE)
输出同样能保留所有行,并将空的properties展开为NA值:
# A tibble: 3 × 3 q a b last_Import_Date <int> <chr> <chr> <chr> 1 1880 NA NA 2024-09-16 2 1888 x y 2024-09-16 3 1890 x y 2024-09-16
内容的提问来源于stack exchange,提问作者deschen
相关产品推荐
相关产品推荐

