मान लीजिए कि आप बस पहले से data.frame का आकार नहीं जानते हैं। यह अच्छी तरह से कुछ पंक्तियों, या कुछ लाखों हो सकता है। आपको किसी प्रकार के कंटेनर की आवश्यकता होती है, जो गतिशील रूप से बढ़ता है। मेरे अनुभव और एसओ में सभी संबंधित उत्तरों को ध्यान में रखते हुए मैं 4 अलग-अलग समाधानों के साथ आता हूं:
rbindlist
डेटा.फ्रेम के लिए
जरूरत है data.table
तेजी से set
ऑपरेशन का उपयोग करें और जरूरत पड़ने पर तालिका को मैन्युअल रूप से दोगुना करने के साथ इसे जोड़े।
RSQLite
स्मृति में रखी गई तालिका का उपयोग और परिशिष्ट।
data.frame
डेटा को संग्रहीत करने के लिए कस्टम वातावरण (जिसमें संदर्भ शब्दार्थ है) को विकसित करने और उपयोग करने की अपनी क्षमता है। इसलिए इसे रिटर्न पर कॉपी नहीं किया जाएगा।
यहां छोटी और बड़ी संख्या में दोनों प्रकार की पंक्तियों के लिए सभी तरीकों का परीक्षण किया गया है। प्रत्येक विधि में इसके साथ जुड़े 3 कार्य हैं:
create(first_element)
first_element
पुट के साथ उपयुक्त समर्थन वस्तु लौटाता है।
append(object, element)
यह element
तालिका के अंत में प्रस्तुत होता है (द्वारा दर्शाया गया है object
)।
access(object)
data.frame
सभी सम्मिलित तत्वों के साथ मिलता है ।
rbindlist
डेटा.फ्रेम के लिए
यह काफी आसान और सीधा है:
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
+ जरूरत पड़ने पर मैन्युअल रूप से तालिका को दोगुना करना।
मैं तालिका की वास्तविक लंबाई को एक rowcount
विशेषता में संग्रहीत करूंगा ।
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,]))
}
एसक्यूएल को तेज रिकॉर्ड प्रविष्टि के लिए अनुकूलित किया जाना चाहिए, इसलिए मुझे शुरू में RSQLite
समाधान के लिए उच्च उम्मीदें थीं
यह मूल रूप से इसी तरह के धागे पर कार्स्टन डब्ल्यू के उत्तर की कॉपी और पेस्ट है ।
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.frame
अपने स्वयं के रो-अपिंग + कस्टम वातावरण।
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)
}
परीक्षण सूट:
सुविधा के लिए मैं एक परीक्षण फ़ंक्शन का उपयोग उन सभी को अप्रत्यक्ष कॉलिंग के साथ कवर करने के लिए करूंगा। (मैंने जाँच की: do.call
सीधे कार्यों को कॉल करने के बजाय कोड का उपयोग करने से कोड चलाने योग्य नहीं रह जाता है)।
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 सम्मिलन के लिए प्रदर्शन देखें।
मैंने एक 'प्लेसीबो' फ़ंक्शंस (प्रत्यय के साथ 0
) भी जोड़ा है जो कुछ भी प्रदर्शन नहीं करता है - सिर्फ टेस्ट सेटअप के ओवरहेड को मापने के लिए।
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 पंक्तियों के लिए (Intel (R) Core (TM) i7-4710HQ CPU @ 2.50GHz पर किए गए माप):
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- आधारित कमजोर पड़ने जैसा दिखता है, हालांकि बड़े डेटा पर कुछ गति प्राप्त करता है, डेटाटैब + मैनुअल घातीय वृद्धि कहीं नहीं है। अंतर परिमाण के लगभग दो क्रम है!
सारांश
यदि आप जानते हैं कि आप छोटी संख्या में पंक्तियों को जोड़ेंगे (n <= 100), तो आगे बढ़ें और सबसे सरल संभव समाधान का उपयोग करें: बस डेटा को पंक्तियों को असाइन करें। ब्रैकेट नोटेशन का उपयोग करके और इस तथ्य को अनदेखा करें कि डेटा.फ्रेम है पहले से आबाद नहीं।
बाकी सब के data.table::set
लिए डेटा का उपयोग करें और विकसित करें। तेजी से (जैसे मेरे कोड का उपयोग करके)।