Domanda

Ho un data.frame ( link al file ) con 18 colonne e 11520 righe che mi trasformo in questo modo:

library(plyr)
df.median<-ddply(data, .(groupname,starttime,fPhase,fCycle), 
                 numcolwise(median), na.rm=TRUE)

in base al system.time (), ci vogliono circa questo tempo per eseguire:

   user  system elapsed 
   5.16    0.00    5.17

Questa chiamata è parte di una webapp, così il tempo di esecuzione è abbastanza importante. C'è un modo per accelerare questo invito in su?

È stato utile?

Soluzione

Usando solo aggregate è un po 'più veloce ...

> groupVars <- c("groupname","starttime","fPhase","fCycle")
> dataVars <- colnames(data)[ !(colnames(data) %in% c("location",groupVars)) ]
> 
> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median))
   user  system elapsed 
   1.89    0.00    1.89 
> system.time(df.median <- ddply(data, .(groupname,starttime,fPhase,fCycle), numcolwise(median), na.rm=TRUE))
   user  system elapsed 
   5.06    0.00    5.06 
> 
> ag.median <- ag.median[ do.call(order, ag.median[,groupVars]), colnames(df.median)]
> rownames(ag.median) <- 1:NROW(ag.median)
> 
> identical(ag.median, df.median)
[1] TRUE

Altri suggerimenti

Giusto per riassumere alcuni dei punti dai commenti:

  1. Prima di iniziare a ottimizzare, si dovrebbe avere un senso per le prestazioni "accettabile". A seconda della prestazione richiesta, si può quindi essere più specifici su come migliorare il codice. Per esempio, ad una certa soglia, si avrebbe bisogno di smettere di usare R e si muovono su un linguaggio compilato.
  2. Una volta che si dispone di un run-time previsto, è possibile profilo il codice esistente per trovare potenziali colli di bottiglia. R ha diversi meccanismi per questo, tra Rprof (ci sono esempi su StackOverflow se ricerca di [r] + rprof ).
  3. plyr è progettato principalmente per la facilità d'uso, non per le prestazioni (anche se la versione recente ha avuto qualche bella miglioramenti delle prestazioni). Alcune delle funzioni di base sono più veloci perché hanno meno spese generali. @JDLong indicò un bel filo che copre alcuni di questi problemi, tra cui alcuni tecniche specializzate da Hadley.

L'ordine della questione dati quando si sta calcolando mediane:. Se i dati sono in ordine dal più piccolo al più grande, allora il calcolo è un po 'più veloce

x <- 1:1e6
y <- sample(x)
system.time(for(i in 1:1e2) median(x))
   user  system elapsed 
   3.47    0.33    3.80

system.time(for(i in 1:1e2) median(y))
   user  system elapsed 
   5.03    0.26    5.29

Per i nuovi set di dati, ordinare i dati da una colonna appropriata quando si importa. Per i set di dati esistenti si possono ordinare come processo batch (al di fuori del web app).

Per aggiungere alla soluzione di Joshua. Se si decide di utilizzare media invece di mediana, è possibile accelerare il calcolo altre 4 volte:

> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median))
   user  system elapsed 
   3.472   0.020   3.615 
> system.time(ag.mean <- aggregate(data[,dataVars], data[,groupVars], mean))
   user  system elapsed 
   0.936   0.008   1.006 

Lavorare con questi dati è notevolmente più veloce con dplyr:

library(dplyr)

system.time({
  data %>% 
    group_by(groupname, starttime, fPhase, fCycle) %>%
    summarise_each(funs(median(., na.rm = TRUE)), inadist:larct)
})
#>    user  system elapsed 
#>   0.391   0.004   0.395

(avrete bisogno dplyr 0.2 per ottenere %>% e summarise_each)

Ciò a fronte favorevole alla plyr:

library(plyr)
system.time({
  df.median <- ddply(data, .(groupname, starttime, fPhase, fCycle), 
    numcolwise(median), na.rm = TRUE)
})
#>    user  system elapsed 
#>   0.991   0.004   0.996

E per aggregate() (codice da @ joshua-Ulrich)

groupVars <- c("groupname", "starttime", "fPhase", "fCycle")
dataVars <- colnames(data)[ !(colnames(data) %in% c("location", groupVars))]
system.time({
  ag.median <- aggregate(data[,dataVars], data[,groupVars], median)
})
#>    user  system elapsed 
#>   0.532   0.005   0.537

Beh ho appena fatto un paio di semplici trasformazioni in una grande cornice di dati (il set di dati di baseball nel pacchetto plyr) utilizzando le funzioni della libreria standard (ad esempio, 'table', 'Tapply', 'aggregato', etc.) e la funzione plyr analoga - in ogni caso, ho trovato plyr essere significativamente più lento. Per es.,

> system.time(table(BB$year))
    user  system elapsed 
   0.007   0.002   0.009 

> system.time(ddply(BB, .(year), 'nrow'))
    user  system elapsed 
   0.183   0.005   0.189 

In secondo luogo, e l'ho fatto non indagare se questo potrebbe migliorare le prestazioni nel tuo caso, ma per i frame di dati della dimensione che si sta lavorando con la società e più grande, io uso il data.table library, disponibile su CRAN. E 'semplice per creare oggetti data.table così come per convertire data.frames esistenti a data.tables - basta chiamare data.table sul data.frame si desidera convertire:

dt1 = data.table(my_dataframe)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top