2010-07-26 19 views
28

मान लीजिए कि आपके पास कई पंक्तियों और कई स्तंभों के साथ डेटा फ्रेम है।आर में, आप डेटा फ्रेम की पंक्तियों पर वास्तव में तेजी से कैसे लूप करते हैं?

कॉलम के नाम हैं। आप नाम से पंक्तियों और स्तंभों तक पंक्तियों तक पहुंच बनाना चाहते हैं।

उदाहरण के लिए, एक (संभवतः धीमी गति से) पंक्तियों पर पाश के लिए रास्ता

for (i in 1:nrow(df)) { 
    print(df[i, "column1"]) 
    # do more things with the data frame... 
} 

एक और तरीका अलग-अलग कॉलम के लिए "सूची" (जैसे column1_list = df[["column1"]) बनाते हैं, और एक पाश में सूचियों का उपयोग करने की है। यदि आप कई कॉलम एक्सेस करना चाहते हैं तो यह दृष्टिकोण तेज़ हो सकता है, लेकिन असुविधाजनक भी हो सकता है।

क्या डेटा फ्रेम की पंक्तियों पर लूपिंग का एक तेज़ तरीका है? तेजी से लूपिंग के लिए कुछ अन्य डेटा संरचना बेहतर है?

+1

यह डीएफ [, "कॉलम 1"] से अलग कैसे है? यह भी देखें? मार्जिन = 1. – Greg

+0

के साथ आवेदन करें उदाहरण मैं वास्तव में नहीं करना चाहता था। मैं डेटा फ्रेम में कुछ मूल्यों को जावास्क्रिप्ट फ़ाइल में डेटा के रूप में लिखना चाहता था। "लागू" में "मार्जिन" के बारे में जानकारी के लिए +1। –

+0

मुझे विशेष परिस्थितियों में कॉलम में मूल्यों के चारों ओर स्थानांतरित करने के लिए पंक्तियों पर लूप की आवश्यकता थी। मुझे याद दिलाया गया था कि आर में ऐसा करने का बेहतर तरीका है: http://stackoverflow.com/questions/7746567/how-to-swap-values-between-2-columns – thadk

उत्तर

13

मुझे लगता है कि मुझे इसे एक पूर्ण उत्तर देने की आवश्यकता है क्योंकि मुझे ट्रैक करने के लिए कठिन टिप्पणियां मिलती हैं और मैंने पहले ही इस पर एक टिप्पणी खो दी है ... nullglob का एक उदाहरण है जो परिवार के कार्यों को अधिक लागू करता है अन्य उदाहरणों से बेहतर है। जब कोई कार्य करता है कि यह बहुत धीमा है तो वह जगह है जहां सभी गति का उपभोग होता है और आपको लूपिंग पर भिन्नताओं में अंतर नहीं मिलेगा। लेकिन जब आप कार्य को तुच्छ बनाते हैं तो आप देख सकते हैं कि लूपिंग चीजों को कितना प्रभावित करती है।

मैं यह भी जोड़ना चाहता हूं कि अन्य उदाहरणों में लागू परिवार के कुछ सदस्यों में दिलचस्प प्रदर्शन गुण हैं। सबसे पहले मैं अपनी मशीन पर नलग्लोब के सापेक्ष परिणामों की प्रतिकृतियां दिखाऊंगा।

n <- 1e6 
system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
5.721 0.028 5.712 

lapply runs much faster for the same result 
system.time(sinI <- lapply(1:n,sin)) 
    user system elapsed 
    1.353 0.012 1.361 

वह भी बहुत धीमी गति से पाया। यहां कुछ ऐसे हैं जिन्हें परीक्षण नहीं किया गया था।

सादा पुराने डेटा के एक मैट्रिक्स संस्करण पर लागू ...

mat <- matrix(1:n,ncol =1),1,sin) 
system.time(sinI <- apply(mat,1,sin)) 
    user system elapsed 
    8.478 0.116 8.531 

तो, लागू() आदेश ही पाश के लिए की तुलना में काफी धीमी है। (पाश के लिए पर्याप्त रूप से धीमा नहीं है, तो मैं पाप (चटाई [मैं, 1])।

एक और एक है कि अन्य पदों में परीक्षण किया जाना प्रतीत नहीं tapply है का उपयोग करें।

system.time(sinI <- tapply(1:n, 1:n, sin)) 
    user system elapsed 
12.908 0.266 13.589 
बेशक

, कोई भी इस तरह से कभी भी इस तरह की गति का उपयोग नहीं करेगा और इसकी उपयोगिता ज्यादातर मामलों में ऐसी किसी भी गति की समस्या से कहीं अधिक है।

+1

+1 nullglob के संदर्भ के लिए। "आर न्यूज", मई 2008 में, यूवे लिगेज और जॉन फॉक्स द्वारा, मई 2008 में, "मैं कैसे इस लूप से बच सकता हूं या इसे तेज कर सकता हूं?" लेख का संदर्भ है। आवेदन कार्यों के बारे में लिखने के लिए धन्यवाद। –

11

सबसे तेज़ तरीका लूप (यानी वेक्टरकृत ऑपरेशंस) नहीं है। एकमात्र ऐसे उदाहरणों में से एक जिसमें आपको लूप की आवश्यकता होती है, जब निर्भरता होती है (यानी एक पुनरावृत्ति दूसरे पर निर्भर करता है)। अन्यथा, लूप के बाहर जितना संभव हो उतना वेक्टरकृत गणना करने की कोशिश करें।

आप, पाश के लिए जरूरत करना तो एक for पाश का उपयोग कर अनिवार्य रूप के रूप में तेजी से कुछ और (lapply एक छोटे से तेजी से हो सकता है लेकिन other apply functions tend to be around the same speed as for) के रूप में है।

+1

शायद लूप से बचने का कोई तरीका नहीं है मैं क्या करना चाहता था --- ऊपर ग्रेग की टिप्पणी पर मेरी प्रतिक्रिया देखें। –

+1

"एक ही गति के आसपास"? क्या आपने सभी उत्तरों को पढ़ा? मेरे जवाब में, मैं दिखाता हूं कि vapply का उपयोग 3x तेज (उस उदाहरण के लिए) लूप के मुकाबले है ... – Tommy

+2

एल्गोरिदमिक दक्षता के मामले में, वे गति में बहुत समान हैं: [एल्गोरिदमिक दक्षता] (http: // en .wikipedia.org/विकी/एल्गोरिदमिक_एफ़िशियेंसी) – Toby

0

इस तथ्य को एक्सप्लोर करना कि डेटा.फ्रेम अनिवार्य रूप से कॉलम वैक्टर की सूचियां हैं, कोई फ़ंक्शन लागू करने के लिए do.call का उपयोग कर सकता है डेटा.फ्रेम के प्रत्येक कॉलम पर स्तंभों की संख्या की धैर्य के साथ (अन्य भाषाओं में किसी सूची पर "ज़िप" के समान)।

do.call(paste, data.frame(x=c(1,2), z=c("a","b"), z=c(5,6))) 
+0

लेकिन वह लूपिंग नहीं है। –

संबंधित मुद्दे