Как указывалось в комментариях к OP, лучше всего сделать большой список, а затем связать все в конце. Это использует lapply()
вместо явного l oop, за которым следует 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)
Теперь, если мы нацеливаемся на этот конкретный пример, требуя al oop, мы также можем использовать пару альтернатив , Например, вместо увеличения списка фреймов данных мы знаем, что каждая итерация приведет к целому числу. Таким образом, мы могли бы просто предварительно выделить целочисленные векторы, которые также легко перевести в r cpp:
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)
Производительность: R cpp, что неудивительно, самый быстрый подход. Но использование data.table::rbindlist
или dplyr::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)
)