Istnieje kilka powodów, dla których można było wolą funkcję apply
rodziny nad for
pętli, lub na odwrót.
Po pierwsze, for()
i apply()
, sapply()
będą generalnie równie szybkie, jak nawzajem, jeśli zostaną wykonane poprawnie. lapply()
powoduje, że więcej działa w skompilowanym kodzie wewnątrz obiektów R niż inne, więc może być szybsze niż te funkcje. Wydaje się, że przewaga prędkości jest większa, gdy akt "zapętlenia" danych jest znaczną częścią czasu obliczeniowego; w wielu codziennych zastosowaniach mało prawdopodobne jest, aby uzyskać znacznie szybciej niż z natury szybciej. W końcu wszystkie te funkcje będą wywoływać funkcje R, więc trzeba je zinterpretować, a następnie uruchomić.
for()
Pętle mogą być łatwiejsze do wdrożenia, zwłaszcza jeśli pochodzą z tła programowania, w którym pętle są powszechne. Praca w pętli może być bardziej naturalna niż wymuszenie iteracyjnego obliczania na jedną z funkcji rodziny. Jednakże, aby poprawnie używać pętli for()
, należy wykonać dodatkową pracę, aby skonfigurować pamięć i zarządzać ponownym podłączeniem wyjścia pętli. Funkcje apply
robią to za ciebie automagicznie. Np .:
IN <- runif(10)
OUT <- logical(length = length(IN))
for(i in IN) {
OUT[i] <- IN > 0.5
}
że jest głupie przykład jako >
jest operatorem wektoryzowane ale chciałem coś do punktu, a mianowicie, że trzeba zarządzać wyjście. Najważniejsze jest to, że z for()
pętlami, zawsze alokować wystarczającą ilość pamięci do przechowywania wyjść przed rozpoczęciem pętli. Jeśli nie wiesz, ile potrzebujesz pamięci, przydziel rozsądną porcję pamięci, a następnie sprawdź w pętli, czy wyczerpałeś tę pamięć i zrób kolejny duży fragment pamięci.
Głównym powodem, dla którego warto korzystać z jednej z rodzin funkcji apply
jest bardziej elegancki, czytelny kod. Zamiast zarządzać pamięcią wyjściową i konfigurowaniem pętli (jak pokazano powyżej), możemy pozwolić R obsłużyć to i zwięźle poprosić R, aby uruchomił funkcję na podzbiorach naszych danych.Prędkość zwykle nie wchodzi w decyzję, przynajmniej dla mnie. Używam tej funkcji, która najlepiej pasuje do sytuacji i da w wyniku prosty, łatwy do zrozumienia kod, ponieważ znacznie częściej tracę więcej czasu niż oszczędzam, wybierając zawsze najszybszą funkcję, jeśli nie pamiętam, co to jest kod Robiąc dzień, tydzień lub więcej później!
Rodzina apply
nadaje się do operacji skalarnych lub wektorowych. Pętla for()
często umożliwia wykonywanie wielu iterowanych operacji przy użyciu tego samego indeksu i
. Na przykład, napisałem kod, który używa pętli for()
, aby wykonać k -fold lub sprawdzanie poprawności krzyżowej na obiektach. Prawdopodobnie nigdy bym tego nie zrobił z jedną z rodziny apply
, ponieważ każda iteracja CV wymaga wielu operacji, dostępu do wielu obiektów w bieżącej ramce i wypełnia kilka obiektów wyjściowych, które przechowują wynik iteracji.
Co do ostatniego punktu, o dlaczego lapply()
może ewentualnie być szybsze że for()
lub apply()
, trzeba zdać sobie sprawę, że „pętla” mogą być wykonywane w interpretowany kod R lub kod skompilowany. Tak, oba wciąż będą wywoływać funkcje R, które muszą być interpretowane, ale jeśli robisz pętlę i wywołujesz bezpośrednio ze skompilowanego kodu C (np. lapply()
), to tam, gdzie wzrost wydajności może pochodzić z ponad apply()
, powiedzmy, który sprowadza się do pętla for()
w rzeczywistym kodzie R. Zobacz źródło dla apply()
, aby zobaczyć, że jest owinięcie wokół for()
pętli, a następnie spojrzeć na kod dla lapply()
, który jest:
> lapply
function (X, FUN, ...)
{
FUN <- match.fun(FUN)
if (!is.vector(X) || is.object(X))
X <- as.list(X)
.Internal(lapply(X, FUN))
}
<environment: namespace:base>
i należy zrozumieć, dlaczego nie może być różnica w prędkości między lapply()
oraz for()
i inne funkcje rodziny. .Internal()
jest jednym ze sposobów wywoływania skompilowanego kodu C używanego przez sam R. Oprócz manipulacji i sprawdzenia poprawności na FUN
, całe obliczenie odbywa się w C, wywołując funkcję R FUN
. Porównaj to ze źródłem dla apply()
.
Zobacz ten wątek: http://stackoverflow.com/q/2275896/429846 –
A ten: http://stackoverflow.com/q/5533246/210673 – Aaron
Istnieje również wielki R Help Desk artykuł na ten temat z powrotem w maju 2008: http://promberger.info/files/rnews-vectorvsloops2008.pdf – DrewConway