【问题标题】:Very simple yet confusing R question about bind_rows()关于 bind_rows() 的非常简单但令人困惑的 R 问题
【发布时间】:2021-06-25 20:35:43
【问题描述】:

我正在尝试使用 bind_rows 将多个数据帧组合成一个数据帧。每个数据框具有相同的列名和长度。假设每个数据帧都命名为“df”,其中有 100 个。所以 df1, df2, df3... df100。

我不想将函数中的每个数据帧都写为 bind_rows(df1, df2 ... df100)。我试过了

total_df <- bind_rows(paste0(df1:df100))

它没有工作。有没有更简单的方法来做到这一点?谢谢!!

【问题讨论】:

  • purrr::reduce() 如果所有 dfs 都存储在列表中,则可以解决问题。如果它们是单独存储的,则必须将它们收集在一个列表中。
  • 似乎问题的本质是在没有明确命名的情况下将许多数据帧放入列表中......这可能会有所帮助:stackoverflow.com/questions/17499013/…
  • 考虑发布您用于创建数据框的代码。通过从一开始就将数据读入 df 列表,可以改进它。

标签: r dplyr


【解决方案1】:

更简单的方法是通过使用列表从一开始就避免使用一堆名为 df1, ..., df100 的数据帧。是因为它可能。您可以使用lapplyget 将您的df 放入一个列表并在列表上调用bind_rows

library(dplyr)

df1 <- mtcars
df2 <- mtcars
df3 <- mtcars

df_bind <- lapply(1:3, function(x) get(paste0("df", x))) %>% 
  bind_rows()

head(df_bind)
#>                        mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4...1         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag...2     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710...3        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> Hornet 4 Drive...4    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> Hornet Sportabout...5 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> Valiant...6           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

或者使用mget 你可以这样做

mget(paste0("df", 1:3)) %>% bind_rows()

【讨论】:

  • mget %>% bind_rows 绝对是这里的路。
【解决方案2】:
library(tidyverse)

#generate some data
rerun(10, iris) %>% 
    walk2(str_c('df', 1:length(.)), ~assign(.y, .x, pos = .GlobalEnv))

map(str_c('df', 1:10), ~ eval(sym(.x))) %>%
    reduce(bind_rows) %>%
    as_tibble() #to avoid console flooding
#> # A tibble: 1,500 x 5
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#>  1          5.1         3.5          1.4         0.2 setosa 
#>  2          4.9         3            1.4         0.2 setosa 
#>  3          4.7         3.2          1.3         0.2 setosa 
#>  4          4.6         3.1          1.5         0.2 setosa 
#>  5          5           3.6          1.4         0.2 setosa 
#>  6          5.4         3.9          1.7         0.4 setosa 
#>  7          4.6         3.4          1.4         0.3 setosa 
#>  8          5           3.4          1.5         0.2 setosa 
#>  9          4.4         2.9          1.4         0.2 setosa 
#> 10          4.9         3.1          1.5         0.1 setosa 
#> # … with 1,490 more rows

#if all the df's are inside a list

data <- rerun(10, iris)

reduce(data, bind_rows) %>% 
    as_tibble()
#> # A tibble: 1,500 x 5
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#>  1          5.1         3.5          1.4         0.2 setosa 
#>  2          4.9         3            1.4         0.2 setosa 
#>  3          4.7         3.2          1.3         0.2 setosa 
#>  4          4.6         3.1          1.5         0.2 setosa 
#>  5          5           3.6          1.4         0.2 setosa 
#>  6          5.4         3.9          1.7         0.4 setosa 
#>  7          4.6         3.4          1.4         0.3 setosa 
#>  8          5           3.4          1.5         0.2 setosa 
#>  9          4.4         2.9          1.4         0.2 setosa 
#> 10          4.9         3.1          1.5         0.1 setosa 
#> # … with 1,490 more rows

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

编辑:使用!!! (bang-bang-bang) 的另一种方式。

.args <- str_c('df', 1:10) %>%
    map(~eval(sym(.x)))

bind_rows(!!!.args) %>% 
    as_tibble()
#> # A tibble: 1,500 x 5
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>  
#>  1          5.1         3.5          1.4         0.2 setosa 
#>  2          4.9         3            1.4         0.2 setosa 
#>  3          4.7         3.2          1.3         0.2 setosa 
#>  4          4.6         3.1          1.5         0.2 setosa 
#>  5          5           3.6          1.4         0.2 setosa 
#>  6          5.4         3.9          1.7         0.4 setosa 
#>  7          4.6         3.4          1.4         0.3 setosa 
#>  8          5           3.4          1.5         0.2 setosa 
#>  9          4.4         2.9          1.4         0.2 setosa 
#> 10          4.9         3.1          1.5         0.1 setosa 
#> # … with 1,490 more rows

【讨论】:

    【解决方案3】:

    我喜欢使用带有idcol 参数的data.table 函数rbindlist。这将向您显示该行在绑定之前来自的源表/df。

    我也喜欢rbindlist,因为它可以让您选择使用fill = TRUE 添加/缺失一些列来填充绑定表。

    library(data.table)
    
    df1 <- mtcars 
    df2 <- mtcars 
    df3 <- mtcars 
        
    # Assuming your files are in working memory and have a common naming convention #
    my_mem_objects <- lapply(ls(pattern = "df"), get)
    
    # Assign names of the list to the same name they had as memory objects
    names(my_mem_objects) <- ls(pattern = "df")
    
    # Combine the dataframes and retain the name of each object the output as new column
    alldata <- rbindlist(my_mem_objects,idcol = "Source_DF")
    
    head(alldata)
    tail(alldata)
    

    给出这个输出:

       Source_DF  mpg cyl disp  hp drat    wt  qsec vs am gear carb
    1:         1 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
    2:         1 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
    3:         1 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
    4:         1 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
    5:         1 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
    6:         1 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
    

    和:

       Source_DF  mpg cyl  disp  hp drat    wt qsec vs am gear carb
    1:         3 26.0   4 120.3  91 4.43 2.140 16.7  0  1    5    2
    2:         3 30.4   4  95.1 113 3.77 1.513 16.9  1  1    5    2
    3:         3 15.8   8 351.0 264 4.22 3.170 14.5  0  1    5    4
    4:         3 19.7   6 145.0 175 3.62 2.770 15.5  0  1    5    6
    5:         3 15.0   8 301.0 335 3.54 3.570 14.6  0  1    5    8
    6:         3 21.4   4 121.0 109 4.11 2.780 18.6  1  1    4    2
    

    【讨论】:

    • 这类似于这个问题的另一个答案,它没有满足提问者的需求。提问者试图弄清楚如何避免在他们的环境中手动输入 100 个 data.frames 的名称的问题:out &lt;- bind_rows(df1, df2, df3, df4, ..., df50, df51, df52, ..., df98, df99, df100)
    • 谢谢@Andrew。我没有仔细阅读。我在编辑中以一种方式解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-14
    • 2017-12-05
    • 2015-10-09
    • 1970-01-01
    • 2016-02-09
    • 1970-01-01
    相关资源
    最近更新 更多