将不完整列表解析为具有两个不同问题的数据框

Parsing incomplete lists into data frames with two different problems

如果您通过 R 请求 Web 数据,您通常会使用 json 或 xml,其中如果字段没有值则不会命名。有时,甚至没有任何数据,它作为某个索引的空列表出现。所以,我认为这是两个不同的问题。我也提出了我用来解决这个问题的解决方案,但我知道有一些更好的解决方案。对于初学者,我有一个我创建的非常混乱和虚假的列表,它缺少字段名称(故意来自 xml、json 规范)并且缺少整个索引(也是故意的)。

(messy_list <- list(list(x = 2, y = 3), 
                   list(), 
                   list(y = 4),
                   list(x = 5)))

现在,我将其分解为 "solved"。

library(plyr)
messy_list_no_empties <- lapply(messy_list, function(x) if(length(x) == 0) {list(NA, NA)} else x)

ldply(messy_list_no_empties, data.frame)[,1:2]

最终结果是我想要的,但我想找到一种更优雅的方法来处理这个问题。

purrr::map_df,

library(purrr)

messy_list <- list(list(x = 2, y = 3), 
                   list(), 
                   list(y = 4),
                   list(x = 5))

messy_list %>% map_df(~list(x = .x$x %||% NA, 
                            y = .x$y %||% NA))
#> # A tibble: 4 × 2
#>       x     y
#>   <dbl> <dbl>
#> 1     2     3
#> 2    NA    NA
#> 3    NA     4
#> 4     5    NA

map_dflapply 一样遍历列表并将结果强制为 data.frame。该函数(以 purrr 的公式形式)组合一个包含 xy 元素的列表,查找现有值(如果存在)。如果不是,子集将 return NULL%||% 将替换为它后面的值 NA.

在基本等价的基础 R 中,

as.data.frame(do.call(rbind, 
                      lapply(messy_list, function(.x){
                          list(x = ifelse(is.null(.x$x), NA, .x$x), 
                               y = ifelse(is.null(.x$y), NA, .x$y))
                      })))
#>    x  y
#> 1  2  3
#> 2 NA NA
#> 3 NA  4
#> 4  5 NA

请注意,基本方法无法很好地处理不同的类型。为此,将所有内容强制转换为字符(rbind 可能无论如何,所以只需将 stringsAsFactors = FALSE 添加到 as.data.frame)和 lapply type.convert.

您的方法已经非常紧凑,但如果您正在寻找其他方法,一种方法可能是使用 rbindlist from data.table:

library(data.table)
new_list <- lapply(messy_list, function(x) if(identical(x,list())){list(x = NA)} else {x})

rbindlist(new_list, fill = T, use.names = T)
#    x  y
#1:  2  3
#2: NA NA
#3: NA  4
#4:  5 NA

请注意,我们需要 lapply,这样它就不会删除空行