2010-06-28 15 views
5

Dzień dobry,Pętle nieskuteczność w R

I zostały rozwijania przez kilka miesięcy w badania i muszę mieć pewność, że czas realizacji mojego kodu nie jest zbyt długa, bo analizy dużych zbiorów danych.

Dlatego starałem się używać jak najwięcej funkcji wektorowych.

Nadal się zastanawiam.

Co jest kosztowne w R, czy sama pętla nie jest właściwa? Mam na myśli, problem pojawia się, gdy zaczniesz modyfikować zmienne w pętli na przykład, czy to prawda?

W związku z tym zastanawiałem się, co zrobić, jeśli po prostu trzeba uruchomić funkcję na każdym elemencie (tak naprawdę nie dbasz o wynik). Na przykład, aby zapisać dane w bazie danych. Co powinieneś zrobić?

1) używać mapply bez przechowywania wynik w dowolnym miejscu?

2) zrobić pętlę nad wektorem i zastosować tylko f (i) do każdego elementu?

3) Czy istnieje lepsza funkcja, którą mogłem pominąć?

(to oczywiście przy założeniu, że funkcja nie jest optymalnie wektoryzowana).

Co z zestawem foreach? Czy zauważyłeś poprawę wydajności dzięki używaniu go?

+1

Zostawię odpowiedź na kogoś, kto jest bardziej ekspertem ode mnie, ale w moim doświadczeniu praktycznym te * Stosowanie funkcji zwykle (ale nie zawsze) znacznie przyspieszyć. – nico

+0

Chyba tak, ponieważ pętla jest wykonywana "w C", a nie bezpośrednio przez R. – SRKX

+1

Zobacz ten wpis SO na rodzinie zastosowania - http: // stackoverflow.com/questions/2275896/is-rs-apply-family-more-than-syntactic-sugar – csgillespie

Odpowiedz

6

Tylko kilka komentarzy. Pętla for jest mniej więcej tak szybka, jak apply i jej warianty, a prawdziwe przyspieszenia pojawiają się, gdy wektoryzujesz swoją funkcję tak bardzo, jak to możliwe (to znaczy, używając pętli niskiego poziomu, zamiast apply, która po prostu ukrywa pętlę for) . Nie jestem pewien, czy to jest najlepszy przykład, ale należy wziąć pod uwagę następujące elementy:

> n <- 1e06 
> sinI <- rep(NA,n) 
> system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
    3.316 0.000 3.358 
> system.time(sinI <- sapply(1:n,sin)) 
    user system elapsed 
    5.217 0.016 5.311 
> system.time(sinI <- unlist(lapply(1:n,sin), 
+  recursive = FALSE, use.names = FALSE)) 
    user system elapsed 
    1.284 0.012 1.303 
> system.time(sinI <- sin(1:n)) 
    user system elapsed 
    0.056 0.000 0.057 

W jednej z poniższych uwag, Marek zwraca uwagę, że czasochłonna część pętli for powyżej jest faktycznie ]<- część:

> system.time(sinI <- unlist(lapply(1:n,sin), 
+  recursive = FALSE, use.names = FALSE)) 
    user system elapsed 
    1.284 0.012 1.303 

wąskie gardło, które nie może być natychmiast wektoryzowane mogą być zapisane w C lub FORTRAN zebrane z R CMD SHLIB, a następnie Wkładana .Call, .C lub .Fortran.

Zobacz także theselinks, aby uzyskać więcej informacji na temat optymalizacji pętli w R. Sprawdź także artykuł "How Can I Avoid This Loop or Make It Faster?" w R News.

+0

nie jest funkcją stosującą obsługę pętli lepiej od jego implementacji C nadal? Pytanie jest w gruncie rzeczy ogólne, czy lepiej jest użyć Reduce, które Twoim zdaniem implementuje prostą pętlę (na przykład)? – SRKX

+3

W wersji 'sapply' większość czasu spędza na wynikach przetwarzania końcowego. Kiedy wykonasz 'system.time (sinI <- unlist (lapply (1: n, sin), FALSE, FALSE))' powinieneś uzyskać najszybszą wersję (nie z 'sin (1: n)' oczywiście). W pętli 'for' czasochłonny jest' [<-', sprawdź 'system.time (dla (i in 1: n) sin (i))' (w tym przypadku jest to bezużyteczny wynik spadku przyczyny). – Marek

4

vapply unika przetwarzania końcowego, wymagając podania wartości zwracanej. Okazuje się być 3,4 razy szybciej niż pętli for:

> system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
    2.41 0.00 2.39 

> system.time(sinI <- unlist(lapply(1:n,sin), recursive = FALSE, use.names = FALSE)) 
    user system elapsed 
    1.46 0.00 1.45 

> system.time(sinI <- vapply(1:n,sin, numeric(1))) 
    user system elapsed 
    0.71 0.00 0.69