R中的rbind()和bind_rows()之间的区别

时间:2017-03-19 13:34:38

标签: r rbind

在网络上,我发现 rbind() 用于组合两个数据框,同一任务由 bind_rows() 功能执行。

然后我不明白这两个函数之间有什么区别,哪个更有效?

3 个答案:

答案 0 :(得分:23)

除了更多的差异之外,使用bind_rows超过rbind的主要原因之一是组合具有不同列数的两个数据帧。在这种情况下,rbind会引发错误,而bind_rows会指定" NA"到数据帧中没有提供值的数据帧中缺少的那些行列。

尝试使用以下代码来查看差异:

a <- data.frame(a = 1:2, b = 3:4, c = 5:6)
b <- data.frame(a = 7:8, b = 2:3, c = 3:4, d = 8:9)

两个电话的结果如下:

rbind(a, b)
> rbind(a, b)
Error in rbind(deparse.level, ...) : 
  numbers of columns of arguments do not match
library(dplyr)
bind_rows(a, b)
> bind_rows(a, b)
  a b c  d
1 1 3 5 NA
2 2 4 6 NA
3 7 2 3  8
4 8 3 4  9

答案 1 :(得分:1)

虽然bind_rows()在将合并具有不同列数的数据帧(将NA分配给缺少这些列的行的意义上)更有用,但是如果您要合并具有相同列的数据帧列,我建议使用rbind()

如果要合并的数据采用相同的格式设置,

rbind() 计算效率更高,并且当列数不同时,它只会引发错误。大数据集将为您节省大量时间。对于这些情况,我强烈建议rbind()。但是,如果数据具有不同的列,则必须使用bind_rows()

答案 2 :(得分:1)

由于此处没有答案可以对base::rbinddplyr::bind_rows之间的差异进行系统的回顾,并且kss关于性能的答案不正确,因此我决定添加以下内容。

我们有一些测试数据框架:

df_1 = data.frame(
  v1_dbl = 1:1000,
  v2_lst = I(as.list(1:1000)),
  v3_fct = factor(sample(letters[1:10], 1000, replace = TRUE)),
  v4_raw = raw(1000),
  v5_dtm = as.POSIXct(paste0("2019-12-0", sample(1:9, 1000, replace = TRUE)))
)

df_1$v2_lst = unclass(df_1$v2_lst) #remove the AsIs class introduced by `I()`

1。 base::rbind以不同方式处理列表输入

rbind(list(df_1, df_1))
     [,1]   [,2]  
[1,] List,5 List,5

# You have to combine it with `do.call()` to achieve the same result:
head(do.call(rbind, list(df_1, df_1)), 3)
  v1_dbl v2_lst v3_fct v4_raw     v5_dtm
1      1      1      b     00 2019-12-02
2      2      2      h     00 2019-12-08
3      3      3      c     00 2019-12-09

head(dplyr::bind_rows(list(df_1, df_1)), 3)
  v1_dbl v2_lst v3_fct v4_raw     v5_dtm
1      1      1      b     00 2019-12-02
2      2      2      h     00 2019-12-08
3      3      3      c     00 2019-12-09

2。 base::rbind可以应付(某些)混合类型

base::rbinddplyr::bind_rows都在尝试绑定时失败,例如将原始列或日期时间列更改为其他类型的列,base::rbind可以解决一定程度的差异。

将列表和非列表列组合会产生一个列表列。将一个因素与其他因素结合会产生警告,但不会产生错误:

df_2 = data.frame(
  v1_dbl = 1,
  v2_lst = 1,
  v3_fct = 1,
  v4_raw = raw(1),
  v5_dtm = as.POSIXct("2019-12-01")
)

head(rbind(df_1, df_2), 3)
  v1_dbl v2_lst v3_fct v4_raw     v5_dtm
1      1      1      b     00 2019-12-02
2      2      2      h     00 2019-12-08
3      3      3      c     00 2019-12-09
Warning message:
In `[<-.factor`(`*tmp*`, ri, value = 1) : invalid factor level, NA generated

