R डेटाफ्रेम पंक्ति-दर-पंक्ति बनाना


107

मैं आर में एक डेटाफ्रेम पंक्ति-दर-पंक्ति का निर्माण करना चाहता हूं। मैंने कुछ खोज की है, और सभी के साथ आया हूं एक खाली सूची बनाने का सुझाव है, एक सूची सूचकांक स्केलर रखें, फिर हर बार सूची में जोड़ें एकल-पंक्ति डेटाफ़्रेम और सूची सूचकांक को एक से आगे बढ़ाएं। अंत में, do.call(rbind,)सूची में।

जबकि यह काम करता है, यह बहुत बोझिल लगता है। क्या समान लक्ष्य प्राप्त करने का आसान तरीका नहीं है?

जाहिर है मैं उन मामलों का उल्लेख करता हूं जहां मैं कुछ applyफ़ंक्शन का उपयोग नहीं कर सकता हूं और स्पष्ट रूप से पंक्ति द्वारा डेटाफ्रेम पंक्ति बनाने की आवश्यकता है। कम से कम, क्या pushकिसी सूची के अंत में स्पष्ट रूप से उपयोग किए जाने वाले अंतिम सूचकांक का ट्रैक रखने के बजाय एक रास्ता है ?


1
आप append()[जिसे संभवतः सम्मिलित नाम दिया जाना चाहिए] या c()किसी सूची के अंत में आइटम जोड़ने के लिए उपयोग कर सकते हैं , हालांकि यहां आपकी मदद नहीं की जाएगी।
हैमेट्रिक्स

वहाँ अनुसंधान में कई कार्यों कि वापसी डेटा फ्रेम जब तक आप उन्हें वापस नहीं कर रहे हैं [पंक्ति-वार] से lapply(), Map(), और इतने पर है, लेकिन आप भी इस पर एक नज़र लेने के लिए चाहते हो सकता है aggregate(), dapply() {heR.Misc}और cast() {reshape}देखने के लिए अपने कार्यों को इन के द्वारा नियंत्रित नहीं किया जा सकता है, तो फ़ंक्शन (ये सभी डेटा फ़्रेम लौटाते हैं)।
हैमेट्रिक्स

जवाबों:


96

आप उन्हें जोड़कर या उपयोग करके पंक्ति से पंक्ति बढ़ा सकते हैं rbind()

इसका मतलब यह नहीं है कि आपको चाहिए। गतिशील रूप से बढ़ती संरचनाएं आर में कोड करने के लिए सबसे कम कुशल तरीकों में से एक है।

यदि आप अपना संपूर्ण डेटा आवंटित कर सकते हैं।

N <- 1e4  # total number of rows to preallocate--possibly an overestimate

DF <- data.frame(num=rep(NA, N), txt=rep("", N),  # as many cols as you need
                 stringsAsFactors=FALSE)          # you don't know levels yet

और फिर अपने ऑपरेशन के दौरान एक बार में पंक्ति डालें

DF[i, ] <- list(1.4, "foo")

वह मनमाने ढंग से डेटा.फ्रेम के लिए काम करना चाहिए और बहुत अधिक कुशल होना चाहिए। यदि आप N को ओवरशूट करते हैं तो आप हमेशा खाली पंक्तियों को अंत में सिकोड़ सकते हैं।


6
क्या आपका मतलब 10 के बजाय N नहीं रखा गया था, और c (1.4, "foo") के बजाय लिस्ट (1.4, "foo") का इस्तेमाल किया गया था ताकि 1.4 को कैरेक्टर मोड में न डाला जाए?
हैमेट्रिक्स

हां, मेरा मतलब डेटा.फ्रेम निर्माण में एन का उपयोग करना था। इसके अलावा, बहुत अच्छी पकड़ चैट में जोर-जबरदस्ती करती है - मुझे वह याद नहीं था।
डिर्क एडल्डबुलेटेल

1
उत्तर को संपादित करने से बेहतर होगा कि इसे टिप्पणियों में छोड़ दें। मैं इस जवाब को टटोलने में उलझन में था।
यूजर

4
data.tableडेटा-वर्कफ़्लो का उपयोग करके पूर्व-आवंटन से भी अधिक तेज़ प्रतीत होता है। यहाँ परीक्षण: stackoverflow.com/a/11486400/636656
अरी बी। फ्रीडमैन

क्या यह अभी भी आर 3.1 में सच है जहां यह तेज होना चाहिए?
userJT

49

एक पंक्तियों को जोड़ सकते हैं NULL:

df<-NULL;
while(...){
  #Some code that generates new row
  rbind(df,row)->df
}

उदाहरण के लिए

df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)

