आर में लूप ऑपरेशन को गति दें


193

मुझे आर में एक बड़ी प्रदर्शन समस्या है। मैंने एक फ़ंक्शन लिखा है जो किसी data.frameऑब्जेक्ट पर निर्भर करता है। यह बस एक नया कॉलम जोड़ता है data.frameऔर कुछ जमा करता है। (सरल ऑपरेशन)। data.frameमोटे तौर पर 850k पंक्तियां हैं। मेरा पीसी अभी भी काम कर रहा है (लगभग 10h अब) और मुझे रनटाइम के बारे में कोई पता नहीं है।

dayloop2 <- function(temp){
    for (i in 1:nrow(temp)){    
        temp[i,10] <- i
        if (i > 1) {             
            if ((temp[i,6] == temp[i-1,6]) & (temp[i,3] == temp[i-1,3])) { 
                temp[i,10] <- temp[i,9] + temp[i-1,10]                    
            } else {
                temp[i,10] <- temp[i,9]                                    
            }
        } else {
            temp[i,10] <- temp[i,9]
        }
    }
    names(temp)[names(temp) == "V10"] <- "Kumm."
    return(temp)
}

किसी भी विचार कैसे इस ऑपरेशन को गति देने के लिए?

जवाबों:


434

सबसे बड़ी समस्या और अप्रभावीता की जड़ डेटा.फ्रेम को अनुक्रमित करना है, मेरा मतलब है कि यह सभी रेखाएं जहां आप उपयोग करते हैं temp[,]
जितना संभव हो इससे बचने की कोशिश करें। मैंने आपका कार्य लिया, अनुक्रमण को बदला और यहाँ version_A लिया

dayloop2_A <- function(temp){
    res <- numeric(nrow(temp))
    for (i in 1:nrow(temp)){    
        res[i] <- i
        if (i > 1) {             
            if ((temp[i,6] == temp[i-1,6]) & (temp[i,3] == temp[i-1,3])) { 
                res[i] <- temp[i,9] + res[i-1]                   
            } else {
                res[i] <- temp[i,9]                                    
            }
        } else {
            res[i] <- temp[i,9]
        }
    }
    temp$`Kumm.` <- res
    return(temp)
}

जैसा कि आप देख सकते हैं मैं वेक्टर बनाता हूं resजो परिणाम इकट्ठा करता है। अंत में मैं इसे जोड़ता हूं data.frameऔर मुझे नामों के साथ गड़बड़ करने की आवश्यकता नहीं है। तो कितना अच्छा है?

मैं के लिए प्रत्येक कार्य को चलाने के data.frameसाथ nrow1,000 से 1,000 से 10,000 और साथ समय को मापनेsystem.time

X <- as.data.frame(matrix(sample(1:10, n*9, TRUE), n, 9))
system.time(dayloop2(X))

परिणाम है

प्रदर्शन

आप देख सकते हैं कि आपका संस्करण तेजी से निर्भर करता है nrow(X)। संशोधित संस्करण में रैखिक संबंध हैं, और सरल lmमॉडल भविष्यवाणी करता है कि 850,000 पंक्तियों के लिए गणना में 6 मिनट और 10 सेकंड लगते हैं।

वैश्वीकरण की शक्ति

जैसा कि शेन और कैलिमो कहते हैं कि उनके जवाब में वैश्वीकरण बेहतर प्रदर्शन की कुंजी है। अपने कोड से आप लूप से बाहर जा सकते हैं:

  • कंडीशनिंग
  • परिणामों का आरंभ (जो हैं temp[i,9])

यह इस कोड की ओर जाता है

dayloop2_B <- function(temp){
    cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
    res <- temp[,9]
    for (i in 1:nrow(temp)) {
        if (cond[i]) res[i] <- temp[i,9] + res[i-1]
    }
    temp$`Kumm.` <- res
    return(temp)
}

इस फ़ंक्शन के लिए परिणाम की तुलना करें, इस बार nrow10,000 से 100,000 से 10,000 तक।

प्रदर्शन

ट्यूनिंग ट्यूनिंग

