r:循环遍历列表并将结果附加到数据框

时间:2021-05-06 23:27:53

标签: r list for-loop

我有以下列表,list1list2

library(tidyverse)

df1a <- data.frame(
  index = c(1, 1, 2, 2),
  first_column = c(1, 2, 3, 4),
  second_column = c(5, 6, 7, 8)
)

df1b <- data.frame(
  index = c(1, 1, 2, 2),
  first_column = c(4, 2, 3, 1),
  second_column = c(8, 6, 7, 5)
)

list1 <- dplyr::lst(df1a, df1b)

df2a <- data.frame(
  index = c(1, 1, 2, 2),
  first_column = c(4, 3, 2, 1),
  second_column = c(8, 7, 6, 5)
)

df2b <- data.frame(
  index = c(1, 1, 2, 2),
  first_column = c(8, 2, 6, 5),
  second_column = c(4, 3, 7, 1)
)

list2 <- dplyr::lst(df2a, df2b)

这是我想在 list1list2 上运行的函数:

output_mean <- function(subset, name) {
  subset %>%
    group_by(index) %>%
    summarize(across(c(first_column, second_column), ~ mean(.x, na.rm = TRUE))) %>%
    mutate(type = name) %>%
    print()
}

现在,我可以遍历一个列表:

x <- list()
for (i in names(list1)) {
   ps <- output_mean(list1[[i]], i)
   x[[paste0(i)]] <- ps
  }

#> # A tibble: 2 x 4
#>   index first_column second_column type 
#>   <dbl>        <dbl>         <dbl> <chr>
#> 1     1          1.5           5.5 df1a 
#> 2     2          3.5           7.5 df1a 
#> # A tibble: 2 x 4
#>   index first_column second_column type 
#>   <dbl>        <dbl>         <dbl> <chr>
#> 1     1            3             7 df1b 
#> 2     2            2             6 df1b

然后我可以将结果放入一个数据框中:

all1 <- do.call(rbind, x)
all1
#> # A tibble: 4 x 4
#>   index first_column second_column type 
#> * <dbl>        <dbl>         <dbl> <chr>
#> 1     1          1.5           5.5 df1a 
#> 2     2          3.5           7.5 df1a 
#> 3     1          3             7   df1b 
#> 4     2          2             6   df1b

但是如果我想将 list1list2 放入 big_list 并循环遍历它怎么办? 这是我尝试过的:

big_list <- list(list1, list2)

y <- list()
for (j in big_list){
  x <- list()
    for (i in names(j)) {
       ps <- output_mean(j[[i]], i)
       x[[paste0(i)]] <- ps
      }

  all = do.call(rbind, x)
}

循环有效,但是只有两个数据帧被附加到 all 中,这是可以理解的,因为外循环覆盖了 all

all
#> # A tibble: 4 x 4
#>   index first_column second_column type 
#> * <dbl>        <dbl>         <dbl> <chr>
#> 1     1          3.5           7.5 df2a 
#> 2     2          1.5           5.5 df2a 
#> 3     1          5             3.5 df2b 
#> 4     2          5.5           4   df2b

我尝试了很多不同的方法,但我无法将四个数据帧附加到一个 4 x 8 的数据帧中。

reprex package (v2.0.0) 于 2021 年 5 月 6 日创建

2 个答案:

答案 0 :(得分:1)

我们可以用 length 初始化 'y' 与 lengthbig_list 相同,循环遍历 'big_list' 的序列,(初始化 'x' 也可能更好使用内部列表的 length

y <- vector('list', length(big_list))
for (j in seq_along(big_list)){
  x <- list()
    for (i in seq_along(big_list[[j]])) {
       ps <- output_mean(big_list[[j]][[i]], names(big_list[[j]])[i])
       x[[i]] <- ps
      }

  y[[j]]  <- do.call(rbind, x)
}

 out <- do.call(rbind, y)

-输出

out
# A tibble: 8 x 4
#  index first_column second_column type 
#  <dbl>        <dbl>         <dbl> <chr>
#1     1          1.5           5.5 df1a 
#2     2          3.5           7.5 df1a 
#3     1          3             7   df1b 
#4     2          2             6   df1b 
#5     1          3.5           7.5 df2a 
#6     2          1.5           5.5 df2a 
#7     1          5             3.5 df2b 
#8     2          5.5           4   df2b 

使用 map

可以更轻松地完成此操作
library(purrr)
out1 <- map_dfr(big_list, ~ imap_dfr(.x, ~ output_mean(.x, .y)))

-输出

out1
# A tibble: 8 x 4
#  index first_column second_column type 
#  <dbl>        <dbl>         <dbl> <chr>
#1     1          1.5           5.5 df1a 
#2     2          3.5           7.5 df1a 
#3     1          3             7   df1b 
#4     2          2             6   df1b 
#5     1          3.5           7.5 df2a 
#6     2          1.5           5.5 df2a 
#7     1          5             3.5 df2b 
#8     2          5.5           4   df2b 

答案 1 :(得分:1)

我建议将 big_list 存储为串联列表而不是嵌套列表。

big_list <- c(list1, list2)

如果您这样做,您的原始代码将按原样运行 -

y <- list()
for (i in names(big_list)) {
    ps <- output_mean(big_list[[i]], i)
    y[[paste0(i)]] <- ps
}

all = do.call(rbind, y)
all

#  index first_column second_column type 
#*  <dbl>        <dbl>         <dbl> <chr>
#1     1          1.5           5.5 df1a 
#2     2          3.5           7.5 df1a 
#3     1          3             7   df1b 
#4     2          2             6   df1b 
#5     1          3.5           7.5 df2a 
#6     2          1.5           5.5 df2a 
#7     1          5             3.5 df2b 
#8     2          5.5           4   df2b 

使用 purrr 也更容易应用该函数:

purrr::imap_dfr(big_list, output_mean)

和基础 R :

do.call(rbind, Map(output_mean, big_list, names(big_list)))