【问题标题】:lapply with nested listlapply 嵌套列表
【发布时间】:2017-11-23 00:50:52
【问题描述】:

我有一个嵌套列表,我想lapplyas.data.frame 在最深的嵌套级别,然后rbindlist(来自data.table)所有内容。这是我的数据的样子:

a <- list(date="2017-01-01",ret=1:5)
b <- list(date="2017-01-02",ret=7:9)
lvl3 <- list(a,b) 
lvl2 <- list(lvl3,lvl3)
lvl1 <- list(lvl2,lvl2,lvl2)

如果我只有lvl3,我想把这个转化成data.framerbind的数据:

rbindlist(lapply(lvl3,as.data.frame))
         date ret
1: 2017-01-01   1
2: 2017-01-01   2
3: 2017-01-01   3
4: 2017-01-01   4
5: 2017-01-01   5
6: 2017-01-02   7
7: 2017-01-02   8
8: 2017-01-02   9

我将如何从 lvl1 和 rbind 全部嵌套 data.frames 做到这一点?这不起作用:

rbindlist(lapply(lvl1,as.data.frame))

想要的结果包含 48 行:

         date ret
 1: 2017-01-01   1
 2: 2017-01-01   2
 3: 2017-01-01   3
 4: 2017-01-01   4
 5: 2017-01-01   5
 6: 2017-01-02   7
 7: 2017-01-02   8
 8: 2017-01-02   9
 9: 2017-01-01   1
10: 2017-01-01   2
11: 2017-01-01   3
12: 2017-01-01   4
13: 2017-01-01   5
14: 2017-01-02   7
15: 2017-01-02   8
16: 2017-01-02   9
17: 2017-01-01   1
18: 2017-01-01   2
19: 2017-01-01   3
20: 2017-01-01   4
21: 2017-01-01   5
22: 2017-01-02   7
23: 2017-01-02   8
24: 2017-01-02   9
25: 2017-01-01   1
26: 2017-01-01   2
27: 2017-01-01   3
28: 2017-01-01   4
29: 2017-01-01   5
30: 2017-01-02   7
31: 2017-01-02   8
32: 2017-01-02   9
33: 2017-01-01   1
34: 2017-01-01   2
35: 2017-01-01   3
36: 2017-01-01   4
37: 2017-01-01   5
38: 2017-01-02   7
39: 2017-01-02   8
40: 2017-01-02   9
41: 2017-01-01   1
42: 2017-01-01   2
43: 2017-01-01   3
44: 2017-01-01   4
45: 2017-01-01   5
46: 2017-01-02   7
47: 2017-01-02   8
48: 2017-01-02   9