एक और ट्विक एक लूप इंडेक्सिंग में बदलना temp[i,9]है res[i](जो कि i-th लूप पुनरावृत्ति में समान है)। यह एक वेक्टर को अनुक्रमित करने और अनुक्रमणिका के बीच फिर से अंतर है data.frame
दूसरी बात: जब आप लूप को देखते हैं तो आप देख सकते हैं कि लूप की बिल्कुल भी आवश्यकता नहीं है i, लेकिन केवल उन लोगों के लिए जो फिट होने की स्थिति में हैं।
तो अब हम शुरू करें

dayloop2_D <- function(temp){
    cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
    res <- temp[,9]
    for (i in (1:nrow(temp))[cond]) {
        res[i] <- res[i] + res[i-1]
    }
    temp$`Kumm.` <- res
    return(temp)
}

प्रदर्शन जो आप प्राप्त करते हैं वह एक डेटा संरचना पर निर्भर करता है। संक्षेप में - TRUEहालत में मूल्यों के प्रतिशत पर । मेरे सिम्युलेटेड डेटा के लिए एक सेकंड के नीचे 850,000 पंक्तियों के लिए अभिकलन समय लगता है।

प्रदर्शन

मैं चाहता हूं कि आप आगे जा सकते हैं, मैं कम से कम दो चीजें देखता हूं जो किया जा सकता है:

  • Cसशर्त कमशॉट करने के लिए एक कोड लिखें
  • यदि आप जानते हैं कि आपके डेटा में अधिकतम अनुक्रम बड़ा नहीं है, तो आप लूप को बदलकर वेक्टरकृत कर सकते हैं, जबकि कुछ ऐसा है

    while (any(cond)) {
        indx <- c(FALSE, cond[-1] & !cond[-n])
        res[indx] <- res[indx] + res[which(indx)-1]
        cond[indx] <- FALSE
    }
    

सिमुलेशन और आंकड़ों के लिए उपयोग किया जाने वाला कोड GitHub पर उपलब्ध है


2
जैसा कि मैं निजी तौर पर मारेक से पूछने का एक तरीका नहीं खोज सकता, वे ग्राफ कैसे उत्पन्न हुए?
कार्बोंटवेला जूल

@carbontwelve आप डेटा या भूखंडों के बारे में पूछ रहे हैं? जाली पैकेज के साथ भूखंड बनाए गए थे। अगर मुझे समय मिलता है तो मैं वेब पर कोड डाल देता हूं और आपको सूचना देता हूं।
मारेक

@carbontwelve Ooops, मैं गलत था :) यह मानक भूखंड हैं (बेस आर से)।
मर्क

@Gregor दुर्भाग्य से नहीं। यह संचयी है, इसलिए आप इसे वेक्टर नहीं कर सकते। सरल उदाहरण: res = c(1,2,3,4)और condहै सब TRUE, तो अंतिम परिणाम होना चाहिए: 1, 3(कारण 1+2), 6(कारण दूसरा है 3, और तीसरा है 3भी), 10( 6+4)। सरल योग आपको मिल कर 1, 3, 5, 7
मारेक

आह, मुझे इसके माध्यम से और अधिक ध्यान से सोचना चाहिए था। मुझे गलती दिखाने के लिए धन्यवाद।
ग्रेगर थॉमस

132

आर कोड को गति देने के लिए सामान्य रणनीतियाँ

सबसे पहले, यह पता लगाएं कि वास्तव में धीमा हिस्सा कहां है। धीरे-धीरे नहीं चलने वाले कोड को ऑप्टिमाइज़ करने की कोई आवश्यकता नहीं है। कोड की छोटी मात्रा के लिए, बस इसके माध्यम से सोचने से काम चल सकता है। यदि वह विफल रहता है, तो RProf और समान प्रोफाइलिंग उपकरण सहायक हो सकते हैं।

एक बार जब आप अड़चन का पता लगा लेते हैं, तो जो आप चाहते हैं उसके लिए अधिक कुशल एल्गोरिदम के बारे में सोचें । यदि संभव हो तो गणना केवल एक बार चलाई जानी चाहिए:

