2013-09-26 17 views
9

Sto partizionando un frame di dati con split() per utilizzare parLapply() per chiamare una funzione su ogni partizione in parallelo. Il frame di dati ha 1,3 milioni di righe e 20 colonne. Sto dividendo/partizionando di due colonne, entrambi i tipi di carattere. Sembra che ci siano ~ 47K ID univoci e ~ 12K codici univoci, ma non tutti gli accoppiamenti di ID e codice sono abbinati. Il numero risultante di partizioni è ~ 250K. Ecco la linea split():Alternativa veloce a dividere in R

system.time(pop_part <- split(pop, list(pop$ID, pop$code))) 

Le partizioni saranno poi inseriti in parLapply() come segue:

cl <- makeCluster(detectCores()) 
system.time(par_pop <- parLapply(cl, pop_part, func)) 
stopCluster(cl) 

Ho lasciato il codice split() solo corro quasi un'ora e non completa. Posso dividere solo per ID, che richiede ~ 10 minuti. Inoltre, R studio e i thread di lavoro consumano circa 6 GB di RAM.

Il motivo per cui conosco il numero risultante di partizioni è che ho codice equivalente in Pentaho Data Integration (PDI) che viene eseguito in 30 secondi (per l'intero programma, non solo il codice "split"). Non spero in quel tipo di performance con R, ma qualcosa che forse si completa in 10-15 minuti nel peggiore dei casi.

La domanda principale: esiste un'alternativa migliore alla divisione? Ho anche provato ddply() con .parallel = TRUE, ma è anche durato più di un'ora e non è mai stato completato.

risposta

9

indici suddivisi in pop

idx <- split(seq_len(nrow(pop)), list(pop$ID, pop$code)) 

Spalato non è lento, ad esempio,

> system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE))) 
    user system elapsed 
    1.056 0.000 1.058 

quindi se il vostro è Immagino ci sia qualche aspetto della tua dati che rallenta le cose, ad esempio, ID e code sono entrambi fattori con molti livelli e quindi la loro interazione completa, piuttosto che le combinazioni di livelli che appaiono nel tuo set di dati, sono calcolate

> length(split(1:10, list(factor(1:10), factor(10:1)))) 
[1] 100 
> length(split(1:10, paste(letters[1:10], letters[1:10], sep="-"))) 
[1] 10 

o forse si sta esaurendo la memoria.

Utilizzare mclapply anziché parLapply se si utilizzano processi su un computer non Windows (che, a mio avviso, è il caso dal momento che si richiede detectCores()).

par_pop <- mclapply(idx, function(i, pop, fun) fun(pop[i,]), pop, func) 

Concettualmente Sembra che tu stia davvero puntando pvec (distribuzione di un calcolo vectorized rispetto ai processori) piuttosto che mclapply (iterare sulle singole righe nel frame di dati).

Inoltre, e in realtà come passo iniziale, considerare l'identificazione dei colli di bottiglia in func; i dati sono grandi ma non così grandi, quindi forse non è necessaria la valutazione parallela - forse hai scritto codice PDI invece di codice R? Prestare attenzione ai tipi di dati nel frame di dati, ad esempio, fattore contro carattere. Non è insolito ottenere un aumento di velocità di 100 volte tra codice R mal scritto ed efficiente, mentre la valutazione parallela è al massimo proporzionale al numero di core.

+0

Grazie, ci proverò. Ah, in realtà ho scritto il codice R inizialmente e poi l'ho portato su PDI (sono più esperto di R che PDI). – argoneus

+0

Ho eseguito il codice 'split()' che hai postato e ho aspettato per quasi un'ora, ma non è mai stato completato. – argoneus

+0

Un paio di suggerimenti aggiuntivi aggiunti attorno a split, che dovrebbero assumere un ordine di un secondo o meno. Forse anche i fattori stanno causando il rallentamento delle funzioni? –

2

Split (x, f) è lento se x è un fattore e f contiene un sacco di elementi diversi

Quindi, questo codice se veloce:

system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE))) 

Ma, questo è molto lento:

system.time(split(factor(seq_len(1300000)), sample(250000, 1300000, TRUE))) 

E questo è ancora una volta veloce perché ci sono solo 25 gruppi

system.time(split(factor(seq_len(1300000)), sample(25, 1300000, TRUE)))