Przegląd
Jestem stosunkowo zaznajomiony z data.table
, nie za bardzo z dplyr
. Przeczytałem kilka dplyr
winiet i przykłady, które pojawiły się na SO, i jak dotąd moje wnioski są takie, że:
data.table
idplyr
są porównywalne pod względem szybkości, z wyjątkiem sytuacji, gdy istnieje wiele grup (tj. > 10-100 tys.) i w niektórych innych okolicznościach (patrz testy porównawcze poniżej)dplyr
ma bardziej przystępną składniędplyr
abstrahuje (lub będzie) potencjalnymi interakcjami DB- Istnieją pewne drobne różnice w funkcjonalności (patrz „Przykłady/Zastosowanie” poniżej)
Moim zdaniem punkt 2. nie ma większego znaczenia, ponieważ dość dobrze go znam data.table
, choć rozumiem, że dla użytkowników, którzy nie znają obu rozwiązań, będzie to miało duże znaczenie. Chciałbym uniknąć sporu o to, co jest bardziej intuicyjne, ponieważ nie ma to znaczenia dla mojego konkretnego pytania zadawanego z perspektywy osoby już zaznajomionej z data.table
. Chciałbym też uniknąć dyskusji na temat tego, jak „bardziej intuicyjne” prowadzi do szybszej analizy (z pewnością to prawda, ale znowu nie to mnie tutaj najbardziej interesuje).
Pytanie
Chcę wiedzieć:
- Czy istnieją zadania analityczne, które są o wiele łatwiejsze do kodowania przy użyciu jednego lub drugiego pakietu dla osób zaznajomionych z pakietami (tj. pewna kombinacja wymaganych naciśnięć klawiszy w porównaniu z wymaganym poziomem ezoteryki, gdzie mniej każdego z nich jest dobrą rzeczą).
- Czy istnieją zadania analityczne, które w jednym pakiecie są wykonywane znacznie (tj. ponad 2 razy) wydajniej niż w innym?
Jedno ostatnie pytanie SO skłoniło mnie do myślenia to trochę więcej, ponieważ do tego momentu nie sądziłem, że dplyr
zaoferuje znacznie więcej niż to, co mogę już zrobić w data.table
. Oto rozwiązanie dplyr
(dane na końcu Q):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
Co było znacznie lepsze niż moja próba włamania się do rozwiązania data.table
. To powiedziawszy, dobre rozwiązania data.table
są również całkiem dobre (dzięki Jean-Robertowi, Arunowi i zauważcie, że wolałem pojedyncze stwierdzenie od ściśle najbardziej optymalnego rozwiązania):
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
Składnia tego ostatniego może wydawać się bardzo ezoteryczna, ale w rzeczywistości jest całkiem prosta, jeśli jesteś przyzwyczajony do data.table
(tj. nie używasz niektórych bardziej ezoterycznych sztuczek).
Idealnie byłoby, gdybym zobaczył kilka dobrych przykładów, w których sposób dplyr
lub data.table
jest znacznie bardziej zwięzły lub działa znacznie lepiej.
Przykłady
Usagedplyr
nie pozwala na grupowane operacje, które zwracają dowolną liczbę wierszy (z pytanie Eddiego, uwaga: wygląda na to, że zostanie zaimplementowane w dplyr 0.5, @beginneR pokazuje także potencjalne obejście, używającdo
w odpowiedzi na pytanie @eddiego).data.table
obsługuje złączenia kroczące (dzięki @dholstius) a także Połączenia nakładające siędata.table
wewnętrznie optymalizuje wyrażenia w postaciDT[col == value]
lubDT[col %in% values]
pod kątem szybkości poprzez automatyczne indeksowanie, które wykorzystuje wyszukiwanie binarne przy użyciu tej samej podstawowej składni R. Tutaj znajdziesz więcej szczegółów i mały test porównawczy.dplyr
oferuje standardowe wersje ewaluacyjne funkcji (np.regroup
,summarize_each_
), które mogą uprościć programowe użyciedplyr
(uwaga: programistyczne użyciedata.table
jest zdecydowanie możliwe, wymaga jedynie dokładnego przemyślenia, podstawienia/cytowania itp., przynajmniej według mojej wiedzy)
- Przeprowadziłem moje własne testy porównawcze i stwierdził, że oba pakiety są porównywalne w analizie stylu „podziel, zastosuj, połącz”, z wyjątkiem sytuacji, gdy istnieje bardzo duża liczba grup (>100 tys.), w którym to momencie
data.table
staje się znacznie szybszy. - @Arun przeprowadził testy porównawcze połączeń, pokazując, że
data.table
skaluje się lepiej niżdplyr
wraz ze wzrostem liczby grup (zaktualizowany o ostatnie ulepszenia w obu pakietach i najnowszej wersji R). Ponadto punkt odniesienia podczas próby uzyskania unikalnych wartości jestdata.table
~6x szybszy. - (Niezweryfikowany) ma
data.table
75% szybciej w większych wersjach grupy/zastosowania/sortowania, podczas gdydplyr
był 40% szybszy w mniejszych (kolejne pytanie z komentarzy, dzięki, Danas). - Matt, główny autor
data.table
, testuje operacje grupowania nadata.table
,dplyr
i pythonpandas
w maksymalnie 2 miliardach wierszy (~100 GB pamięci RAM). - starszy test porównawczy dla grup 80 tys. jest
data.table
~8 razy szybszy
Dane
To jest pierwszy przykład, który pokazałem w sekcji pytań.
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
dplyr
to:as.data.table(dat)[, .SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)], by = list(name, job)]
- person eddi   schedule 29.01.2014dplyr
idata.table
pracują nad testami porównawczymi, więc odpowiedź pojawi się w pewnym momencie. #2 (składnia) imO jest całkowicie fałszywe, ale wyraźnie wkracza na terytorium opinii, więc również głosuję za zamknięciem. - person eddi   schedule 29.01.2014(d)plyr
, ma miarę 0 - person eddi   schedule 29.01.2014dplyr
na tyle dobrze, aby to wykluczyć i byłem ciekawy, czy ktoś wymyśli dobry kontrprzykład. Również ładne uproszczenie sformułowaniadata.table
. - person BrodieG   schedule 29.01.2014plyr
idata.table
i również zostało zamknięte. Moja odpowiedź tam wyjaśnia, dlaczego to więcej. - person Brian Diggs   schedule 29.01.2014data.table
ma miarę 0, ale nie jest to sprzeczne z twoim przekonaniem;) - person hadley   schedule 29.01.2014data.table
na końcu? I (prawdopodobnie powtarzając oczywistość stwierdzoną w innym miejscu) co z bardziej interesującymi rozmiarami danych (gdzie zdefiniowałbym interesujące jako coś, co zajmuje więcej niż powiedzmy minutę w bazie - co jest generalnie głównym powodem, dla którego ludzie zaczynają badać testy porównawcze pakietów)? - person eddi   schedule 30.01.2014dplyr
, jak iplyr
w odniesieniu do składni i jest w zasadzie głównym powodem, dla którego nie lubię ich składni, jest to, że muszę nauczyć się zbyt wielu (czytaj więcej niż 1) dodatkowych funkcji (z nazwami które nadal nie mają dla mnie sensu), pamiętajcie, co robią, jakie przyjmują argumenty itp. To zawsze było dla mnie ogromnym odejściem od filozofii plyr. - person eddi   schedule 30.01.2014.SD
). [poważnie] Myślę, że są to uzasadnione różnice w projekcie, które przypadną do gustu różnym osobom - person hadley   schedule 30.01.2014.SD
i in. - to prawda -.SD
zajęło mi trochę czasu zrozumienie, ale zanim tam dotarłem, byłem już w stanie wiele zrobić, podczas gdy (d)plyr przedstawia ci dużą barierę od razu. - person eddi   schedule 30.01.2014dplyr
idata.table
. - person danas.zuokas   schedule 31.01.2014data.table
, że jest znacznie mniej szczegółowy niż standardowa ramka danych, a większość operacji jest szybsza. Zmusza cię do myślenia wektorowego (który ma lepszą wydajność). Uważam to za dobry zamiennik ramki danych. Składnia na początku nie jest intuicyjna, ale gdy już się jej nauczysz, łatwo ją zapamiętać. Postrzegamdplyr
jako zestaw funkcji, aledata.table
jako nowy obiekt klasy o znacznie lepszej wydajności i zwięzłej składni niż tradycyjna ramka danych. - person David Leal   schedule 15.03.2017