3
यह एक मैट्रिक्स को आउटपुट करता है, न कि डेटा फ्रेम
ओल्गा

1
@ ओल्गा केवल यदि आप एक समान प्रकार के तत्वों की पंक्तियों को बांधते हैं - तो उस स्थिति में बीटीडब्ल्यू sapply(या वेक्टर) बेहतर है और स्थानांतरित करें।
mbq

1
@mbq वास्तव में मैं क्या कर रहा हूँ। मैंने यह भी पाया कि यदि आप इसे df <-data.frame () के साथ आरंभ करते हैं, तो यह एक डेटा फ़्रेम आउटपुट करता है।
ओल्गा

9

यह कैसे उपयोग करने के लिए की एक मूर्खतापूर्ण उदाहरण है do.call(rbind,)के उत्पादन पर Map()[जो के समान है lapply()]

> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3))
> DF
  x y
1 1 2
2 2 3
3 3 4
> class(DF)
[1] "data.frame"

मैं इस निर्माण का उपयोग अक्सर करता हूं।


8

Rcpp मुझे बहुत पसंद है इसका कारण यह है कि मुझे हमेशा ऐसा नहीं लगता कि R Core कैसे सोचता है, और Rcpp के साथ, अधिक बार नहीं, मुझे नहीं करना है।

दार्शनिक रूप से बोलते हुए, आप कार्यात्मक प्रतिमान के संबंध में पाप की स्थिति में हैं, जो यह सुनिश्चित करने की कोशिश करता है कि हर मूल्य हर दूसरे मूल्य से स्वतंत्र प्रतीत होता है ; एक मान को बदलने से दूसरे मूल्य में कभी भी दृश्यमान परिवर्तन नहीं होना चाहिए, जिस तरह से आपको सी में प्रतिनिधित्व साझा करने के संकेत मिलते हैं।

समस्याएँ तब आती हैं जब कार्यात्मक प्रोग्रामिंग छोटे शिल्प को रास्ते से हटने का संकेत देती है, और छोटा शिल्प "मैं एक प्रकाशस्तंभ हूं" का उत्तर देता हूं। एक बड़े ऑब्जेक्ट के लिए छोटे बदलावों की एक लंबी श्रृंखला बनाना, जिसे आप इस बीच में प्रोसेस करना चाहते हैं, यह आपको लाइटहाउस क्षेत्र में वर्ग बनाता है।

C ++ STL में, push_back()जीवन का एक तरीका है। यह कार्यात्मक होने की कोशिश नहीं करता है, लेकिन यह सामान्य प्रोग्रामिंग मुहावरों को कुशलतापूर्वक समायोजित करने का प्रयास करता है ।

पर्दे के पीछे कुछ चतुराई के साथ, आप कभी-कभी प्रत्येक दुनिया में एक पैर रखने की व्यवस्था कर सकते हैं। स्नैपशॉट आधारित फाइल सिस्टम एक अच्छा उदाहरण है (जो यूनियन माउंट्स जैसी अवधारणाओं से विकसित हुआ है, जो दोनों पक्षों को प्लाई करता है)।

यदि आर कोर ऐसा करना चाहता था, तो अंतर्निहित वेक्टर भंडारण संघ माउंट की तरह कार्य कर सकता है। वेक्टर स्टोरेज का एक संदर्भ सब्सक्राइबर्स के लिए मान्य हो सकता है 1:N, जबकि उसी स्टोरेज का एक अन्य संदर्भ सब्सक्राइबर्स के लिए मान्य होता है 1:(N+1)। वहाँ आरक्षित भंडारण अभी तक वैध रूप से संदर्भित नहीं किया जा सकता है लेकिन एक त्वरित के लिए सुविधाजनक है push_back()। किसी भी मौजूदा संदर्भ को मान्य मानने वाली श्रेणी के बाहर जोड़ते समय आप कार्यात्मक अवधारणा का उल्लंघन नहीं करते हैं।

अंततः पंक्तियों को बढ़ाते हुए, आप आरक्षित संग्रहण से बाहर चले जाते हैं। आपको हर चीज की नई प्रतियां बनाने की आवश्यकता होगी, भंडारण के साथ कुछ वृद्धि से गुणा किया जाएगा। आवंटन का विस्तार करते समय मैंने जो STL कार्यान्वयन का उपयोग किया है, उनका संग्रहण 2 से गुणा करना है। मुझे लगा कि मैं आर इंटर्नल्स में पढ़ता हूं कि मेमोरी संरचना है जहां भंडारण में 20% की वृद्धि होती है। किसी भी तरह से, ग्रोथ ऑपरेशंस लॉगरिदमिक फ्रिक्वेंसी के साथ होते हैं, जो कुल संलग्न तत्वों की संख्या के सापेक्ष है। एक परिमित आधार पर, यह आमतौर पर स्वीकार्य है।

