performance - R মধ্যে লুপ অপারেশন গতি




loops rcpp (6)

আমি আর একটি বড় কর্মক্ষমতা সমস্যা আছে। আমি একটি ফাংশন লিখেছেন যে একটি data.frame বস্তুর উপর পুনরাবৃত্তি। এটি কেবল একটি তথ্য data.frame একটি নতুন কলাম যোগ করে এবং কিছু জমা। (সহজ অপারেশন)। data.frame প্রায় 850K সারি আছে। আমার পিসি এখনও কাজ করছে (প্রায় 10 ঘন্টা) এবং আমার রানটাইম সম্পর্কে কোন ধারণা নেই।

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)
}

কোন ধারনা এই অপারেশন গতি কিভাবে?


R তে, আপনি apply পারিবারিক ফাংশনগুলি ব্যবহার করে দ্রুত গতির লুপ প্রক্রিয়াজাতকরণ করতে apply (আপনার ক্ষেত্রে এটি সম্ভবত replicate )। অগ্রগতি বার সরবরাহ করে যে plyr প্যাকেজ একটি বর্ণন আছে।

আরেকটি বিকল্প হল সম্পূর্ণরূপে loops এড়ানো এবং ভেক্টরাইজড গাণিতিক সঙ্গে তাদের প্রতিস্থাপন করা হয়। আমি ঠিক কি করছি তা নিশ্চিত নই, তবে আপনি সম্ভবত আপনার ফাংশনটি একবারে সমস্ত সারিতে প্রয়োগ করতে পারেন:

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]

ভেক্টরাইজড গাণিতিকদের সমস্যা সম্পর্কে আরও বেশি সময় এবং চিন্তা করার প্রয়োজন, তবে তারপরে আপনি কখনও কখনও মৃত্যুদন্ডের সময়কালের বেশিরভাগ আদেশ সংরক্ষণ করতে পারেন।


আপনি loops for ব্যবহার for , আপনি সম্ভবত সি কোডিং বা জাভা বা অন্য কিছু হিসাবে কোডিং সম্ভবত। R কোড সঠিকভাবে vectorised হয় অত্যন্ত দ্রুত।

ক্রম অনুসারে 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 

এখানে উত্তর মহান। একটি ছোটখাটো দৃষ্টিভঙ্গি আচ্ছাদিত নয় যে প্রশ্নটি " আমার পিসি এখনও কাজ করছে (এখন প্রায় 10 ঘন্টা) এবং আমার রানটাইম সম্পর্কে কোন ধারণা নেই "। পরিবর্তনগুলি কীভাবে প্রভাবিত হয় এবং এটি সম্পন্ন করতে কতক্ষণ সময় লাগবে তা পর্যবেক্ষণের জন্য একটি অনুভূতি পেতে ডেভেলপ করার সময় আমি সর্বদা লুপগুলিতে নিম্নলিখিত কোডটি রাখি।

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)
}

পাশাপাশি lapply সঙ্গে কাজ করে।

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)
}

তার উত্তরের শেষে অ্যারি উল্লেখ করেছিলেন, 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 জিনিস #include করার জন্য একই পদ্ধতি রয়েছে, যেখানে আপনি মাত্র একটি পরামিতি পাস করেন

inc <- '#include <header.h>

cxxfunction, include=inc হিসাবে include=inc । এই বিষয়ে সত্যিই কী শীতল এটি আপনার জন্য লিঙ্কিং এবং সংকলন সমস্ত করে, তাই প্রোটোটাইপিং সত্যিই দ্রুত।

Disclaimer: আমি পুরোপুরি নিশ্চিত নই যে tmp এর শ্রেণী সংখ্যাসূচক হওয়া উচিত এবং সংখ্যাসূচক ম্যাট্রিক্স বা অন্য কিছু নয়। কিন্তু আমি বেশিরভাগ নিশ্চিত।

সম্পাদনা করুন: OpenMP পরে আপনার আরও গতির প্রয়োজন হলে, OpenMP C++ জন্য একটি সমান্তরাল সুবিধা ভাল। আমি inline থেকে এটি ব্যবহার করার চেষ্টা করে নি, কিন্তু এটা কাজ করা উচিত। ধারণাটি হবে, n কোরের ক্ষেত্রে, লুপ পুনরাবৃত্তি k k % n দ্বারা সঞ্চালিত হবে। ম্যাটলফের দ্য আর্ট অফ আর প্রোগ্রামিং এর মধ্যে একটি উপযুক্ত ভূমিকা পাওয়া যায়, here পাওয়া here , অধ্যায় 16 এ, C তে রিসোর্টিং।


সূচী বা নেস্টেড ifelse() বিবৃতি ব্যবহার করে loops skipping করে এটি আরও দ্রুত তৈরি করা যেতে পারে।

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."

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

আপনি শর্ত ফিল্টারিং থেকে সম্ভাব্য লাভ উপেক্ষা, এটি খুব দ্রুত। স্পষ্টতই, আপনি তথ্য উপসেট উপর গণনা করতে পারেন, এটি সাহায্য করে।







r-faq