Использование foreach в определении функции и использование foreach для записи в файл

У меня возникают трудности с распараллеливанием R для оптимизации скорости вызовов функций при записи в файл. Функция проста, но файлы, которые она создает, огромны и занимают неоправданно много времени. Я использовал profvis, чтобы визуализировать, куда уходит время, и кажется, что подозреваемые находятся в операторе cat в конце функции и на этапе захвата при записи в выходной файл. Я включил упрощенный, небольшой, воспроизводимый пример сценария ниже, но на самом деле файлы огромны, и я запускаю их на суперкомпьютерном кластере. Запуск скрипта параллельно, как написано, не дает мне никакого увеличения скорости, но я не понимаю, как структурировать оператор foreach, чтобы он фактически захватывал каждую итерацию функции параллельно. Помещение foreach в саму функцию вызывает у меня проблемы с порядком (вместо заголовка, базовых пар, заголовков, базовых пар и т. д., они добавляются случайным образом, однако они оказались оторванными от того ядра, на котором они работали) и помещением его в Capture.output, похоже, ничего не делает.

Предполагаемый результат:

ACCTTCGAA
1321:1007
GGGTCAATA
1258:1115
GGGCCTACG
1335:1642
ATCATCGCC
1547:1735
TCTCAACGA
1518:1935
TTGTGTTCT
1352:1828
CCTTTCGGC
1403:1162
ACAATTCGC 

Воспроизводимый пример скрипта:

library(doParallel)
library(foreach)


#create cluster with desired number of cores
cl <- makeCluster(20)

# Register cluster
registerDoParallel(cl)

#create example data
bps <- replicate(10,paste(sample(size = 30, x = c("A","C","G","T"), replace = TRUE), collapse = ""))
true_false <- replicate(10,paste(sample(size = 1, x = c("T","F"), replace = TRUE), collapse = ""))
my.df<- data.frame(bps, true_false) 


#create function to make unique Header
  Header = function(){
    header = c(sample(1000:2000, 1), ":", sample(1000:2000, 1))
    paste(header, collapse="")
  }


#assemble reads:
  make_file <- function(df) { 
    bps  <- NULL 
    fragment <- seq(from=1, to=(nrow(df)))
    first.9<- seq(from=1, to=9)
    for(i in 1:nrow(df)){
      header <- Header()
      fragment[i] <- df[i,1]
      first.9 <- substring(fragment,1,9)
      bps[i] <- cat(header, first.9[i], sep = "\n")
    }
    return(bps)
  }



  #regular capture
capture.output(make_file(df = my.df), file = "myfile1.txt", append = TRUE)

  #foreach capture 
foreach(x=(capture.output(make_file(df = my.df), file = "myfile2.txt", append = TRUE))) %dopar% {x}

person user8173816    schedule 13.07.2017    source источник
comment
Привет @ user8173816, если мой ответ помог решить вашу проблему, рассмотрите возможность принятия его в качестве ответа, нажав на галочку слева. Это позволяет сообществу узнать, что это сработало и что ваша проблема закрыта.   -  person CPak    schedule 09.09.2017


Ответы (1)


foreach уже обеспечивает зацикливание и пытается собрать вывод (который вы можете указать).

Ваши данные:

bps <- replicate(10,paste(sample(size = 30, x = c("A","C","G","T"), replace = TRUE), collapse = ""))
true_false <- replicate(10,paste(sample(size = 1, x = c("T","F"), replace = TRUE), collapse = ""))
my.df<- data.frame(bps, true_false) 

Новый код:

library(readr)
library(iterators)
library(foreach)

newfile <- foreach(i=iter(my.df,by="row"), .combine="rbind") %do% { as.data.frame(rbind(Header(), substring(i$bps,1,9))) }
write_tsv(newfile, "C:/temp/temp.txt", append=F, col_names=F)

В каждом loop из foreach выполните итерацию по my.df по строке. Затем %do% следующие: rbind Header() и substring..., затем превращаемся в data.frame. Наконец, .combine вывод с rbind. Это создает кадр данных с одним столбцом. Запишите в выходной файл с write_tsv....

Выход:

          V1
1  1054:1658
2  GACCACTCC
3  1578:1988
4  CAAACGGCT
5  1604:1065

------ распараллелить--------

Для распараллеливания просто замените %do% на %dopar%. В зависимости от того, сколько записей у вас есть, %do% может оказаться быстрее.

person CPak    schedule 13.07.2017
comment
Спасибо @Chi Pak, мне потребовалось некоторое время, чтобы заставить это работать с реальной (гораздо более сложной) функцией, но, похоже, она работает с небольшими тестовыми наборами - кажется, у меня проблемы с памятью, запуская скрипт на фактическом данные о кластере. - person user8173816; 18.07.2017
comment
При возникновении проблем с памятью вы можете: A) сразу же записать каждую строку в файл (то есть не собирать в большую структуру R) или B) разбить входной файл на небольшие пакеты. Вам нужно будет опубликовать новый вопрос, если вам нужна более конкретная помощь. - person CPak; 18.07.2017