Как переписать мой код R для многоядерной обработки? - PullRequest
2 голосов
/ 17 августа 2011

У меня есть R-код, который мне нужен, чтобы перейти к стадии «распараллеливания».Я новичок в этом, поэтому, пожалуйста, прости меня, если я использую неправильные термины.У меня есть процесс, который просто должен проходить через каждого человека по отдельности, а затем усреднять по отдельным людям в конце.Процесс одинаков для каждого человека (это броуновский мост), я просто должен сделать это для> 300 человек.Итак, я надеялся, что кто-то здесь может знать, как изменить мой код, чтобы он мог появиться?или распараллелен?или как бы там ни было, чтобы убедиться, что 48 процессоров, к которым у меня теперь есть доступ, могут помочь сократить 58 дней, которые потребуются для вычисления этого с моим маленьким ноутбуком.В моей голове я бы просто отправил 1 человека на один процессор.Сделайте так, чтобы он выполнялся через скрипт, а затем отправьте еще один .... если это имеет смысл.

Ниже приведен мой код.Я попытался прокомментировать это и указал, где я думаю, что код должен быть изменен.

for (n in 1:(length(IDNames))){ #THIS PROCESSES THROUGH EACH INDIVIDUAL 

#THIS FIRST PART IS JUST EXTRACTING THE DATA FROM MY TWO INPUT FILES.  
#I HAVE ONE FILE WITH ALL THE LOCATIONS AND THEN ANOTHER FILE WITH A DATE RANGE.  
#EACH INDIVIDUAL HAS DIFFERENT DATE RANGES, THUS IT HAS TO PULL OUT EACH INDIVIDUALS 
#DATA SET SEPARATELY AND THEN RUN THE FUNCTION ON IT.

    IndivData = MovData[MovData$ID==IDNames[n],]
    IndivData = IndivData[1:(nrow(IndivData)-1),]
    if (UseTimeWindow==T){
      IndivDates = dates[dates$ID==IDNames[n],]
      IndivData = IndivData[IndivData$DateTime>IndivDates$Start[1]&IndivData$DateTime<IndivDates$End[1],]
    }
    IndivData$TimeDif[nrow(IndivData)]=NA

    ########################
#THIS IS THE PROCESS WHERE I THINK I NEED THAT HAS TO HAVE EACH INDIVIDUAL RUN THROUGH IT

    BBMM <- brownian.bridge(x=IndivData$x, y=IndivData$y,
    time.lag = IndivData$TimeDif[1:(nrow(IndivData)-1)], location.error=20,
    area.grid = Grid, time.step = 0.1)

  #############################
  # BELOW IS JUST CODE TO BIND THE RESULTS INTO A GRID DATA FRAME I ALREADY CREATED.  
  #I DO NOT UNDERSTAND HOW THE MULTICORE PROCESSED CODE WOULD JOIN THE DATA BACK 
  #WHICH IS WHY IVE INCLUDED THIS PART OF THE CODE.  

    if(n==1){   #creating a data fram with the x, y, and probabilities for the first individual
      BBMMProbGrid = as.data.frame(1:length(BBMM[[2]]))
      BBMMProbGrid = cbind(BBMMProbGrid,BBMM[[2]],BBMM[[3]],BBMM[[4]])
      colnames(BBMMProbGrid)=c("GrdId","X","Y",paste(IDNames[n],"_Prob", sep=""))
    } else {                #For every other individual just add the new information to the dataframe
      BBMMProbGrid = cbind(BBMMProbGrid,BBMM[[4]])
      colnames(BBMMProbGrid)[n*2+2]=paste(IDNames[n],"_Prob", sep ="")
    }# end if  


    } #end loop through individuals

Ответы [ 3 ]

4 голосов
/ 17 августа 2011

Это общий пример, так как у меня не хватило терпения прочитать весь ваш код.Один из самых быстрых способов распространить это на несколько процессоров - использовать библиотеку multicore и mclapply (распараллеленную версию lapply), чтобы выдвинуть список (отдельные элементы в списке будут кадрами данных для каждого из300+ человек в вашем случае) через функцию.

Пример:

library(multicore)
result=mclapply(data_list, your_function,mc.preschedule=FALSE, mc.set.seed=FALSE)
4 голосов
/ 17 августа 2011

Не уверен, почему это было отклонено либо.Я думаю, что пакет foreach - это то, что вам нужно.Эти первые несколько PDF-файлов содержат очень четкую полезную информацию.В основном напишите, что вы хотите сделать для каждого человека как функцию.Затем используйте foreach для отправки данных об одном человеке на узел для запуска функции (при отправке других людей на другой узел и т. Д.), А затем она компилирует все результаты, используя что-то вроде rbind.Я использовал это несколько раз с отличными результатами.

Редактировать: я не пытался переделать ваш код, как я полагаю, учитывая, что вы получили настолько далеко, что у вас будет достаточно навыков, чтобы обернуть егофункцию, а затем используйте один вкладыш foreach.

Редактировать 2: Это было слишком долго для комментария, чтобы ответить вам.

Я думал, так как вы зашли так далеко с кодом, который выЯ смог бы включить его в функцию :). Если вы все еще работаете над этим, вам может понадобиться написать цикл for для циклов по вашим объектам и выполнить вычисления, необходимые для этого объекта.Тогда цикл for - это то, что вы хотите в своей функции.Я думаю, что в вашем коде все это вплоть до «area.grid».Тогда вы можете избавиться от большинства ваших [n], так как данные являются только подмножеством один раз за итерацию.

Возможно:

pernode <- function(MovData) {
    IndivData = MovData[MovData$ID==IDNames[i],]
    IndivData = IndivData[1:(nrow(IndivData)-1),]
    if (UseTimeWindow==T){
                         IndivDates = dates[dates$ID==IDNames,]
                         IndivData = IndivData[IndivData$DateTime>IndivDates$Start[1]
                         &IndivData$DateTime<IndivDates$End[1],]
                         }
    IndivData$TimeDif[nrow(IndivData)]=NA

    BBMM <- brownian.bridge(x=IndivData$x, y=IndivData$y,
    time.lag = IndivData$TimeDif[1:(nrow(IndivData)-1)], location.error=20,
    area.grid = Grid, time.step = 0.1)

return(BBMM)
}

Тогда что-то вроде:

library(doMC)
library(foreach)
registerDoMC(cores=48) # or perhaps a few less than all you have

system.time(
  output <- foreach(i = 1:length(IDNames)), .combine = "rbind", .multicombine=T,
 .inorder = FALSE) %dopar% {pernode(i)}
)

Трудно сказать, так ли это без каких-либо тестовых данных, дайте мне знать, как вы ладите.

2 голосов
/ 17 августа 2011

Как я понял из вашего описания у вас есть доступ к распределенному компьютерному кластеру.Так что пакет многоядерный не будет работать.Вы должны использовать Rmpi, снег или foreach.Исходя из вашей существующей структуры цикла, я бы посоветовал использовать пакет foreach и doSnow.Но ваши коды выглядят так, как будто у вас много данных.Вы, вероятно, должны проверить, чтобы уменьшить данные (только необходимые), которые будут отправлены на узлы.

...