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?
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:
- 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.
- 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 ).
-
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)