【问题标题】:Extracting data from hierarchical lists of different lengths into `data.frame` using `purr`使用`purr`从不同长度的分层列表中提取数据到`data.frame`
【发布时间】:2017-09-26 05:56:35
【问题描述】:

这是我之前提出的关于提取列表列表的特定子集的类似问题的直接后续:Extracting data from a list of lists into its own `data.frame` with `purrr`

因此我将使用相同的示例数据集:

l <- list(structure(list(a = -1.54676469632688, b = "s", c = "T", 
                     d = structure(list(id = 5L, label = "Utah", link = "Asia/Anadyr",
                                        score = -0.21104594634643), .Names = c("id", "label", "link", "score")), e = 49.1279871269422), .Names = c("a", "b", "c", "d", "e")), structure(list(a = -0.934821052832427, b = "k", c = "T", d = list(structure(list(id = 8L, label = "South Carolina", link = "Pacific/Wallis", score = 0.526540892113734, externalId = -6.74354377676955), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 9L, label = "Nebraska", link = "America/Scoresbysund", score = 0.250895465294041, externalId = 16.4257470807879), .Names = c("id", "label", "link", "score", "externalId"))), e = 52.3161400117052), .Names = c("a", "b", "c", "d", "e")), structure(list(a = -0.27261485993069, b = "f", c = "P", d = list(structure(list(id = 8L, label = "Georgia", link = "America/Nome", score = 0.526494135483816, externalId = 7.91583574935589), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 2L, label = "Washington", link = "America/Shiprock", score = -0.555186440792989, externalId = 15.0686663219837), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 6L, label = "North Dakota", link = "Universal", score = 1.03168296038975), .Names = c("id", "label", "link", "score")), structure(list(id = 1L, label = "New Hampshire", link = "America/Cordoba", score = 1.21582056168681, externalId = 9.7276418869132), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 1L, label = "Alaska", link = "Asia/Istanbul", score = -0.23183264861979), .Names = c("id", "label", "link", "score")), structure(list(id = 4L, label = "Pennsylvania", link = "Africa/Dar_es_Salaam", score = 0.590245339334121), .Names = c("id", "label", "link", "score"))), e = 132.1153538536), .Names = c("a", "e")), structure(list(a = 0.202685974077313, b = "x", c = "O", d = structure(list(id = 3L, label = "Delaware", link = "Asia/Samarkand", score = 0.695577130634724, externalId = 15.2364820698193), .Names = c("id", "label", "link", "score", "externalId")), e = 97.9908914452971), .Names = c("a", "b", "c", "d", "e")), structure(list(a = -0.396243444741009, b = "z", c = "P", d = list(structure(list(id = 4L, label = "North Dakota", link = "America/Tortola", score = 1.03060272795705, externalId = -7.21666936522344), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 9L, label = "Nebraska", link = "America/Ojinaga", score = -1.11397997280413, externalId = -8.45145052697411), .Names = c("id", "label", "link", "score", "externalId"))), e = 123.597945533926), .Names = c("a", "b", "c", "d", "e")))

我试图解决的一般问题是提取嵌套列表的不同长度的内容,并将它们绑定到同一列表中的其他内容,这些内容基本上用作嵌套内容的 ID。

在上述示例数据集的上下文中,我尝试将子列表d 的内容提取到data.table/data.frame 中,但也提取并基本上重复a 中的每个元素的数据-- 这样我就可以理解d 中的哪些提取元素属于同一个子集,因为它们的长度不同。所需data.table 的示例将解释得最好:

a          id           label                        link       score  externalId
-1.5467647  5            Utah                 Asia/Anadyr  -0.2110459          NA
-0.9348211  8  South Carolina              Pacific/Wallis   0.5265409   -6.743544
-0.9348211  9        Nebraska        America/Scoresbysund   0.2508955    16.42575

请注意,第一列al 中第一个子列表的内容。第一行是d(长度为1)中第一个嵌套项的内容,然后第二行和第三行是d(长度2)中第二项的内容,因此a中的值是相同的-0.9348211

目前,我实现此目的的解决方案是迂回的,并且容易出错 - 鉴于与上面引用的帖子的关系,我想知道我是否不理解能够将其扩展到的解决方案这个相关的问题。

