2016-06-03 12 views
11

Devo eseguire un codice simile su colonne in una matrice di grandi dimensioni.Come posso modificare il mio codice per migliorare la mia velocità di elaborazione

set.seed(1) 

my_vector <- runif(10000) 

my_sums <- NULL 

for (l in 1:length(my_vector)) { 

    current_result <- my_vector[ my_vector < runif(1) ] 

    my_sums[l] <- sum(current_result) 

} 

head(my_sums) 
# [1] 21.45613 2248.31463 2650.46104 62.82708 11.11391 86.21950 

Sys.time risultati:

user system elapsed 
    1.14 0.00 1.14 

tutte le idee su come migliorare le prestazioni?

+0

ho avuto una piccola spinta nel tempo con 'replicando (1E4, sum (my_vector [my_vector

+1

ho anche avuto un miglioramento sul vostro loop allocando la giusta dimensione per 'my_sums' in anticipo. 'my_sums <- numeric (10000)' –

+0

È sempre una cattiva idea far crescere gli oggetti in un loop. Evita questo quando puoi, e qui, come dimostra Pierre, è possibile farlo. – lmo

risposta

1

Che dire di sapply?

temp <- sapply(seq_along(my_vector), function(l){ 

    current_result <- my_vector[ my_vector < runif(1) ] 
    my_sums[l] <- sum(current_result) 

}) 

Fornisce alcuni miglioramenti delle prestazioni?

1

Modifica: l'aggiunta di sort() riduce il tempo a 0,74. Il tempo necessario per ordinare my_vector è banale in questo esempio, ma può essere costoso su dati più grandi/diversi.

set.seed(1) 

my_vector <- runif(10000) 
n<-runif(10000) 
my_sums <- 1:10000 
system.time(my_vector<-sort(my_vector)) 

#user system elapsed 
# 0  0  0 
# my_vector is now sorted. 


system.time(
for (l in 1:length(my_vector)) { 

my_sums[l] <- sum(my_vector[my_vector < n[l]]) 
}) 

# user system elapsed 
# 0.73 0.00 0.74 

head(my_sums) 
# [1] 21.4561 2248.3146 2650.4610 62.8271 11.1139 86.2195 
14
require(data.table) 

system.time({ 
    set.seed(1) 
    my_vector = runif(10000) 
    DT = data.table(my_vector) 
    setkey(DT, my_vector) 
    DT[,cumsum:=cumsum(my_vector)] 
    my_sums = DT[.(runif(10000)), cumsum, roll=TRUE] 
    my_sums[is.na(my_sums)] = 0 
}) 

head(my_sums) 
# [1] 21.45613 2248.31463 2650.46104 62.82708 11.11391 86.21950 

# user system elapsed 
# 0.004 0.000 0.004 
+0

Bella risposta +1. Un piccolo problema in cui il comportamento di questo differisce dal codice in OP: 'DT [. (X), cumsum, roll = TRUE]' restituisce 'NA' per' x dww

+0

@dww Ben individuato. Risolto da modifica per includere uno 0 all'inizio di 'my_vector'. Nessun cambiamento ai tempi. –

+0

@dww In alternativa, aggiungendo l'ultima riga 'my_sums [is.na (my_sums)] = 0' evita di aggiungere il primo 0. Inoltre non cambia il tempo. –

1

Dal momento che si desidera applicare la stessa funzione attraverso colonne di una matrice grande, vorrei suggerire questo:

dt <- data.table(my_vector1 = runif(1000000), 
        my_vector2 = runif(1000000), 
        my_vector3 = runif(1000000)) 

cols <- paste0(names(dt),"_csum") 

setkey(dt) 

dt[, (cols) := lapply (.SD, function(x) cumsum(x))] 


> head(dt) 
#>  my_vector1 my_vector2 my_vector3 my_vector1_csum my_vector2_csum my_vector3_csum 
#> 1: 7.664785e-07 0.47817820 0.9008552 7.664785e-07  0.4781782  0.9008552 
#> 2: 8.875504e-07 0.24142375 0.9849384 1.654029e-06  0.7196019  1.8857936 
#> 3: 1.326203e-06 0.48592786 0.3791094 2.980232e-06  1.2055298  2.2649030 
#> 4: 2.730172e-06 0.76847160 0.5732031 5.710404e-06  1.9740014  2.8381061 
#> 5: 4.655216e-06 0.01094117 0.5120915 1.036562e-05  1.9849426  3.3501976 

Inoltre, il library profvis è davvero utile per identificare il tempo e la memoria consumo di ogni riga nel tuo codice. Example here.

19

Matt Dowle's excellent data.table approach nella base di R

system.time({ 
    set.seed(1) 
    my_vector <- runif(10000) 
    x <- runif(10000) 
    sorted <- sort(my_vector) 
    ind <- findInterval(x, sorted) + 1 
    my_sums <- c(0, cumsum(sorted))[ind] 
}) 

# user system elapsed 
#  0  0  0 

head(my_sums) 
#[1] 21.45613 2248.31463 2650.46104 62.82708 11.11391 86.21950 
+5

+1 per super veloce. Tuttavia, c'è un errore che dovresti correggere. I valori di 'x' minore di' min (my_vector) 'restituiscono un indice di 0. La sottodimensionatura' cumsum (ordinata) [ind = 0] 'produrrà' NULL' per tali valori, cancellandoli dal vettore 'my_sums' , che sarà quindi più breve di 'my_vector'.La soluzione è usare 'my_sums <- c (0, cumsum (ordinato)) [ind + 1]' – dww

+0

@dww Corretto come suggerito. Grazie. – Khashaa

+0

bello, grazie mille! –

Problemi correlati