代码之家  ›  专栏  ›  技术社区  ›  user9630195

有效地将不同长度的嵌套列表转换为数据。框架(带底座R)

  •  4
  • user9630195  · 技术社区  · 6 年前

    我希望在将嵌套列表转换为数据帧方面得到一些帮助。我的解决方案多次迭代,我想知道是否有更有效的解决方案。

    嵌套列表的玩具示例:

    nested_list <- list(list('date' = '2018-01-10', 'value1' = 1, 'value2' = 2), 
                        list('date' = '2018-01-09', 'value1' = 3, 'value2' = 4), 
                        list('date' = '2018-01 08', 'value1' = NULL, 'value2' = NULL), 
                        list('date' = '2018-01-07', 'value1' = NULL, 'value2' = NULL), 
                        list('date' = '2018-01-06', 'value1' = 5, 'value2' = 6))
    

    正如您所看到的,有些值为NULL。我的意图是完全省略这些数据。

    目前,我首先屏蔽长度大于1的所有嵌套列表。

    mask <- sapply((lapply(nested_list, unlist)), length) > 1 
    

    然后我通过do应用rbind。调用并转换为数据。框架在这个过程的最后,我必须强制使用数值,因为它们都转换为字符串。

    data.frame(do.call('rbind', lapply(nested_list[mask], unlist)), stringsAsFactors = FALSE)
    

    正如您所看到的,这看起来很混乱,我想知道是否有更有效的方法来完成到数据帧的转换。

    非常感谢。

    3 回复  |  直到 6 年前
        1
  •  2
  •   akrun    6 年前

    这是一个 base R 选项,其中我们循环遍历“nested\u list”和 if any 元素具有 length 即0,然后将其分配给 NULL 或返回 data.frame

    res <- do.call(rbind, lapply(nested_list, function(x) 
          if(any(lengths(x) == 0)) NULL else data.frame(x, stringsAsFactors = FALSE)))
    res
    #         date value1 value2
    #1 2018-01-10      1      2
    #2 2018-01-09      3      4
    #3 2018-01-06      5      6
    

    在输入数据集中,“日期”值为 character ,最好存储为 Date

    res$date <- as.Date(res$date)
    str(res)
    # 'data.frame':   3 obs. of  3 variables:
    # $ date  : Date, format: "2018-01-10" "2018-01-09" "2018-01-06"
    # $ value1: num  1 3 5
    # $ value2: num  2 4 6
    
        2
  •  2
  •   mt1022    6 年前

    另一种解决方案:

    > data.table::rbindlist(nested_list[sapply(nested_list, function(x) min(lengths(x))) > 0])
             date value1 value2
    1: 2018-01-10      1      2
    2: 2018-01-09      3      4
    3: 2018-01-06      5      6
    
        3
  •  2
  •   Maurits Evers    6 年前

    我知道你的标题是“base R”,但你也要求一种更有效的方法。因此,另一种选择是 tidyverse 解决方案:

    nested_list %>%
        map(unlist) %>%
        rbind_all() %>%
        filter(complete.cases(.)) %>%
        mutate_at(vars(contains("value")), as.numeric);
    ## A tibble: 3 x 3
    #  date       value1 value2
    #  <chr>       <dbl>  <dbl>
    #1 2018-01-10     1.     2.
    #2 2018-01-09     3.     4.
    #3 2018-01-09     5.     6.
    

    或者(感谢@arun):

    nested_list %>% 
        transpose %>% 
        map_df(~ .x %>% replace(., lengths(.)==0, NA) %>% unlist) %>% 
        filter(!is.na(value1))