2012-10-19 14 views
7

Mam dwa wektora e i g. Chcę wiedzieć dla każdego elementu w e procent elementów w g, które są mniejsze. Jednym ze sposobów, aby zaimplementować to w R jest:Przyspieszenie funkcji, które używa w ramach połączenia sapply w R

set.seed(21) 
e <- rnorm(1e4) 
g <- rnorm(1e4) 
mf <- function(p,v) {100*length(which(v<=p))/length(v)} 
mf.out <- sapply(X=e, FUN=mf, v=g) 

Z dużym e lub g, to zajmuje dużo czasu, aby uruchomić. Jak mogę zmienić lub dostosować ten kod, aby działał szybciej?

Uwaga: Powyższa funkcja mf jest oparta na kodzie z funkcji mess w pakiecie dysków.

+0

Można zmienić mf do 'mf <- function (p, v) {100 * średnia (v <= p)}, ale nie jestem pewien, ile to pomoże. – Dason

+0

Dzięki Dason, ale wydaje się, że zajmuje więcej czasu – Paulo

+0

"vapply" zamiast "sapply" prawdopodobnie pomoże. –

Odpowiedz

8

Powód jest tak powolny, ponieważ wywołujesz swoją funkcję length(e) razy. Nie robi dużej różnicy dla małych wektorów, ale narzut z wywołań funkcji R naprawdę zaczyna się sumować z większymi wektorami.

Normalnie trzeba by przenieść to do skompilowanego kodu, ale na szczęście można użyć findInterval:

set.seed(21) 
e <- rnorm(1e4) 
g <- rnorm(1e4) 
O <- findInterval(e,sort(g))/length(g) 

# Now for some timings: 
f <- function(p,v) mean(v<=p) 
system.time(o <- sapply(e, f, g)) 
# user system elapsed 
# 0.95 0.03 0.98 
system.time(O <- findInterval(e,sort(g))/length(g)) 
# user system elapsed 
#  0  0  0 
identical(o,O) # may be FALSE 
all.equal(o,O) # should be TRUE 

# How fast is this on large vectors? 
set.seed(21) 
e <- rnorm(1e7) 
g <- rnorm(1e7) 
system.time(O <- findInterval(e,sort(g))/length(g)) 
# user system elapsed 
# 22.08 0.08 22.31 
+0

Dzięki @Joshua, świetna odpowiedź. Poprawa szybkości jest niesamowita. Jedna mała korekta, aby uzyskać takie same wyniki jak w pierwotnej funkcji: findInterval (e, sort (g))/length (g) – Paulo

Powiązane problemy