जैसे-जैसे पर्दे के पीछे की चाल चली जाती है, मैंने और बुरा देखा है। हर बार जब आप push_back()डेटाफ़्रेम पर एक नई पंक्ति बनाते हैं, तो एक शीर्ष स्तरीय सूचकांक संरचना को कॉपी करने की आवश्यकता होगी। नई पंक्ति किसी भी पुराने कार्यात्मक मूल्यों को प्रभावित किए बिना साझा प्रतिनिधित्व पर अपील कर सकती है। मुझे भी नहीं लगता कि यह कचरा इकट्ठा करने वाले को ज्यादा परेशान करेगा; चूँकि मैं push_front()सभी संदर्भों का प्रस्ताव नहीं कर रहा हूँ , वे आबंटित वेक्टर स्टोरेज के सामने के संदर्भ हैं।


2

डिर्क एडल्डबुलेट का जवाब सबसे अच्छा है; यहाँ मैं सिर्फ यह नोट करता हूं कि आप डेटाफ्रेम आयामों या डेटा प्रकारों को पूर्व-निर्दिष्ट नहीं कर सकते हैं, जो कभी-कभी उपयोगी होते हैं यदि आपके पास कई डेटा प्रकार और बहुत सारे कॉलम हैं:

row1<-list("a",1,FALSE) #use 'list', not 'c' or 'cbind'!
row2<-list("b",2,TRUE)  

df<-data.frame(row1,stringsAsFactors = F) #first row
df<-rbind(df,row2) #now this works as you'd expect.

क्या आपका मतलब था df<-rbind(df, row2)?
टिमोथी सी। क्विन

1

मैंने बिना मैट्रिक्स के कच्चे द्वारा डेटाफ्रेम बनाने का यह तरीका पाया है।

स्वचालित कॉलम नाम के साथ

df<-data.frame(
        t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
        ,row.names = NULL,stringsAsFactors = FALSE
    )

कॉलम नाम के साथ

df<-setNames(
        data.frame(
            t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
            ,row.names = NULL,stringsAsFactors = FALSE
        ), 
        c("col1","col2","col3")
    )

0

यदि आपके पास वैक्टर हैं, तो वे पंक्तियाँ बनने के लिए नियत हैं, उनका उपयोग करते हुए c(), उन्हें एक मैट्रिक्स रो-बाय-रो के पास दें, और उस मैट्रिक्स को डेटाफ़्रेम में परिवर्तित करें।

उदाहरण के लिए, पंक्तियाँ

dummydata1=c(2002,10,1,12.00,101,426340.0,4411238.0,3598.0,0.92,57.77,4.80,238.29,-9.9)
dummydata2=c(2002,10,2,12.00,101,426340.0,4411238.0,3598.0,-3.02,78.77,-9999.00,-99.0,-9.9)
dummydata3=c(2002,10,8,12.00,101,426340.0,4411238.0,3598.0,-5.02,88.77,-9999.00,-99.0,-9.9)

इस प्रकार एक डेटा फ्रेम में परिवर्तित किया जा सकता है:

dummyset=c(dummydata1,dummydata2,dummydata3)
col.len=length(dummydata1)
dummytable=data.frame(matrix(data=dummyset,ncol=col.len,byrow=TRUE))

निस्संदेह, मुझे 2 प्रमुख सीमाएँ दिखाई देती हैं: (1) यह केवल एकल-मोड डेटा के साथ काम करता है, और (2) आपको इसके लिए अपने अंतिम # कॉलम को पता होना चाहिए कि काम करने के लिए (यानी, मुझे लगता है कि आप एक के साथ काम नहीं कर रहे हैं रैग्ड ऐरे जिसकी सबसे बड़ी पंक्ति की लंबाई अज्ञात है ) एक प्राथमिकता है

यह समाधान सरल लगता है, लेकिन आर में टाइप रूपांतरणों के साथ मेरे अनुभव से, मुझे यकीन है कि यह नई चुनौतियों को नीचे ले जाता है। क्या कोई इस पर टिप्पणी कर सकता है?


0

आपकी नई पंक्ति के प्रारूप के आधार पर, आप उपयोग कर सकते हैं tibble::add_row यदि आपकी नई पंक्ति सरल है और "मूल्य-जोड़े" में निर्दिष्ट की जा सकती है। या आप का उपयोग कर सकते हैं dplyr::bind_rows, "do.call (rbind, dfs) ​​के सामान्य पैटर्न का एक कुशल कार्यान्वयन"।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.