2017-10-28 2 views
1

Ich arbeite gerade an einem Programm, um die Out-of-Sample-Performance mehrerer Prognosemodelle auf simulierten Daten zu bewerten. Für diejenigen, die mit Finanzen vertraut sind, funktioniert es genau wie Backtesting einer Handelsstrategie, außer dass ich Prognosen und nicht Transaktionen bewerten würde.Umgang mit mehrdimensionaler Ausgabe in paralleler Programmierung

Einige der Objekte, die ich derzeit mit for-Schleifen für diese Art von Aufgabe manipuliere, sind 7-dimensionale Arrays (Dimensionen stehen für Monte-Carlo-Replikationen, Datengenerierungsprozesse, Prognosehorizonte, 3 Dimensionen für die Modellparameterauswahl und eine Dimension für alle) die in der Analyse außerhalb der Stichprobe erfassten Zeiträume). Offensichtlich ist es schmerzhaft langsam, so dass paralleles Rechnen für mich ein Muss geworden ist.

Mein Problem ist: Wie behalte ich mehr als 2 Dimensionen in R? Lassen Sie uns Ihnen zeigen, mit ‚for-Schleifen‘ und nur 3 Dimensionen, was ich meine:

x <- array(dim=c(2,2,2)) 
    for (i in 1:2){ 
     for (j in 1:2){ 
     for (k in 1:2){ 
      x[i,j,k] <- i+j+k 
     } 
     } 
    } 

Wenn ich so etwas wie ‚foreach‘ verwenden, ich bin sehr verärgert durch die Tatsache, dass meines Wissens zur Verfügung kombiniert Funktionalitäten Rückkehrlisten, Matrizen oder Vektoren - aber nicht beliebig große mehrdimensionale Arrays. Zum Beispiel:

library(doParallel) 
library(foreach) 

# Get the number of cores to use 
no_cores <- max(1, detectCores()-1) 

# Make cluster object using no_cores 
cl <- makeCluster(no_cores) 

# Initialize cluster for parallel computing 
registerDoParallel(cl) 

x <- foreach(i=1:2, .combine=rbind)%:% 
     foreach(j=1:2, .combine=cbind)%:% 
     foreach(k=1:2, .combine=c)%dopar%{ 
      i+j+k 
    } 

Hier, im Grunde kombiniere ich Ergebnisse in Vektoren, dann Matrizen und schließlich ich anhäufen Matrizen durch Reihen. Eine andere Option wäre die Verwendung von Listen oder Stapelmatrizen durch Spalten, aber Sie können sich die Unordnung vorstellen, wenn Sie 7 Dimensionen und Millionen von Iterationen verfolgen müssen.

Ich denke, ich könnte auch meine eigene 'kombinieren' Funktion schreiben und die Art von Ausgabe bekommen, die ich will, aber ich vermute, dass ich nicht die erste Person bin, die auf dieses Problem trifft. Entweder gibt es einen Weg, genau das zu tun, was ich will, oder jemand hier kann einen Weg weisen, anders über das Speichern meiner Ergebnisse zu denken. Es wäre nicht überraschend, dass ich einen absurd ineffizienten Weg einleite, um dieses Problem zu lösen - ich bin schließlich ein Ökonom, kein Datenwissenschaftler!

Jede Hilfe würde sehr geschätzt werden. Danke im Voraus.

Antwort

0

Was ich tun würde und ich bereits in einem meiner Pakete, bigstatsr.

Nehmen Sie nur eine Dimension und schneiden Sie es in no_cores Blöcke. Es sollte genügend Iterationen haben (z. B. 20 für 4 Kerne). Erstellen Sie für jede Iteration einen Teil des gewünschten Arrays und speichern Sie ihn in einer temporären Datei. Verwenden Sie den Inhalt dieser Dateien, um das gesamte Array zu füllen. Auf diese Weise füllen Sie nur vorab zugewiesene Objekte, die schneller und einfacher sein sollten.

Beispiel:

x.all <- array(dim=c(20,2,2)) 
no_cores <- 3  
tmpfile <- tempfile()  
range.parts <- bigstatsr:::CutBySize(nrow(x.all), nb = no_cores) 

library(foreach) 
cl <- parallel::makeCluster(no_cores) 
doParallel::registerDoParallel(cl) 

foreach(ic = 1:no_cores) %dopar% { 

    ind <- bigstatsr:::seq2(range.parts[ic, ]) 
    x <- array(dim = c(length(ind), 2, 2)) 

    for (i in seq_along(ind)){ 
    for (j in 1:2){ 
     for (k in 1:2){ 
     x[i,j,k] <- ind[i]+j+k 
     } 
    } 
    } 

    saveRDS(x, file = paste0(tmpfile, "_", ic, ".rds")) 
} 
parallel::stopCluster(cl) 

for (ic in 1:no_cores) { 
    ind <- bigstatsr:::seq2(range.parts[ic, ]) 
    x.all[ind, , ] <- readRDS(paste0(tmpfile, "_", ic, ".rds")) 
} 

print(x.all) 

Statt Schreiben von Dateien, können Sie auch direkt geben die no_cores Teile des Arrays in foreach und kombinieren sie mit der rechten abind.

+0

Es ist eigentlich eine sehr gute Lösung. Es hat einige Zeit gedauert, bis ich mit R zusammengearbeitet habe, um zu verstehen, was du hier machen wolltest, aber ich werde diesen Vorschlag auf Eis legen, bis ich etwas neues zu erledigen habe. –

1

Es gibt eine verfügbare Lösung, über die ich heute Abend gestolpert bin. Ich kann entlang der Dimension meiner Wahl einer geeigneten Kombination Funktion erstellen Sie die ‚abind‘ Funktion des ‚abind‘ Paket mit:

library(abind) 

# Get the number of cores to use 
no_cores <- max(1, detectCores()-1) 

# Make cluster object using no_cores 
cl <- makeCluster(no_cores) 

# Initialize cluster for parallel computing 
registerDoParallel(cl) 

mbind <- function(...) abind(..., along=3) 

x <- foreach(i=1:2, .combine=mbind)%:% 
    foreach(j=1:2, .combine=cbind)%:% 
    foreach(k=1:2, .combine=c)%dopar%{ 
     i+j+k 
} 

würde ich noch gerne sehen, wenn jemand anderes Mittel zu tun hat, was ich will mach es aber. Es gibt viele Möglichkeiten, dies zu tun, und ich bin neu in R, aber diese Lösung ist eine eindeutige Möglichkeit.

+0

Dies ist das Paket und Ansatz, den ich verwende, aber Sie sollten die '.multicombine = TRUE' Option zusammen mit' mbind' verwenden, sonst 'mbind' wird nie mit mehr als zwei Argumente aufgerufen werden, die Ihre verletzen können Performance. Siehe https://Stackoverflow.com/a/17572065/2109128 für meine Antwort auf eine ähnliche Frage. –