2013-04-26 4 views
6

Ich habe 2 numerische Vektoren, einer speichert Werte zur Berechnung des Maximums ab, andere Längen eines rollenden Fensters, um diese Maxima rollierend zu berechnen. Unten finden Sie einen Beispielcode. Generell versuche ich den Code in system.time zu beschleunigen. Gibt es eine fertige Funktion oder einen vektorisierten Weg, um dasselbe zu tun?Was ist der schnellste Weg in R, um Rolling Max mit einer variablen Rolling Window-Größe zu berechnen?

a <- rep(1:5,20000) 
set.seed(123) 
b <- rep(sample(1:50),2000) 

system.time({ 
out <- vector(mode='numeric', length=NROW(a)) 
for(i in seq(a)) { 
    if (i-b[i]>=0) out[i] <- max(a[(i-b[i]+1):i]) 
    else out[i] <- NA 
} 
}) 
+0

+1 Gute Frage. Dies ist ein interessantes Problem zu versuchen und zu optimieren! –

Antwort

1

Managed Teile davon vektorisieren:

Ursprünglich -

system.time({ 
    out <- vector(mode='numeric', length=NROW(a)) 
    for(i in seq(a)) { 
    if (i-b[i]>=0) out[i] <- max(a[(i-b[i]+1):i]) 
    else out[i] <- NA 
    } 
}) 
## user system elapsed 
## 0.64 0.00 0.64 

leicht vektorisiert -

system.time({ 
    nr <- NROW(a) 
    out <- rep(NA,nr) 
    m <- 1:nr - b + 1 
    n <- (1:nr)[m>0] 

    for(i in n) 
    out[i] <- max(a[m[i]:i]) 
}) 
## user system elapsed 
## 0.39 0.00 0.39 
+0

Danke, jetzt sieht der Code besser aus – user1603038

+0

+1 Schöne Lösung –

0

Sie die Teile dieses Problems vektorisieren können, wo Sie brauchen vor allem um die Startindexposition in a herauszufinden (ich nannte dies str) und das Ende des Fensters (end), aber ich muss ein Schleifenkonstrukt verwenden, um diese Indexpositionen auf a anzuwenden, um die max mit mapply zu nehmen. Wie so:

x <- seq_len(length(a)) 
end <- which(x-b > 0) 
str <- end - b[end] 
res <- a 
res[ - end ] <- NA 
res[end] <- mapply(function(x,y) max(a[ x:y ]) , str , end) 

und den Vergleich mit @ e4e5f4 ‚s Antwort:

identical(res , out) 
[1] TRUE 

aber es ist nicht ganz so schnell:

user system elapsed 
0.46 0.00 0.47 

Wenn es einen Weg, der vektorisieren letzte Operation dann wäre das wirklich schnell, aber ich kann mir im Moment keine Möglichkeit vorstellen, dies zu tun!

Verwandte Themen