Comme l'a suggéré l'OP dans les commentaires, la meilleure chose à faire est de dresser une grande liste et de tout lier à la fin. Cela permet d'utiliser lapply()
au lieu d'une boucle explicite suivie par 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)
Maintenant, si nous ciblons cet exemple particulier tout en exigeant une boucle, nous pouvons également utiliser quelques alternatives. Par exemple, au lieu de faire croître une liste d'images de données, nous savons que chaque itération aboutira à un entier. Par conséquent, nous pourrions simplement pré-allouer des vecteurs d'entiers, ce qui est également facile à traduire en rcpp :
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));
}
')
De même, il y a beaucoup de frais généraux pour les data.frame
appels. dplyr::bind_rows()
y data.table::rbindlist()
par défaut data.frame
type de résultats pour 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)
Performance : Rcpp est sans surprise l'approche la plus rapide. Mais l'utilisation de data.table::rbindlist
ou dplyr::bind_rows
avec une liste est une approche assez simple.
### 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)
)