Ilekroć chcę zrobić coś „mapującego” py w R, zwykle próbuję użyć funkcji w apply
rodzinie.
Jednak nigdy do końca nie rozumiałem różnic między nimi - jak { sapply
, lapply
itp.} Zastosuj funkcję do wejścia / zgrupowanego wejścia, jak będzie wyglądać wyjście, a nawet czym może być wejście - więc często po prostu przejrzyj je wszystkie, aż dostanę to, czego chcę.
Czy ktoś może wyjaśnić, jak korzystać z którego?
Moje obecne (prawdopodobnie niepoprawne / niepełne) zrozumienie to ...
sapply(vec, f)
: wejście jest wektorem. wyjście jest wektorem / macierzą, w któreji
znajduje się elementf(vec[i])
, co daje macierz, jeślif
ma wyjście wieloelementowelapply(vec, f)
: tak samo jaksapply
, ale wyjście jest listą?apply(matrix, 1/2, f)
: dane wejściowe to macierz. wyjście to wektor, w którym elementemi
jest f (wiersz / col i macierzy)tapply(vector, grouping, f)
: wyjście to macierz / tablica, w której element w macierzy / macierzy jest wartością zf
grupyg
wektorów ig
jest wypychany do nazw wierszy / kolumnby(dataframe, grouping, f)
: niechg
będzie grupa. stosuje sięf
do każdej kolumny grupy / ramki danych. całkiem wydrukuj grupowanie i wartośćf
w każdej kolumnie.aggregate(matrix, grouping, f)
: podobny doby
, ale zamiast ładnego drukowania danych wyjściowych, agregacja umieszcza wszystko w ramce danych.
Boczne pytanie: Nadal nie nauczyłem się plyr ani przekształcania - plyr
czy reshape
zastąpiłbym je wszystkie całkowicie?
*apply()
iby
. plyr (przynajmniej dla mnie) wydaje się o wiele bardziej spójny, ponieważ zawsze wiem dokładnie, jakiego formatu danych oczekuje i dokładnie co wypluje. To oszczędza mi wielu kłopotów.doBy
oraz możliwości wyboru i zastosowaniadata.table
.sapply
jest tylkolapply
z dodatkiemsimplify2array
na wyjściu.apply
działa na wektor atomowy, ale wyjściem może być wektor lub lista.by
dzieli ramki danych na sub-ramki danych, ale nie używaf
osobno dla kolumn. Tylko jeśli istnieje metoda dla klasy „data.frame”, możef
zostać zastosowana kolumnaby
.aggregate
jest ogólny, więc istnieją różne metody dla różnych klas pierwszego argumentu.Odpowiedzi:
R ma wiele * zastosowanych funkcji, które są prawidłowo opisane w plikach pomocy (np
?apply
.). Jest ich jednak dość, że początkujący użytkownicy mogą mieć trudności z podjęciem decyzji, który z nich jest odpowiedni do ich sytuacji, a nawet z zapamiętaniem ich wszystkich. Mogą mieć ogólne przekonanie, że „powinienem tutaj użyć * funkcji zastosowania”, ale na początku może być trudno utrzymać je wszystkie prosto.Pomimo faktu (zauważonego w innych odpowiedziach), że większość funkcjonalności rodziny * apply jest objęta niezwykle popularnym
plyr
pakietem, funkcje podstawowe pozostają użyteczne i warte poznania.Ta odpowiedź ma służyć jako drogowskaz dla nowych useRs, aby pomóc im skierować je do właściwej * funkcji zastosowania dla ich konkretnego problemu. Uwaga: nie ma to na celu po prostu regurgitacji ani wymiany dokumentacji R! Mamy nadzieję, że ta odpowiedź pomoże Ci zdecydować, która * funkcja zastosowania pasuje do Twojej sytuacji, a następnie od Ciebie zależy, czy ją zbadasz. Z jednym wyjątkiem różnice wydajności nie zostaną uwzględnione.
Apply - Kiedy chcesz zastosować funkcję do wierszy lub kolumn macierzy (i analogów o wyższych wymiarach); generalnie nie jest wskazane dla ramek danych, ponieważ najpierw wymusi macierz.
Jeśli chcesz środki wiersz / kolumna lub kwoty na matrycy 2D, należy zbadać wysoce zoptymalizowane, błyskawicznym
colMeans
,rowMeans
,colSums
,rowSums
.lapply - Kiedy chcesz zastosować funkcję do każdego elementu listy po kolei i odzyskać listę.
Jest to koń roboczy wielu innych * funkcji stosujących. Odklej ich kod, a często znajdziesz go
lapply
pod spodem.sapply - Kiedy chcesz zastosować funkcję do każdego elementu listy po kolei, ale chcesz wektora z powrotem, a nie listy.
Jeśli zaczniesz pisać
unlist(lapply(...))
, przestań i zastanów sięsapply
.W bardziej zaawansowanych zastosowaniach
sapply
spróbuje przymusić wynik do tablicy wielowymiarowej, jeśli to właściwe. Na przykład, jeśli nasza funkcja zwraca wektory o tej samej długości,sapply
użyje ich jako kolumn macierzy:Jeśli nasza funkcja zwróci macierz dwuwymiarową,
sapply
zrobi zasadniczo to samo, traktując każdą zwróconą macierz jako pojedynczy długi wektor:O ile nie określimy
simplify = "array"
, w którym to przypadku wykorzysta poszczególne macierze do zbudowania tablicy wielowymiarowej:Każde z tych zachowań jest oczywiście zależne od naszej funkcji zwracającej wektory lub macierze o tej samej długości lub wymiarze.
vapply - gdy chcesz użyć,
sapply
ale być może trzeba wycisnąć trochę więcej kodu z kodu.Bo w
vapply
zasadzie podajesz R przykład tego, co zwróci twoja funkcja, co może zaoszczędzić trochę czasu, zmuszając zwrócone wartości do dopasowania do pojedynczego wektora atomowego.mapply - Gdy masz kilka struktur danych (np. wektory, listy) i chcesz zastosować funkcję do 1. elementów każdego, a następnie do 2. elementów każdego itd., zmuszając wynik do wektora / tablicy, jak w
sapply
.Jest to wielowymiarowe w tym sensie, że twoja funkcja musi akceptować wiele argumentów.
Mapa - opakowanie do
mapply
zSIMPLIFY = FALSE
, więc na pewno zwróci listę.rapply - Gdy chcesz zastosować funkcję do każdego elementu zagnieżdżonej struktury listy , rekurencyjnie.
Aby dać ci pojęcie o tym, jak niezwykłe
rapply
jest, zapomniałem o tym, publikując tę odpowiedź po raz pierwszy! Oczywiście jestem pewien, że wiele osób go używa, ale YMMV.rapply
najlepiej ilustruje funkcja zdefiniowana przez użytkownika do zastosowania:tapply - Gdy chcesz zastosować funkcję do podzbiorów wektora, a podzbiory są zdefiniowane przez inny wektor, zwykle czynnik.
Czarne owce * stosują rodzinę. Użycie wyrażenia „tablica obdarta” w pliku pomocy może być nieco mylące , ale w rzeczywistości jest dość proste.
Wektor:
Współczynnik (o tej samej długości!) Definiujący grupy:
Dodaj wartości w
x
ramach każdej podgrupy zdefiniowanej przezy
:Bardziej złożone przykłady mogą być obsługiwane, gdy podgrupy są zdefiniowane przez unikalne kombinacje listy kilku czynników.
tapply
jest napisane w duchu podobnym do split-apply-łączą funkcje, które są powszechne w R (aggregate
,by
,ave
,ddply
, itd.) Stąd jego status czarna owca.źródło
by
jest to czysto podzielone lap iaggregate
jesttapply
w ich rdzeniu. Myślę, że czarne owce są doskonałym materiałem.aggregate
iby
również? (W końcu rozumiem je po twoim opisie !, ale są dość powszechne, więc może być użyteczneaggregate
,by
itp są w oparciu o * Stosowanie funkcji, sposób podejście ich użyciu jest inna tyle z punktu widzenia użytkowników, że powinny one być zebrane w osobnej odpowiedzi. Mogę spróbować, jeśli będę miał czas, a może ktoś inny mnie do tego pobije i zdobędzie moje poparcie.?Map
jako krewnymapply
data.frame
s są absolutnie centralną częścią R i jakolist
obiekt są często manipulowane przy użyciulapply
szczególnie. Działają również jako pojemniki do grupowania wektorów / czynników wielu typów razem w tradycyjny prostokątny zestaw danych. Chociażdata.table
iplyr
może dodać pewien typ składni, który niektórzy mogą uważać za wygodniejszy, rozszerzają i działajądata.frame
odpowiednio na s.Na marginesie, oto jak różne
plyr
funkcje odpowiadają funkcjom podstawowym*apply
(od dokumentu wprowadzającego do dokumentu plyr ze strony internetowej plyr http://had.co.nz/plyr/ )Jednym z celów
plyr
jest zapewnienie spójnych konwencji nazewnictwa dla każdej funkcji, kodując typy danych wejściowych i wyjściowych w nazwie funkcji. Zapewnia również spójność danych wyjściowych, ponieważ dane wyjściowedlply()
są łatwo przejezdne wldply()
celu uzyskania użytecznych danych wyjściowych itp.Koncepcyjnie nauka
plyr
nie jest trudniejsza niż zrozumienie podstawowych*apply
funkcji.plyr
areshape
funkcje zastąpiły prawie wszystkie te funkcje w moim codziennym użytkowaniu. Ale także z dokumentu Wprowadzenie do Plyra:źródło
*apply()
rodzina funkcji. Dla mnieddply()
było bardzo intuicyjne, ponieważ znałem funkcje agregujące SQL.ddply()
stał się moim młotem do rozwiązywania wielu problemów, z których niektóre można by lepiej rozwiązać za pomocą innych poleceń.plyr
funkcji jest podobne do*apply
funkcji, więc jeśli możesz zrobić jedną, możesz zrobić drugą, aleplyr
funkcje są łatwiejsze do zapamiętania. Ale całkowicie zgadzam się co doddply()
młotka!join()
funkcję, która wykonuje zadania podobne do scalania. Być może bardziej chodzi o to, aby wspomnieć o tym w kontekście plyr.eapply
vapply
i wadysapply
. Główną zaletąvapply
jest to, że wymusza typ wyjścia i jego długość, dzięki czemu uzyskasz dokładnie oczekiwany wynik lub błąd informacyjny. Z drugiej stronysapply
postara się uprościć wyniki, przestrzegając reguł, które nie zawsze są oczywiste, i w przeciwnym razie wróci do listy. Na przykład, spróbuj przewidzieć typ wyjścia będzie produkować:sapply(list(1:5, 6:10, matrix(1:4, 2)), function(x) head(x, 1))
. Cosapply(list(matrix(1:4, 2), matrix(1:4, 2)), ...)
?Ze slajdu 21 http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy :
(Mam nadzieję, że jest jasne, że
apply
odpowiada @ Hadley'saaply
iaggregate
odpowiada @ Hadley'sddply
itp. Slajd 20 tego samego udziału w slajdzie wyjaśni, jeśli nie otrzymasz go z tego obrazu.)(po lewej jest wejście, na górze wyjście)
źródło
Najpierw zacznij od doskonałej odpowiedzi Jorana - wątpliwe, że coś może to poprawić.
Następnie następujące mnemoniki mogą pomóc zapamiętać różnice między nimi. Chociaż niektóre z nich są oczywiste, inne mogą być mniej - --- znajdziesz w nich uzasadnienie w dyskusjach Jorana.
Mnemonika
lapply
to zastosowanie listy, która działa na listę lub wektor i zwraca listę.sapply
jest prostylapply
(domyślnie funkcja zwraca wektor lub macierz, jeśli to możliwe)vapply
jest zweryfikowanym zastosowaniem (pozwala na wstępne określenie typu obiektu zwrotnego)rapply
to rekurencyjne zastosowanie do list zagnieżdżonych, tj. list w listachtapply
jest oznaczony stosuj, gdy znaczniki identyfikują podzbioryapply
jest ogólny : stosuje funkcję do wierszy lub kolumn macierzy (lub bardziej ogólnie do wymiarów tablicy)Budowanie właściwego tła
Jeśli korzystanie z
apply
rodziny nadal wydaje Ci się trochę obce, być może brakuje Ci kluczowego punktu widzenia.Te dwa artykuły mogą pomóc. Stanowią one niezbędne tło do motywowania technik programowania funkcjonalnego zapewnianych przez
apply
rodzinę funkcji.Użytkownicy Lisp natychmiast rozpoznają ten paradygmat. Jeśli nie jesteś zaznajomiony z Lispem, po obejrzeniu FP zdobędziesz potężny punkt widzenia do użycia w R - i
apply
nabierzesz dużo więcej sensu.źródło
Ponieważ zdałem sobie sprawę, że (bardzo doskonałe) odpowiedzi na ten post brak
by
iaggregate
wyjaśnienia. Oto mój wkład.PRZEZ
by
Funkcji, jak podano w dokumentacji może być jednak jako „Okładki”tapply
. Siłaby
powstaje, gdy chcemy obliczyć zadanie,tapply
którego nie można obsłużyć. Jednym z przykładów jest ten kod:Jeśli wydrukujemy te dwa obiekty
ct
icb
„zasadniczo” uzyskamy te same wyniki, a jedyne różnice dotyczą sposobu ich wyświetlania i różnychclass
atrybutów odpowiednioby
dlacb
iarray
dlact
.Jak powiedziałem, moc
by
powstaje, gdy nie możemy użyćtapply
; poniższy kod jest jednym przykładem:R mówi, że argumenty muszą mieć tę samą długość, powiedz „chcemy obliczyć
summary
wszystkie zmienneiris
wzdłuż współczynnikaSpecies
”: ale R po prostu nie może tego zrobić, ponieważ nie wie, jak sobie z tym poradzić.Dzięki
by
funkcji R wywołujemy określoną metodę dladata frame
klasy, a następnie pozwalamy tejsummary
funkcji działać, nawet jeśli długość pierwszego argumentu (i także typu) jest różna.naprawdę działa, a wynik jest bardzo zaskakujący. Jest to obiekt klasy,
by
który wrazSpecies
(powiedzmy dla każdej z nich) oblicza wartośćsummary
każdej zmiennej.Zauważ, że jeśli pierwszym argumentem jest a
data frame
, wywoływana funkcja musi mieć metodę dla tej klasy obiektów. Na przykład, czy używamy tego kodu zmean
funkcją, będziemy mieli ten kod, który nie ma żadnego sensu:AGREGAT
aggregate
może być postrzegany jako inny sposób użycia,tapply
jeśli wykorzystamy go w taki sposób.Dwie bezpośrednie różnice polegają na tym, że drugim argumentem
aggregate
musi być lista, podczas gdytapply
może (nie jest obowiązkowa) być listą i że wyjściemaggregate
jest ramka danych, podczas gdy jednym ztapply
jestarray
.Siła
aggregate
polega na tym, że może on łatwo obsługiwać podzbiory danych za pomocąsubset
argumentów oraz że posiada metody dlats
obiektów, aformula
także.Elementy te
aggregate
ułatwiają pracę z tymtapply
w niektórych sytuacjach. Oto kilka przykładów (dostępnych w dokumentacji):Możemy osiągnąć to samo,
tapply
ale składnia jest nieco trudniejsza, a wynik (w niektórych okolicznościach) mniej czytelny:Są inne czasy, kiedy nie możemy użyć
by
lubtapply
musimy użyćaggregate
.Nie możemy uzyskać wynik z poprzednią
tapply
w jednej rozmowy, ale musimy obliczyć średnią wrazMonth
z poszczególnych elementów, a następnie połączyć je (również pamiętać, że musimy nazwaćna.rm = TRUE
, ponieważformula
sposobyaggregate
funkcjonowania ma domyślniena.action = na.omit
):podczas gdy z
by
po prostu nie możemy tego osiągnąć, w rzeczywistości następujące wywołanie funkcji zwraca błąd (ale najprawdopodobniej jest to związane z podaną funkcjąmean
):Innym razem wyniki są takie same, a różnice występują tylko w klasie (a następnie w jaki sposób jest ona wyświetlana / drukowana i nie tylko - przykład, jak ją podzielić) obiekt:
Poprzedni kod osiąga ten sam cel i wyniki, w niektórych momentach narzędzie, które należy zastosować, jest tylko kwestią osobistych upodobań i potrzeb; poprzednie dwa obiekty mają bardzo różne potrzeby pod względem podzbiorów.
źródło
data.frame(tapply(unlist(iris[,-5]),list(rep(iris[,5],ncol(iris[-5])),col(iris[-5])),summary))
Jest to użycie tapply. With the right splitting there is nothing you cant do with
tapply. The only thing is it returns a matrix. Please be careful by saying we cant use
tapply`Istnieje wiele świetnych odpowiedzi, które omawiają różnice w przypadkach użycia dla każdej funkcji. Żadna z odpowiedzi nie omawia różnic w wydajności. Jest to uzasadnione, ponieważ różne funkcje oczekują różnych danych wejściowych i generują różne dane wyjściowe, jednak większość z nich ma ogólny wspólny cel do oceny według serii / grup. Moja odpowiedź będzie koncentrować się na wydajności. Z uwagi na powyższe tworzenie danych wejściowych z wektorów jest uwzględnione w taktowaniu, również
apply
funkcja nie jest mierzona.Ja testowałem dwie różne funkcje
sum
ilength
naraz. Testowana objętość wynosi 50 M na wejściu i 50 K na wyjściu. Dołączyłem również dwa obecnie popularne pakiety, które nie były powszechnie używane w czasie, gdy zadawano pytanie,data.table
orazdplyr
. Oba zdecydowanie warto sprawdzić, jeśli zależy Ci na dobrej wydajności.źródło
Pomimo wszystkich świetnych odpowiedzi tutaj są jeszcze 2 podstawowe funkcje, które zasługują na wzmiankę, użyteczna
outer
funkcja i niejasnaeapply
funkcjazewnętrzny
outer
jest bardzo przydatną funkcją ukrytą jako bardziej przyziemna. Jeśli czytasz pomoc dotyczącąouter
jej opisu, mówi:co sprawia, że wydaje się, że jest to przydatne tylko dla rzeczy typu algebry liniowej. Można go jednak używać podobnie
mapply
do zastosowania funkcji do dwóch wektorów danych wejściowych. Różnica polega na tym,mapply
że zastosuje funkcję do pierwszych dwóch elementów, a następnie do dwóch drugich itd., Natomiastouter
zastosuje funkcję do każdej kombinacji jednego elementu z pierwszego wektora i jednego z drugiego. Na przykład:Użyłem tego osobiście, gdy mam wektor wartości i wektor warunków i chcę zobaczyć, które wartości spełniają które warunki.
eapply
eapply
przypomina to,lapply
że zamiast stosować funkcję do każdego elementu na liście, stosuje funkcję do każdego elementu w środowisku. Na przykład, jeśli chcesz znaleźć listę funkcji zdefiniowanych przez użytkownika w środowisku globalnym:Szczerze mówiąc, nie używam tego zbyt wiele, ale jeśli budujesz wiele pakietów lub tworzysz wiele środowisk, może się to przydać.
źródło
Być może warto wspomnieć
ave
.ave
jesttapply
przyjaznym kuzynem. Zwraca wyniki w postaci, którą można podłączyć bezpośrednio z powrotem do ramki danych.W pakiecie podstawowym nie ma nic, co działałoby jak w
ave
przypadku całych ramek danych (takby
jak wtapply
przypadku ramek danych). Ale możesz to zrobić:źródło
Niedawno odkryłem dość przydatną
sweep
funkcję i dodałem ją tutaj ze względu na kompletność:zamiatać
Podstawową ideą jest przeszukanie tablicy pod kątem wierszy lub kolumn i zwrócenie zmodyfikowanej tablicy. Przykład wyjaśni to (źródło: datacamp ):
Załóżmy, że masz macierz i chcesz ją ujednolicić pod względem kolumn:
Uwaga: w tym prostym przykładzie ten sam wynik można oczywiście łatwiej osiągnąć
apply(dataPoints, 2, scale)
źródło
sweep
Jest to funkcja wyższego rzędu jak wszystkie inne wymienione tu, na przykładapply
,sapply
,lapply
więc to samo pytanie można zadać o akceptowanej odpowiedzi z ponad 1000 upvotes i przykłady podane w nim. Wystarczy spojrzeć na podanyapply
tam przykład .sweep(matrix(1:6,nrow=2),2,7:9,list)
. Jest to zwykle bardziej wydajne niżapply
dlatego, że gdzieapply
pętlesweep
mogą używać funkcji wektoryzowanych.W pakiecie zwinięcia wydanym niedawno w CRAN, próbowałem skompresować większość typowych funkcji „zastosuj” do zaledwie 2 funkcji:
dapply
(Zastosuj dane) stosuje funkcje do wierszy lub (domyślnych) kolumn macierzy i danych. Ramki i (domyślnie) zwraca obiekt tego samego typu i o tych samych atrybutach (chyba że wynikiem każdego obliczenia jest atomowy idrop = TRUE
). Wydajność jest porównywalna zlapply
kolumnami data.frame i około 2x szybsza niż wapply
przypadku wierszy lub kolumn macierzy. Równoległość jest dostępna przezmclapply
(tylko dla MAC).Składnia:
Przykłady:
BY
jest generyczną wersją S3 do obliczeń typu dzielenie, zastosowanie, łączenie z wykorzystaniem metody wektorowej, macierzowej i data.frame. Jest to znacznie szybsze niżtapply
,by
aaggregate
(an również szybciej niżplyr
na dużych danychdplyr
jest szybsza choć).Składnia:
Przykłady:
Można również dostarczyć listy zmiennych grupujących
g
.Mówiąc o wydajności: Głównym celem załamania jest wspieranie wysokowydajnego programowania w języku R i całkowite wyjście poza dzielenie, stosowanie, łączenie. W tym celu pakiet ma pełny zestaw funkcji C ++ opartych szybko Generic:
fmean
,fmedian
,fmode
,fsum
,fprod
,fsd
,fvar
,fmin
,fmax
,ffirst
,flast
,fNobs
,fNdistinct
,fscale
,fbetween
,fwithin
,fHDbetween
,fHDwithin
,flag
,fdiff
ifgrowth
. Wykonują zgrupowane obliczenia w jednym przejściu przez dane (tj. Bez podziału i ponownego łączenia).Składnia:
Przykłady:
W pakiecie winiety podaję punkty odniesienia. Programowanie za pomocą szybkich funkcji jest znacznie szybsze niż programowanie za pomocą dplyr lub data.tabela , szczególnie na mniejszych danych, ale także na dużych danych.
źródło