R допар foreach на куски вместо строки - PullRequest
1 голос
/ 08 марта 2019

Этот вопрос относится к параллельной обработке в R с использованием foreach и dopar.Я создал простой набор данных и простую операцию (фактическая операция является более сложной, и поэтому я представляю здесь простую операцию).Код для данных и текущий код размещен для вашей справки.

Загрузка пакетов и создание данных

#Creating a mock dataframe
Area =c('XX','YY','ZZ','XX','YY','ZZ','XX','YY','ZZ','YY')
Car_type = c('A','A','B','C','B','C','A','A','B','C')
Variable1=c(.34,.19,.85,.27,.32,.43,.22,.56,.17,.11)
Variable2=c(.76,.3,.16,.24,.47,.23,.87,.27,.43,.59)
Final_data = data.frame(Area,Car_type,Variable1,Variable2)    
#replicate the above 100 times to create a bigger dataset
n =100
Final_data2=do.call("rbind", replicate(n, Final_data, simplify = FALSE))
Final_data2$Final_value = 0
#car_list = unique(Final_data2$Car_type) #have not figured out how to use this

код допар foreach

#Create clusters and load required packages the clusters 
library(doParallel)    
cl=makeCluster(3,type="PSOCK") 
registerDoParallel(cl)


home1 <- function(zz1){
  output <- foreach(x = iter(zz1, by = "row"), .combine = rbind, 
                    .packages = "truncnorm") %dopar% {
    if (x$Car_type=='A'){
      x$Final_value = rtruncnorm(1,a=-1,b=1,mean = x$Variable1,sd=x$Variable2)
    } else if(x$Car_type=='B'){
      x$Final_value = rtruncnorm(1,a=-5,b=5,mean = x$Variable1,sd=1)  
    }  else{
      x$Final_value = rtruncnorm(1,a=-10,b=10,mean = 1,sd=1)
    }
    return(x)
  }
  output
}
Final_data3 <- home1(zz1=Final_data2)
stopCluster(cl) #Stop cluster

В первомЧасть I создает примерный фрейм данных с именем Final_data2.Во второй части, основываясь на типе автомобиля в столбце «Car_type», я генерирую значение из усеченных нормальных распределений, где точки усечения, а также среднее и стандартное отклонение изменяются в зависимости от типа Car_type.Этот код работает в текущем формате.После использования разных ядер он проходит по каждой строке по одному.

Issue

Теперь я хочу расширить это таким образом, чтобы вместо повторения и выполнения операции над каждой строкой на отдельном ядреЯ хочу выполнить операции с блоками набора данных.То, что я хотел бы сделать, это запустить часть dopar foreach для разных областей на отдельных ядрах.НапримерЯ хочу запустить цикл dopar foreach для Area = XX в кластере 1, Area = YY в кластере 2 и Area = ZZ в кластере 3. К сожалению, я не смог понять это самостоятельно.Кто-нибудь поможет мне с этим?Будем благодарны за любую помощь.

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

1 Ответ

1 голос
/ 09 марта 2019

Для вашего конкретного приложения я бы использовал pmap::purrr():

home2 <- function(Car_type, Variable1, Variable2) {
  if (Car_type=='A'){
    truncnorm::rtruncnorm(1,a=-1,b=1,mean = Variable1,sd=Variable2)
  } else if(Car_type=='B'){
    truncnorm::rtruncnorm(1,a=-5,b=5,mean = Variable1,sd=1)  
  }  else{
    truncnorm::rtruncnorm(1,a=-10,b=10,mean = 1,sd=1)
  }
}

Final_data2$Final_value <- 
  purrr::pmap_dbl(Final_data2[c("Car_type", "Variable1", "Variable2")], home2)

Если эта операция действительно занимает много времени, вы можете легко распараллелить ее, используя пакеты {future} и {furrr}:

future::plan(future::multiprocess)
Final_data2$Final_value <- 
  furrr::future_pmap_dbl(Final_data2[c("Car_type", "Variable1", "Variable2")], home2)
...