使用 dplyr 传播和加入不等大小列表的列表

Spread and join list of lists of unequal sizes with dplyr

我有兴趣做一个相当复杂的连接,但我一直找不到答案。这是一个示例数据集:

dat2 <- data.frame(age = c(2,2), id = c("T1", "T2"), Height = c(1.1,1.2), Number = c(1,1), node_age = c(0, 0))
dat3 <- data.frame(age = c(3,3,3,3), id = c("T1", "T1", "T2", "T2"), Height = c(1.1,2.2, 1.2, 2.3), Number = c(1,2,1,2), node_age = c(1,0,1,0))
dat4 <- data.frame(age = c(4,4,4,4,4,4), id = c("T1", "T1", "T1", "T2", "T2", "T2"), Height = c(1.1,2.2,3.3,1.2, 2.3,3.4 ), Number = c(1,2,3,1,2,3), node_age = c(2,1,0,2,1,0))
dat_list <- list(dat2, dat3, dat4)

我想使用这个列表并将所有内容连接在一起,这样结果看起来像这样:

$`T1`
  id Height Number_2 node_age_2 Number_3 node_age_3 Number_4 node_age_4
1 T1    1.1        1          0        1          1        1          2
2 T1    2.2       NA         NA        2          0        2          1
3 T1    3.3       NA         NA       NA         NA        3          0

$T2
  id Height Number_2 node_age_2 Number_3 node_age_3 Number_4 node_age_4
4 T2    1.2        1          0        1          1        1          2
5 T2    2.3       NA         NA        2          0        2          1
6 T2    3.4       NA         NA       NA         NA        3          0

其中输出是按 id 排列的列表列表,"Number" 和 "node_age" 作为 "age" 的函数重复。

我在收集、团结和传播方面取得了一些进步。但是我觉得效率很低,把bind_rows的列表,然后散开,再组合回列表。也许我在这里错了?

我的真实数据是一个大列表(115 个元素)。当我 bind_rows 我的列表时,我最终得到 233561 个观察结果。所以我有很多 id,node_age 一直到 115,这就是我瞄准列表结构的原因。

提前致谢。

我们可以绑定行,然后 split 通过 'id' 和 dcast 到 'wide' 格式

library(tidyverse)
library(data.table)
dat_list %>%
   bind_rows %>% 
   split(.$id) %>% 
   map(~  dcast(as.data.table(.x), id + Height ~ age, 
              value.var = c( 'Number', 'node_age')))
#$T1
#   id Height Number_2 Number_3 Number_4 node_age_2 node_age_3 node_age_4
#1: T1    1.1        1        1        1          0          1          2
#2: T1    2.2       NA        2        2         NA          0          1
#3: T1    3.3       NA       NA        3         NA         NA          0

#$T2
#   id Height Number_2 Number_3 Number_4 node_age_2 node_age_3 node_age_4
#1: T2    1.2        1        1        1          0          1          2
#2: T2    2.3       NA        2        2         NA          0          1
#3: T2    3.4       NA       NA        3         NA         NA          0

或者我们用gather/spread代替dcast

dat_list %>% 
   bind_rows %>%
   split(.$id) %>%
   map(~ .x  %>% 
            gather(key, val, Number:node_age) %>%
            unite(keyage, key, age) %>%
            spread(keyage, val))
#$T1
#  id Height node_age_2 node_age_3 node_age_4 Number_2 Number_3 Number_4
#1 T1    1.1          0          1          2        1        1        1
#2 T1    2.2         NA          0          1       NA        2        2
#3 T1    3.3         NA         NA          0       NA       NA        3

#$T2
#  id Height node_age_2 node_age_3 node_age_4 Number_2 Number_3 Number_4
#1 T2    1.2          0          1          2        1        1        1
#2 T2    2.3         NA          0          1       NA        2        2
#3 T2    3.4         NA         NA          0       NA       NA        3

如果我们需要特定 order 中的列,请将 'key' 创建为 factor 列,并按该顺序指定 levels 以更改 orderspread

dat_list %>% 
    bind_rows %>%
    split(.$id) %>%
    map(~ .x  %>% 
             gather(key, val, Number:node_age) %>%
             group_by(key) %>%
             mutate(rn = row_number())  %>%
             ungroup %>% 
             arrange(rn) %>%
             unite(keyage, key, age) %>%
             mutate(keyage = factor(keyage, levels = unique(keyage))) %>% 
             select(-rn) %>%
             spread(keyage, val))
#$T1
# A tibble: 3 x 8
#  id    Height Number_2 node_age_2 Number_3 node_age_3 Number_4 node_age_4
#  <fct>  <dbl>    <dbl>      <dbl>    <dbl>      <dbl>    <dbl>      <dbl>
#1 T1       1.1        1          0        1          1        1          2
#2 T1       2.2       NA         NA        2          0        2          1
#3 T1       3.3       NA         NA       NA         NA        3          0

#$T2
# A tibble: 3 x 8
#  id    Height Number_2 node_age_2 Number_3 node_age_3 Number_4 node_age_4
#  <fct>  <dbl>    <dbl>      <dbl>    <dbl>      <dbl>    <dbl>      <dbl>
#1 T2       1.2        1          0        1          1        1          2
#2 T2       2.3       NA         NA        2          0        2          1
#3 T2       3.4       NA         NA       NA         NA        3          0