【问题讨论】:

  • rbindlist(lapply(lvl1,as.data.table)) 也许?
  • @agerom 那行不通。
  • 是的,我明白了,您介意发布您希望获得的结果吗?
  • "rbind 所有嵌套的 data.frames" -- 好的,然后返回 NULL,因为没有嵌套的 data.frames。 lvl1 %&gt;% unlist(recursive=FALSE) %&gt;% unlist(recursive=FALSE) %&gt;% lapply(as.data.table) %&gt;% rbindlist 工作,有点(与 magrittr)。应该有某种rapply 可以工作,但我永远无法让该函数正常运行。
  • 以类似的方式,这也适用(dplyrlapply(lvl1, function(y) lapply(y, function(x) lapply(x, data.frame) %&gt;% rbindlist) %&gt;% rbindlist) %&gt;% rbindlist

标签: r list data.table


【解决方案1】:

可能还有更优雅的方法,但是将 data.table 与嵌套的 foreach 循环结合起来:

library(foreach)
library(data.table)

a <- list(date="2017-01-01",ret=1:5)
b <- list(date="2017-01-02",ret=7:9)
lvl3 <- list(a,b) 
lvl2 <- list(lvl3,lvl3)
lvl1 <- list(lvl2,lvl2,lvl2)

o.3 <- foreach(i=1:length(lvl1)) %do% {
    o.2 <- foreach(j=1:length(lvl1[[i]])) %do% {
            o.1 <- foreach(k=1:length(lvl1[[i]][[j]])) %do% {
                as.data.table(lvl1[[i]][[j]][[k]])
            }
            rbindlist(o.1)
        }
        rbindlist(o.2)
    }

dat.final <- rbindlist(o.3)

【讨论】:

    【解决方案2】:

    我会选择 wickedpurrr。特别是:

    library(purrr)
    
    (rbindlist(lapply(simplify_all((rbindlist((lvl1 %>% at_depth(3,data.frame))))),rbindlist)))
    
         date ret
    1: 2017-01-01   1
    2: 2017-01-01   2
    3: 2017-01-01   3
    4: 2017-01-01   4
    5: 2017-01-01   5
    -----
    44: 2017-01-01   4
    45: 2017-01-01   5
    46: 2017-01-02   7
    47: 2017-01-02   8
    48: 2017-01-02   9
    

    【讨论】:

    • 你的结果是8行还是48行?
    【解决方案3】:

    一个丑陋的嵌套lapply 调用do.call 就可以了:

    do.call(rbind,do.call(rbind,lapply(lvl1,function(x) lapply(x,function(y) do.call(rbind,lapply(y, function(z) as.data.frame(z)))))))

    输出:

    > do.call(rbind,do.call(rbind,lapply(lvl1,function(x) lapply(x,function(y) do.call(rbind,lapply(y, function(z) as.data.frame(z)))))))
             date ret
    1  2017-01-01   1
    2  2017-01-01   2
    3  2017-01-01   3
    4  2017-01-01   4
    5  2017-01-01   5
    6  2017-01-02   7
    7  2017-01-02   8
    8  2017-01-02   9
    9  2017-01-01   1
    10 2017-01-01   2
    11 2017-01-01   3
    12 2017-01-01   4
    13 2017-01-01   5
    14 2017-01-02   7
    15 2017-01-02   8
    16 2017-01-02   9
    17 2017-01-01   1
    18 2017-01-01   2
    19 2017-01-01   3
    20 2017-01-01   4
    21 2017-01-01   5
    22 2017-01-02   7
    23 2017-01-02   8
    24 2017-01-02   9
    25 2017-01-01   1
    26 2017-01-01   2
    27 2017-01-01   3
    28 2017-01-01   4
    29 2017-01-01   5
    30 2017-01-02   7
    31 2017-01-02   8
    32 2017-01-02   9
    33 2017-01-01   1
    34 2017-01-01   2
    35 2017-01-01   3
    36 2017-01-01   4
    37 2017-01-01   5
    38 2017-01-02   7
    39 2017-01-02   8
    40 2017-01-02   9
    41 2017-01-01   1
    42 2017-01-01   2
    43 2017-01-01   3
    44 2017-01-01   4
    45 2017-01-01   5
    46 2017-01-02   7
    47 2017-01-02   8
    48 2017-01-02   9
    

    【讨论】:

      【解决方案4】:

      您可以构建自己的递归函数,点菜

      f <- function(l) {
        data.table::rbindlist(lapply(l, function(x) {
          if(all(sapply(x, is.atomic))) as.data.table(x) else f(x)
        }))
      }
      f(lvl1)
      

      这将返回一个 48 行 2 列的普通 data.table。

      另请注意,这适用于 lvl1lvl2lvl3,无需修改。

      【讨论】:

      • 那么不允许列表列,是吗?例如,L = list(x = 1:2, vals = list(1:2, 3:4))
      • 不,在这个设置中不是。您可以修改以检查至少一个列表元素是否是原子的,也许
      【解决方案5】:

      @docendo 的通用解决方案在我看来是最好的,但如果你知道它只是嵌套了两层...

      library(magrittr)
      
      lvl1 %>% 
        unlist(recursive=FALSE) %>% 
        unlist(recursive=FALSE) %>% 
        lapply(as.data.table) %>% 
        rbindlist
      

      来自@lmo,这是无管道模拟(不需要 magrittr):

      do.call(
        rbind, 
        lapply(
          unlist(unlist(lvl1, recursive=FALSE), recursive=FALSE), 
          as.data.frame
        )
      )
      

      【讨论】:

      • @lmo 谢谢,已添加。
      猜你喜欢
      • 2014-01-21
      • 2021-10-30
      • 2021-03-31
      • 1970-01-01
      • 2021-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-26
      相关资源
      最近更新 更多