gpt4 book ai didi

r - 在循环中将 data.frame 行绑定(bind)到另一个 data.frame 的有效方法?

转载 作者:行者123 更新时间:2023-12-03 22:01:56 26 4
gpt4 key购买 nike

我知道在循环中附加到向量或列表的最节省内存的方法是 preallocate那个向量/列表,在分配给它的索引之前。

问题:

在循环中将 data.frames 绑定(bind)到另一个的内存(和时间)效率最高的方法是什么? (注意:最终,我追求的是在一个循环中绑定(bind)大量大型数据帧的最有效、最明智的方法)

目前我所知道的:

我们可以使用标准的rbind,例如:

output <- data.frame(a=c(), b=c())

for(i in 1:1000) {
temp <- data.frame(a=c(i), b=c(i))
output <- rbind(output, temp)
}

或者 bind_rows():(should be faster)

library(dplyr)
output <- data.frame(a=c(), b=c())

for(i in 1:1000) {
temp <- data.frame(a=c(i), b=c(i))
output <- bind_rows(output, temp)
}

我不确定其中之一是否效率更高(例如对于长期/大型操作),也不确定是否有其他更有效的替代方案/最佳实践?

最佳答案

正如 OP 在评论中所建议的那样,最好的办法是制作一个大列表,然后在最后绑定(bind)所有内容。这使用 lapply() 而不是后跟 do.call(rbind, tmp) 的显式循环:

n = 1000
tmp = lapply(seq_len(n), function(i) data.frame(a = i, b = i))
output = do.call(rbind, tmp)
## or
output = dplyr::bind_rows(tmp)
## or
output = data.table::rbindlist(tmp)

现在,如果我们在需要循环的同时针对这个特定示例,我们还可以使用几个替代方案。例如,我们知道每次迭代都会产生一个整数,而不是增加数据帧列表。因此,我们可以简单地预先分配整数向量,这也很容易转换为 。 :

n = 1000L
a = b = integer(n)
for (i in seq_len(n)) {
a[i] = b[i] = i
}
data.frame(a = a, b = b)

## or with Rcpp:
rcpp_new_loop = Rcpp::cppFunction(code =
'DataFrame rcpp_new_loop(int n) {
IntegerVector a(n);
IntegerVector b(n);

for (int i = 0; i < n; i++) {
a(i) = b(i) = i + 1;
}
return(DataFrame::create(Named("a") = a, _["b"] = b));
}
')

同样,data.frame调用也有很多开销。 dplyr::bind_rows()data.table::rbindlist() 默认为 data.frame lists< 的结果类型:

tmp = lapply(seq_len(n), function(i) list(a = i, b = i))

##data.table
output = rbindlist(tmp)
setDF(output)

##dplyr
output = bind_rows(tmp)
as.data.frame(output)

性能:不出所料,Rcpp 是最快的方法。但是将 data.table::rbindlistdplyr::bind_rows 与列表一起使用是一种非常简单的方法。

### n = 1,000 
# A tibble: 9 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1 OP 378.18ms 379.92ms 2.63 15.7MB 2.63 2 2 760ms
2 do_call 254.76ms 254.89ms 3.92 220.7KB 5.88 2 3 510ms
3 bind_rows_df 196.69ms 202.48ms 4.94 16.9KB 3.29 3 2 607ms
4 dt_df 179.41ms 184.76ms 4.52 32.8KB 3.01 3 2 664ms
5 bind_rows_list 2.74ms 2.81ms 321. 16.9KB 3.98 161 2 502ms
6 new_loop 2.56ms 2.63ms 342. 17.6KB 4.00 171 2 500ms
7 dt_list 1.33ms 1.35ms 525. 32.8KB 3.99 263 2 501ms
8 new_loop_fx(n) 270.2us 280.5us 2188. 11.8KB 4.00 1094 2 500ms
9 rcpp_new_loop(n) 217.4us 228.3us 3872. 10.4KB 4.00 1936 2 500ms

### n = 10,000
# A tibble: 9 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1 OP 5.69s 5.69s 0.176 1.51GB 5.80 1 33 5.69s
2 do_call 2.67s 2.67s 0.374 2.2MB 3.74 1 10 2.67s
3 bind_rows_df 1.92s 1.92s 0.520 157.52KB 4.16 1 8 1.92s
4 dt_df 2.25s 2.25s 0.444 243.77KB 4.44 1 10 2.25s
5 bind_rows_list 30.73ms 34.57ms 28.5 157.75KB 3.81 15 2 525.49ms
6 new_loop 3.64ms 3.79ms 238. 123.07KB 3.99 119 2 500.85ms
7 dt_list 14.68ms 17.98ms 49.8 243.77KB 5.98 25 3 502ms
8 new_loop_fx(n) 1.2ms 1.24ms 691. 117.28KB 7.99 346 4 500.55ms
9 rcpp_new_loop(n) 299.5us 313.3us 2818. 80.66KB 4.00 1409 2 499.96ms

##code to reproduce::
library(data.table)
library(dplyr)

n = 1000L

new_loop_fx = function(n){
a = b = integer(n)
for (i in seq_len(n)) {
a[i] = b[i] = i
}
data.frame(a = a, b = b)
}

rcpp_new_loop = Rcpp::cppFunction(code =
'DataFrame rcpp_new_loop(int n) {
IntegerVector a(n);
IntegerVector b(n);

for (int i = 0; i < n; i++) {
a(i) = b(i) = i + 1;
}
return(DataFrame::create(Named("a") = a, _["b"] = b));
}
')

bench::mark(
OP = {
output <- data.frame(a=c(), b=c())

for(i in seq_len(n)) {
temp <- data.frame(a=i, b=i)
output <- rbind(output, temp)
}
output
}
,
do_call = {
tmp = lapply(seq_len(n), function(i) data.frame(a = i, b = i))
output = do.call(rbind, tmp)
}
,
bind_rows_df = {
tmp = lapply(seq_len(n), function(i) data.frame(a = i, b = i))
output = bind_rows(tmp)
as.data.frame(output)
}
,
dt_df = {
tmp = lapply(seq_len(n), function(i) data.frame(a = i, b = i))
output = rbindlist(tmp)
setDF(output)
}
,
bind_rows_list = {
tmp = lapply(seq_len(n), function(i) list(a = i, b = i))
output = bind_rows(tmp)
as.data.frame(output)
}
,
new_loop = {
a = b = integer(n)
for (i in seq_len(n)){
a[i] = b[i] = i
}
data.frame(a = a, b = b)
}
,
dt_list = {
tmp = lapply(seq_len(n), function(i) list(a = i, b = i))
output = rbindlist(tmp)
setDF(output)
}

,
new_loop_fx(n),
rcpp_new_loop(n)
)

关于r - 在循环中将 data.frame 行绑定(bind)到另一个 data.frame 的有效方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60865434/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com