# Fails on the lst, num combination:
head(dplyr::bind_rows(df_1, df_2), 3)
Error: Column `v2_lst` can't be converted from list to numeric

# Fails on the fct, num combination:
head(dplyr::bind_rows(df_1[-2], df_2), 3)
Error: Column `v3_fct` can't be converted from factor to numeric

3。 base::rbind保留行名

Tidyverse提倡将行名放入专用列中,因此其功能将其删除。

rbind(mtcars[1:2, 1:4], mtcars[3:4, 1:4])
                mpg cyl disp  hp
Mazda RX4      21.0   6  160 110
Mazda RX4 Wag  21.0   6  160 110
Datsun 710     22.8   4  108  93
Hornet 4 Drive 21.4   6  258 110

dplyr::bind_rows(mtcars[1:2, 1:4], mtcars[3:4, 1:4])
   mpg cyl disp  hp
1 21.0   6  160 110
2 21.0   6  160 110
3 22.8   4  108  93
4 21.4   6  258 110

4。 base::rbind无法解决缺少的列

仅出于完整性考虑,因为Abhilash Kandwal已在回答中如此表示。

5。 base::rbind以不同方式处理命名参数

虽然base::rbind在行名前加上参数名,但是dplyr::rbind可以选择添加专用ID列:

rbind(hi = mtcars[1:2, 1:4], bye = mtcars[3:4, 1:4])
                    mpg cyl disp  hp
hi.Mazda RX4       21.0   6  160 110
hi.Mazda RX4 Wag   21.0   6  160 110
bye.Datsun 710     22.8   4  108  93
bye.Hornet 4 Drive 21.4   6  258 110

dplyr::bind_rows(hi = mtcars[1:2, 1:4], bye = mtcars[3:4, 1:4], .id = "my_id")
  my_id  mpg cyl disp  hp
1    hi 21.0   6  160 110
2    hi 21.0   6  160 110
3   bye 22.8   4  108  93
4   bye 21.4   6  258 110

6。 base::rbind将向量参数分成行(并回收它们)

相反,dplyr::bind_rows添加列(因此需要命名x的元素):

rbind(mtcars[1:2, 1:4], x = 1:2))
              mpg cyl disp  hp
Mazda RX4      21   6  160 110
Mazda RX4 Wag  21   6  160 110
x               1   2    1   2

dplyr::bind_rows(mtcars[1:2, 1:4], x = c(a = 1, b = 2))
  mpg cyl disp  hp  a  b
1  21   6  160 110 NA NA
2  21   6  160 110 NA NA
3  NA  NA   NA  NA  1  2

7。 base::rbind较慢,需要更多RAM

要绑定一百个中等大小的数据帧(一千行),base::rbind需要多出50倍的RAM,并且要慢15倍以上:

dfs = rep(list(df_1), 100)
bench::mark(
  "base::rbind" = do.call(rbind, dfs),
  "dplyr::bind_rows" = dplyr::bind_rows(dfs)
)[, 1:5]

# A tibble: 2 x 5
  expression            min   median `itr/sec` mem_alloc
  <bch:expr>       <bch:tm> <bch:tm>     <dbl> <bch:byt>
1 base::rbind       47.23ms  48.05ms      20.0  104.48MB
2 dplyr::bind_rows   3.69ms   3.75ms     261.     2.39MB

由于我需要绑定许多小数据帧,因此这也是一个基准。两者的速度,尤其是RAM的差异非常惊人:

dfs = rep(list(df_1[1:2, ]), 10^4)
bench::mark(
  "base::rbind" = do.call(rbind, dfs),
  "dplyr::bind_rows" = dplyr::bind_rows(dfs)
)[, 1:5]

# A tibble: 2 x 5
  expression            min   median `itr/sec` mem_alloc
  <bch:expr>       <bch:tm> <bch:tm>     <dbl> <bch:byt>
1 base::rbind         1.65s    1.65s     0.605    1.56GB
2 dplyr::bind_rows  19.31ms  20.21ms    43.7    566.69KB

最后,help("rbind")help("bind_rows")也很有趣。