【问题标题】:r: looping through a list of lists and appending the results to a data framer:循环遍历列表并将结果附加到数据框
【发布时间】:2021-07-29 07:17:11
【问题描述】:

我有以下列表,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-05-06 创建

【问题讨论】:

    标签: r list for-loop


    【解决方案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)))
    

    【讨论】:

      【解决方案2】:

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

      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 
      

      【讨论】:

      • 谢谢,但正如您所见,type 应该是数据框的名称(df1adf1b 等),并且所有数据框应该以 4 x 8 的形式附加在一起数据框。对不起,如果我不清楚。
      • @Emy 你的意思是更新后的输出
      • 几乎,我希望它们在一个数据框中组合在一起。感谢您的帮助。
      • @Emy 我添加了一个更紧凑的版本map/imap
      • 看起来很棒,谢谢!有什么建议可以进一步了解listsmap/imap
      猜你喜欢
      • 1970-01-01
      • 2021-10-11
      • 2018-10-28
      • 2019-08-20
      • 1970-01-01
      • 2021-08-04
      • 2021-02-08
      • 2018-09-28
      • 2016-07-24
      相关资源
      最近更新 更多