Diyelim ki data.frame'in boyutunu önceden bilmiyorsunuz. Birkaç sıra veya birkaç milyon olabilir. Dinamik olarak büyüyen bir tür konteynere ihtiyacınız var. SO'daki deneyimlerimi ve ilgili tüm cevapları dikkate alarak 4 farklı çözümle geliyorum:
rbindlist data.frame'e
data.tableHızlı setçalışmayı kullanın ve gerektiğinde masayı manuel olarak ikiye katlayarak birleştirin.
RSQLiteHafızada tutulan tabloyu kullanın ve ekleyin.
data.frameData.frame'i saklamak için özel ortamı (referans semantiğine sahip) büyütme ve kullanma becerisi, böylece geri dönüşte kopyalanmayacaktır.
Burada, hem küçük hem de çok sayıda eklenen satırlar için tüm yöntemlerin bir testi bulunmaktadır. Her yöntemin kendisiyle ilişkili 3 işlevi vardır:
create(first_element)bu, yerleştirilmiş uygun destek nesnesini döndürür first_element.
append(object, element)elementtablonun sonuna ekler (ile temsil edilir object).
access(object)data.frameeklenen tüm öğelerle birlikte alır .
rbindlist data.frame'e
Bu oldukça kolay ve anlaşılırdır:
create.1<-function(elems)
{
return(as.data.table(elems))
}
append.1<-function(dt, elems)
{
return(rbindlist(list(dt, elems),use.names = TRUE))
}
access.1<-function(dt)
{
return(dt)
}
data.table::set + gerektiğinde masayı manuel olarak ikiye katlama.
Tablonun gerçek uzunluğunu bir rowcountöznitelikte saklayacağım .
create.2<-function(elems)
{
return(as.data.table(elems))
}
append.2<-function(dt, elems)
{
n<-attr(dt, 'rowcount')
if (is.null(n))
n<-nrow(dt)
if (n==nrow(dt))
{
tmp<-elems[1]
tmp[[1]]<-rep(NA,n)
dt<-rbindlist(list(dt, tmp), fill=TRUE, use.names=TRUE)
setattr(dt,'rowcount', n)
}
pos<-as.integer(match(names(elems), colnames(dt)))
for (j in seq_along(pos))
{
set(dt, i=as.integer(n+1), pos[[j]], elems[[j]])
}
setattr(dt,'rowcount',n+1)
return(dt)
}
access.2<-function(elems)
{
n<-attr(elems, 'rowcount')
return(as.data.table(elems[1:n,]))
}
Hızlı kayıt ekleme için SQL optimize edilmelidir, bu nedenle başlangıçta büyük umutlarım vardı RSQLite çözüm
Bu temelde Karsten W. yanıtının benzer konuya kopyalanması ve yapıştırılmasıdır .
create.3<-function(elems)
{
con <- RSQLite::dbConnect(RSQLite::SQLite(), ":memory:")
RSQLite::dbWriteTable(con, 't', as.data.frame(elems))
return(con)
}
append.3<-function(con, elems)
{
RSQLite::dbWriteTable(con, 't', as.data.frame(elems), append=TRUE)
return(con)
}
access.3<-function(con)
{
return(RSQLite::dbReadTable(con, "t", row.names=NULL))
}
data.framekendi satır ekleme + özel ortamı.
create.4<-function(elems)
{
env<-new.env()
env$dt<-as.data.frame(elems)
return(env)
}
append.4<-function(env, elems)
{
env$dt[nrow(env$dt)+1,]<-elems
return(env)
}
access.4<-function(env)
{
return(env$dt)
}
Test paketi:
Kolaylık sağlamak için, hepsini dolaylı aramayla kapsayacak şekilde bir test işlevi kullanacağım. (Kontrol ettim: do.callişlevleri doğrudan çağırmak yerine kullanmak kodun daha uzun süre ölçülebilir çalışmasını sağlamaz).
test<-function(id, n=1000)
{
n<-n-1
el<-list(a=1,b=2,c=3,d=4)
o<-do.call(paste0('create.',id),list(el))
s<-paste0('append.',id)
for (i in 1:n)
{
o<-do.call(s,list(o,el))
}
return(do.call(paste0('access.', id), list(o)))
}
N = 10 eklemenin performansını görelim.
Ayrıca 0hiçbir şey yapmayan bir 'plasebo' işlevi (son ekli ) ekledim - sadece test kurulumunun ek yükünü ölçmek için.
r<-microbenchmark(test(0,n=10), test(1,n=10),test(2,n=10),test(3,n=10), test(4,n=10))
autoplot(r)


1E5 satırları için (ölçümler Intel (R) Core (TM) i7-4710HQ CPU @ 2.50GHz'de yapılmıştır):
nr function time
4 data.frame 228.251
3 sqlite 133.716
2 data.table 3.059
1 rbindlist 169.998
0 placebo 0.202
SQLite tabanlı sulandırma, büyük verilerde bir miktar hız kazanmasına rağmen, data.table + manuel üstel büyümeye yakın değil gibi görünüyor. Aradaki fark neredeyse iki kat büyüklüğündedir!
özet
Oldukça az sayıda satır ekleyeceğinizi biliyorsanız (n <= 100), devam edin ve mümkün olan en basit çözümü kullanın: satırları parantez gösterimini kullanarak data.frame'e atayın ve data.frame'in önceden doldurulmamış.
Diğer her şey data.table::setiçin data.table'ı üssel olarak kullanın ve büyütün (örneğin benim kodumu kullanarak).