अधिक कुशल कार्यों का उपयोग करने से मध्यम या बड़ी गति प्राप्त हो सकती है। उदाहरण के लिए, paste0एक छोटी दक्षता लाभ पैदा करता है लेकिन .colSums()और इसके रिश्तेदार कुछ अधिक स्पष्ट लाभ उत्पन्न करते हैं। meanहै विशेष रूप से धीमी गति से

तो आप कुछ विशेष रूप से आम परेशानियों से बच सकते हैं :

  • cbind तुम सच में जल्दी से धीमा होगा।
  • अपनी डेटा संरचनाओं को प्रारंभ करें, फिर उन्हें हर बार विस्तारित करने के बजाय उन्हें भरें ।
  • पूर्व-आवंटन के साथ भी, आप पास-दर-मूल्य दृष्टिकोण के बजाय पास-दर-संदर्भ दृष्टिकोण पर स्विच कर सकते हैं, लेकिन यह परेशानी के लायक नहीं हो सकता है।
  • बचने के लिए अधिक नुकसान के लिए आर इन्फर्नो पर एक नज़र डालें ।

बेहतर वैश्वीकरण के लिए प्रयास करें , जो अक्सर हो सकता है लेकिन हमेशा मदद नहीं करता है। इस संबंध में, स्वाभाविक रूप से सदिश कमांड्स जैसे ifelse, diffऔर इस तरह applyकमांड के परिवार की तुलना में अधिक सुधार प्रदान करेगा (जो कि एक अच्छी तरह से लिखे गए लूप से कम गति नहीं प्रदान करता है)।

आप R फ़ंक्शन को अधिक जानकारी प्रदान करने का भी प्रयास कर सकते हैं । उदाहरण के लिए, पाठ-आधारित डेटा में पढ़ने के vapplyबजायsapply उपयोग करें , और निर्दिष्ट करें । गति का लाभ आपके द्वारा समाप्त किए जाने वाले अनुमान के आधार पर परिवर्तनशील होगा।colClasses

अगला, अनुकूलित पैकेजों पर विचार करें : data.tableपैकेज बड़े पैमाने पर गति लाभ पैदा कर सकता है जहां इसका उपयोग डेटा हेरफेर में और बड़ी मात्रा में डेटा पढ़ने में ( fread) है।

अगला, आर बुलाने के अधिक कुशल साधनों के माध्यम से गति लाभ के लिए प्रयास करें :

  • अपनी आर स्क्रिप्ट संकलित करें। या का उपयोग Raऔर jit(एक प्रकार की कटार में एक उदाहरण है जस्ट-इन-समय संकलन के लिए संगीत कार्यक्रम में संकुल इस प्रस्तुति )।
  • सुनिश्चित करें कि आप एक अनुकूलित BLAS का उपयोग कर रहे हैं। ये पूरे बोर्ड में गति प्रदान करते हैं। ईमानदारी से, यह शर्म की बात है कि आर स्वचालित रूप से इंस्टॉल पर सबसे कुशल पुस्तकालय का उपयोग नहीं करता है। उम्मीद है कि क्रांति आर उस काम में योगदान करेगी जो उन्होंने यहां समग्र समुदाय को वापस किया है।
  • रेडफोर्ड नील ने अनुकूलन का एक समूह किया है, जिनमें से कुछ को आर कोर में अपनाया गया था, और कई अन्य जिन्हें पीकेआर में बंद कर दिया गया था

और अंत में, यदि उपरोक्त सभी अभी भी आपको उतनी तेजी से नहीं मिलते हैं जितनी आपको जरूरत है, तो आपको धीमी कोड स्निपेट के लिए तेज भाषा में जाने की आवश्यकता हो सकती है । का संयोजन यहाँ Rcppऔर inlineC एल्गोरिथ्म का केवल सबसे धीमा भाग C ++ कोड के साथ विशेष रूप से आसान है। उदाहरण के लिए, ऐसा करने का मेरा पहला प्रयास है , और यह बहुत अधिक अनुकूलित आर समाधानों को उड़ा देता है।