【问题讨论】:

    标签: r data.table purrr


    【解决方案1】:

    每个嵌套列表往往需要稍微不同的方法,但这涵盖了一些典型的方法:

    library(tidyverse)
    
    l <- list(structure(list(a = -1.54676469632688, b = "s", c = "T", 
                         d = structure(list(id = 5L, label = "Utah", link = "Asia/Anadyr",
                                            score = -0.21104594634643), .Names = c("id", "label", "link", "score")), e = 49.1279871269422), .Names = c("a", "b", "c", "d", "e")), structure(list(a = -0.934821052832427, b = "k", c = "T", d = list(structure(list(id = 8L, label = "South Carolina", link = "Pacific/Wallis", score = 0.526540892113734, externalId = -6.74354377676955), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 9L, label = "Nebraska", link = "America/Scoresbysund", score = 0.250895465294041, externalId = 16.4257470807879), .Names = c("id", "label", "link", "score", "externalId"))), e = 52.3161400117052), .Names = c("a", "b", "c", "d", "e")), structure(list(a = -0.27261485993069, b = "f", c = "P", d = list(structure(list(id = 8L, label = "Georgia", link = "America/Nome", score = 0.526494135483816, externalId = 7.91583574935589), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 2L, label = "Washington", link = "America/Shiprock", score = -0.555186440792989, externalId = 15.0686663219837), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 6L, label = "North Dakota", link = "Universal", score = 1.03168296038975), .Names = c("id", "label", "link", "score")), structure(list(id = 1L, label = "New Hampshire", link = "America/Cordoba", score = 1.21582056168681, externalId = 9.7276418869132), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 1L, label = "Alaska", link = "Asia/Istanbul", score = -0.23183264861979), .Names = c("id", "label", "link", "score")), structure(list(id = 4L, label = "Pennsylvania", link = "Africa/Dar_es_Salaam", score = 0.590245339334121), .Names = c("id", "label", "link", "score"))), e = 132.1153538536), .Names = c("a", "e")), structure(list(a = 0.202685974077313, b = "x", c = "O", d = structure(list(id = 3L, label = "Delaware", link = "Asia/Samarkand", score = 0.695577130634724, externalId = 15.2364820698193), .Names = c("id", "label", "link", "score", "externalId")), e = 97.9908914452971), .Names = c("a", "b", "c", "d", "e")), structure(list(a = -0.396243444741009, b = "z", c = "P", d = list(structure(list(id = 4L, label = "North Dakota", link = "America/Tortola", score = 1.03060272795705, externalId = -7.21666936522344), .Names = c("id", "label", "link", "score", "externalId")), structure(list(id = 9L, label = "Nebraska", link = "America/Ojinaga", score = -1.11397997280413, externalId = -8.45145052697411), .Names = c("id", "label", "link", "score", "externalId"))), e = 123.597945533926), .Names = c("a", "b", "c", "d", "e")))
    
    l %>% 
        map(set_names, letters[1:5]) %>%    # add missing names
        map(modify_at, 'd', bind_rows) %>%    # coerce nested elements to data.frame
        # make each element to a data.frame, and rbind them all together
        map_df(data.frame, stringsAsFactors = FALSE)
    #>             a b c d.id        d.label               d.link    d.score         e d.externalId
    #> 1  -1.5467647 s T    5           Utah          Asia/Anadyr -0.2110459  49.12799           NA
    #> 2  -0.9348211 k T    8 South Carolina       Pacific/Wallis  0.5265409  52.31614    -6.743544
    #> 3  -0.9348211 k T    9       Nebraska America/Scoresbysund  0.2508955  52.31614    16.425747
    #> 4  -0.2726149 f P    8        Georgia         America/Nome  0.5264941 132.11535     7.915836
    #> 5  -0.2726149 f P    2     Washington     America/Shiprock -0.5551864 132.11535    15.068666
    #> 6  -0.2726149 f P    6   North Dakota            Universal  1.0316830 132.11535           NA
    #> 7  -0.2726149 f P    1  New Hampshire      America/Cordoba  1.2158206 132.11535     9.727642
    #> 8  -0.2726149 f P    1         Alaska        Asia/Istanbul -0.2318326 132.11535           NA
    #> 9  -0.2726149 f P    4   Pennsylvania Africa/Dar_es_Salaam  0.5902453 132.11535           NA
    #> 10  0.2026860 x O    3       Delaware       Asia/Samarkand  0.6955771  97.99089    15.236482
    #> 11 -0.3962434 z P    4   North Dakota      America/Tortola  1.0306027 123.59795    -7.216669
    #> 12 -0.3962434 z P    9       Nebraska      America/Ojinaga -1.1139800 123.59795    -8.451451
    

    有很多方法可以做到这一点,但关键是首先将嵌套最多的元素安排到适当的数据结构中,然后将它们与剩余的元素组合,直到你有一个 data.frame。

    请注意,在这里使用data.frame 而不是等效的 tibble 有点麻烦,但是 data.frame 更擅长将 data.frames 和值合并到单个 data.frame 中,并根据需要进行回收。使用 tidyverse 版本需要使所有内容都具有正确的长度,而不是依赖回收。

    【讨论】:

    • 以上内容肯定会有所帮助,并且可以到达我需要的地方-将您的解决方案应用于我的实际数据仍然不完整。这是由于实际数据与上面的示例数据之间存在差异,例如 "arguments imply different number of rows: 1, 2, 7" 之类的错误——我的想法是这可能是由于我不感兴趣的部分列表,例如,如果我想排除 bce,我怎么能只关注 ad 使用以上?
    • purrr::keep 是一种选择
    • 我正在查看purrr::keep 的帮助,看来这是由逻辑或谓词驱动的,我将如何利用基于数字的a 的函数,甚至说@987654331 @ 哪个是字符?
    • 取决于您对数据的了解。您也可以将map 添加到子集:l %&gt;% map(~.x[c('a', 'd')])
    猜你喜欢
    • 2014-02-09
    • 2020-02-06
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多