यदि आप इस सब के बाद भी परेशानियों से बचे हैं, तो आपको सिर्फ कंप्यूटिंग शक्ति की आवश्यकता है। में देखो बनता है ( http://cran.r-project.org/web/views/HighPerformanceComputing.html ) या यहां तक कि GPU आधारित समाधान ( gpu-tools)।

अन्य मार्गदर्शन के लिए लिंक


35

यदि आप forलूप का उपयोग कर रहे हैं , तो आप सबसे अधिक संभावना आर कोडिंग कर रहे हैं जैसे कि यह सी या जावा या कुछ और था। ठीक से सदिश किया गया आर कोड बेहद तेज है।

उदाहरण के लिए अनुक्रम में 10,000 पूर्णांकों की सूची उत्पन्न करने के लिए कोड के इन दो सरल बिट्स को लें:

पहला कोड उदाहरण है कि पारंपरिक कोडिंग प्रतिमान का उपयोग करके एक लूप को कैसे कोड किया जाएगा। इसे पूरा करने में 28 सेकंड का समय लगता है

system.time({
    a <- NULL
    for(i in 1:1e5)a[i] <- i
})
   user  system elapsed 
  28.36    0.07   28.61 

पूर्व-आवंटन स्मृति की सरल क्रिया द्वारा आप लगभग 100 बार सुधार प्राप्त कर सकते हैं:

system.time({
    a <- rep(1, 1e5)
    for(i in 1:1e5)a[i] <- i
})

   user  system elapsed 
   0.30    0.00    0.29 

लेकिन कोल आर ऑपरेटर के आधार पर आर आर वेक्टर ऑपरेशन का उपयोग करके :यह ऑपरेशन लगभग तात्कालिक है:

system.time(a <- 1:1e5)

   user  system elapsed 
      0       0       0 

+1 हालांकि मैं आपके दूसरे उदाहरण को असंबद्ध के रूप में मानता हूं क्योंकि a[i]यह नहीं बदलता है। लेकिन system.time({a <- NULL; for(i in 1:1e5){a[i] <- 2*i} }); system.time({a <- 1:1e5; for(i in 1:1e5){a[i] <- 2*i} }); system.time({a <- NULL; a <- 2*(1:1e5)})एक समान परिणाम है।
हेनरी

@ हेनरी, निष्पक्ष टिप्पणी, लेकिन जैसा कि आप बताते हैं, परिणाम समान हैं। मैंने एक को इनिशियलाइज़ करने के लिए उदाहरण को संशोधित किया है rep(1, 1e5)- टाइमिंग समान हैं।
एंड्री

17

इंडेक्स या नेस्टेड ifelse()स्टेटमेंट्स का उपयोग करके लूप्स को लंघन करके इसे बहुत तेज बनाया जा सकता है ।

idx <- 1:nrow(temp)
temp[,10] <- idx
idx1 <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
temp[idx1,10] <- temp[idx1,9] + temp[which(idx1)-1,10] 
temp[!idx1,10] <- temp[!idx1,9]    
temp[1,10] <- temp[1,9]
names(temp)[names(temp) == "V10"] <- "Kumm."

जवाब के लिए धन्यवाद। मैं आपके बयानों को समझने की कोशिश करता हूं। पंक्ति 4: "अस्थायी [idx1,10] <- अस्थायी [idx1,9] + अस्थायी [जो (idx1) -1,10]" एक त्रुटि का कारण बना क्योंकि लंबी वस्तु की लंबाई लंबाई की एक बहु नहीं है छोटी वस्तु। "अस्थायी [idx1,9] = संख्या [1: 11496]" और "अस्थायी [जो (idx1) -1,10] = int [1: 11494]" तो 2 पंक्तियाँ गायब हैं।
काय

यदि आप एक डेटा सैंपल (कुछ पंक्तियों के साथ dput () का उपयोग करते हैं) तो मैं आपके लिए इसे ठीक कर दूँगा। जिसकी वजह से () - 1 बिट, इंडेक्स असमान हैं। लेकिन आपको यह देखना चाहिए कि यह यहां से कैसे काम करता है: किसी भी लूपिंग या आवेदन की आवश्यकता नहीं है; बस सदिश कार्यों का उपयोग करें।
शनि

1
वाह! मैं सिर्फ एक नेस्टेड बदल दिया है अगर .. फ़ंक्शन ब्लॉक और mapply, एक नेस्टेड ifelse फ़ंक्शन के लिए और 200x स्पीडअप मिला!
जेम्स

आपकी सामान्य सलाह सही है, लेकिन कोड में आप वास्तव में चूक गए हैं, तो यह iमूल्य ऑन i-1-th पर निर्भर करता है, इसलिए वे उस तरीके से सेट नहीं किए जा सकते हैं जैसा कि आप इसे करते हैं (उपयोग करते हुए which()-1)।
मारेक

8

मुझे कोड लिखना पसंद नहीं है ... बेशक इफ्ले और लेप्ली भी बेहतर विकल्प हैं लेकिन कभी-कभी उस फिट को बनाना मुश्किल होता है।

अक्सर मैं डेटा का उपयोग करता हूं। वर्कफ़्लो जैसे कि सूचियों का उपयोग करेगा df$var[i]

यहाँ एक बना हुआ उदाहरण है:

nrow=function(x){ ##required as I use nrow at times.
  if(class(x)=='list') {
    length(x[[names(x)[1]]])
  }else{
    base::nrow(x)
  }
}

system.time({
  d=data.frame(seq=1:10000,r=rnorm(10000))
  d$foo=d$r
  d$seq=1:5
  mark=NA
  for(i in 1:nrow(d)){
    if(d$seq[i]==1) mark=d$r[i]
    d$foo[i]=mark
  }
})

system.time({
  d=data.frame(seq=1:10000,r=rnorm(10000))
  d$foo=d$r
  d$seq=1:5
  d=as.list(d) #become a list
  mark=NA
  for(i in 1:nrow(d)){
    if(d$seq[i]==1) mark=d$r[i]
    d$foo[i]=mark
  }
  d=as.data.frame(d) #revert back to data.frame
})

data.frame संस्करण:

   user  system elapsed 
   0.53    0.00    0.53

सूची संस्करण:

   user  system elapsed 
   0.04    0.00    0.03 

17. गुना तेजी से डेटा की सूची से वैक्टर की एक सूची का उपयोग करने के लिए।

आंतरिक रूप से डेटा.फ्रेम इस संबंध में इतने धीमे क्यों हैं इस पर कोई टिप्पणी? एक को लगता है कि वे सूची की तरह काम करेंगे ...

और भी तेज़ कोड के लिए और के class(d)='list'बजाय ऐसा करेंd=as.list(d)class(d)='data.frame'

system.time({
  d=data.frame(seq=1:10000,r=rnorm(10000))
  d$foo=d$r
  d$seq=1:5
  class(d)='list'
  mark=NA
  for(i in 1:nrow(d)){
    if(d$seq[i]==1) mark=d$r[i]
    d$foo[i]=mark
  }
  class(d)='data.frame'
})
head(d)

1
यह शायद ओवरहेड के लिए धन्यवाद है [<-.data.frame, जिसे किसी भी तरह से तब किया जाता है जब आप करते हैं d$foo[i] = markऔर प्रत्येक <-संशोधन पर संभवतः पूरे डेटा.फ्रेम के वेक्टर की एक नई प्रतिलिपि बना सकते हैं । यह SO पर एक दिलचस्प सवाल करेगा।
फ्रैंक

2
@Frank यह (i) यह सुनिश्चित करना है कि संशोधित वस्तु अभी भी एक वैध डेटा है। बैंडविड्थ और (ii) afaik कम से कम एक प्रति बनाता है, संभवतः एक से अधिक। डेटाफ्रेम सबसाइनमेंट को धीमा माना जाता है और यदि आप लंबे स्रोत कोड को देखते हैं तो यह वास्तव में आश्चर्यजनक नहीं है।
रोलैंड

@ फ्रेंक, @ रोलैंड: क्या df$var[i]नोटेशन एक ही [<-.data.frameफ़ंक्शन से गुजरता है ? मैंने देखा कि यह वास्तव में काफी लंबा है। यदि नहीं, तो यह किस फ़ंक्शन का उपयोग करता है?
क्रिस

@ क्रिस का मानना d$foo[i]=markहै कि मोटे तौर पर इसमें अनुवाद किया जाता है d <- `$<-`(d, 'foo', `[<-`(d$foo, i, mark)), लेकिन अस्थायी चर के कुछ उपयोग के साथ।
टिम गुडमैन

7

जैसा कि अरी ने अपने जवाब के अंत में उल्लेख किया है, Rcppऔर inlineपैकेज चीजों को तेज करने के लिए अविश्वसनीय रूप से आसान बनाते हैं। एक उदाहरण के रूप में, इस inlineकोड को आज़माएं (चेतावनी: परीक्षण नहीं किया गया):

body <- 'Rcpp::NumericMatrix nm(temp);
         int nrtemp = Rccp::as<int>(nrt);
         for (int i = 0; i < nrtemp; ++i) {
             temp(i, 9) = i
             if (i > 1) {
                 if ((temp(i, 5) == temp(i - 1, 5) && temp(i, 2) == temp(i - 1, 2) {
                     temp(i, 9) = temp(i, 8) + temp(i - 1, 9)
                 } else {
                     temp(i, 9) = temp(i, 8)
                 }
             } else {
                 temp(i, 9) = temp(i, 8)
             }
         return Rcpp::wrap(nm);
        '

settings <- getPlugin("Rcpp")
# settings$env$PKG_CXXFLAGS <- paste("-I", getwd(), sep="") if you want to inc files in wd
dayloop <- cxxfunction(signature(nrt="numeric", temp="numeric"), body-body,
    plugin="Rcpp", settings=settings, cppargs="-I/usr/include")

dayloop2 <- function(temp) {
    # extract a numeric matrix from temp, put it in tmp
    nc <- ncol(temp)
    nm <- dayloop(nc, temp)
    names(temp)[names(temp) == "V10"] <- "Kumm."
    return(temp)
}

वहाँ सामान के लिए एक समान प्रक्रिया है #include, जहाँ आप सिर्फ एक पैरामीटर पास करते हैं

inc <- '#include <header.h>

cxxfunction, के रूप में include=inc। इस बारे में वास्तव में अच्छा है कि यह आपके लिए सभी लिंकिंग और संकलन करता है, इसलिए प्रोटोटाइप वास्तव में तेज़ है।

अस्वीकरण: मुझे पूरी तरह से यकीन नहीं है कि tmp का वर्ग संख्यात्मक होना चाहिए, न कि संख्यात्मक मैट्रिक्स या कुछ और। लेकिन मुझे ज्यादातर यकीन है।

संपादित करें: यदि आपको इसके बाद भी अधिक गति की आवश्यकता है, तो OpenMP एक समानांतरकरण सुविधा है जिसके लिए यह अच्छा है C++। मैंने इसे इस्तेमाल करने की कोशिश नहीं की है inline, लेकिन यह काम करना चाहिए। इस विचार से, nकोर के मामले में , लूप पुनरावृत्ति kद्वारा किया जाएगा k % n। एक उपयुक्त परिचय Matloff की द आर्ट ऑफ़ आर प्रोग्रामिंग में पाया गया है , यहाँ उपलब्ध है , अध्याय 16 में, रिसोर्टिंग टू सी


3

यहां के जवाब बहुत अच्छे हैं। कवर नहीं किया गया एक मामूली पहलू यह है कि प्रश्न " मेरा पीसी अभी भी काम कर रहा है (लगभग 10h अब) और मुझे रनटाइम के बारे में कोई पता नहीं है "। मैं हमेशा निम्नलिखित कोडों को लूप में रखता हूं जब यह महसूस करने के लिए विकसित हो रहा है कि गति को प्रभावित करने के लिए परिवर्तन कैसे दिखते हैं और यह भी निगरानी के लिए कि इसे पूरा होने में कितना समय लगेगा।

dayloop2 <- function(temp){
  for (i in 1:nrow(temp)){
    cat(round(i/nrow(temp)*100,2),"%    \r") # prints the percentage complete in realtime.
    # do stuff
  }
  return(blah)
}

साथ ही शिथिलता से काम करता है।

dayloop2 <- function(temp){
  temp <- lapply(1:nrow(temp), function(i) {
    cat(round(i/nrow(temp)*100,2),"%    \r")
    #do stuff
  })
  return(temp)
}

यदि लूप के भीतर का कार्य काफी तेज है, लेकिन लूप की संख्या बड़ी है, तो हर बार छपाई पर विचार करें क्योंकि कंसोल पर प्रिंटिंग के साथ ही एक ओवरहेड है। जैसे

dayloop2 <- function(temp){
  for (i in 1:nrow(temp)){
    if(i %% 100 == 0) cat(round(i/nrow(temp)*100,2),"%    \r") # prints every 100 times through the loop
    # do stuff
  }
  return(temp)
}

एक समान विकल्प, अंश i / n प्रिंट करें। मेरे पास हमेशा कुछ ऐसा होता है cat(sprintf("\nNow running... %40s, %s/%s \n", nm[i], i, n))जब से मैं आमतौर पर नामित चीजों (नामों के साथ nm) पर लूपिंग करता हूं ।
फ्रैंक

2

आर में, आप अक्सर applyपारिवारिक कार्यों (आपके मामले में, यह शायद होगा replicate) का उपयोग करके लूप-प्रोसेसिंग को गति दे सकते हैं । plyrपैकेज पर एक नज़र डालें जो प्रगति सलाखों को प्रदान करता है।

एक और विकल्प पूरी तरह से छोरों से बचने और उन्हें वेक्टरकृत अंकगणित के साथ बदलने का है। मुझे यकीन नहीं है कि आप क्या कर रहे हैं, लेकिन आप शायद एक ही बार में अपने कार्य को सभी पंक्तियों में लागू कर सकते हैं:

temp[1:nrow(temp), 10] <- temp[1:nrow(temp), 9] + temp[0:(nrow(temp)-1), 10]

यह बहुत तेज़ होगा, और फिर आप अपनी स्थिति से पंक्तियों को फ़िल्टर कर सकते हैं:

cond.i <- (temp[i, 6] == temp[i-1, 6]) & (temp[i, 3] == temp[i-1, 3])
temp[cond.i, 10] <- temp[cond.i, 9]

वेक्टर किए गए अंकगणित को समस्या के बारे में अधिक समय और सोचने की आवश्यकता होती है, लेकिन फिर आप कभी-कभी निष्पादन समय में परिमाण के कई आदेशों को बचा सकते हैं।


14
आप उस वेक्टर फ़ंक्शंस पर हाजिर हैं जो लूप्स से अधिक तेज़ होगा या लागू होगा () लेकिन यह सच नहीं है कि लागू () लूप्स से तेज़ है। कई मामलों में लागू () बस लूप को उपयोगकर्ता से दूर कर रहा है लेकिन फिर भी लूपिंग कर रहा है। इस पिछले सवाल को देखें: stackoverflow.com/questions/2275896/…
JD Long

0

प्रसंस्करण data.tableएक व्यवहार्य विकल्प है:

n <- 1000000
df <- as.data.frame(matrix(sample(1:10, n*9, TRUE), n, 9))
colnames(df) <- paste("col", 1:9, sep = "")

library(data.table)

dayloop2.dt <- function(df) {
  dt <- data.table(df)
  dt[, Kumm. := {
    res <- .I;
    ifelse (res > 1,             
      ifelse ((col6 == shift(col6, fill = 0)) & (col3 == shift(col3, fill = 0)) , 
        res <- col9 + shift(res)                   
      , # else
        res <- col9                                 
      )
     , # else
      res <- col9
    )
  }
  ,]
  res <- data.frame(dt)
  return (res)
}

res <- dayloop2.dt(df)

m <- microbenchmark(dayloop2.dt(df), times = 100)
#Unit: milliseconds
#       expr      min        lq     mean   median       uq      max neval
#dayloop2.dt(df) 436.4467 441.02076 578.7126 503.9874 575.9534 966.1042    10

यदि आप फ़िल्टर करने की शर्तों से संभावित लाभ की उपेक्षा करते हैं, तो यह बहुत तेज़ है। जाहिर है, यदि आप आंकड़ों के सबसेट पर गणना कर सकते हैं, तो इससे मदद मिलती है।


2
आप data.table का उपयोग करने के सुझाव को क्यों दोहरा रहे हैं? पहले के उत्तरों में इसे कई बार बनाया जा चुका है।
IRTFM
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.