Próbuję przenieść moje rozumienie plyr do dplyr, ale nie mogę dowiedzieć się, jak grupować według wielu kolumn.
# make data with weird column names that can't be hard coded
data = data.frame(
asihckhdoydkhxiydfgfTgdsx = sample(LETTERS[1:3], 100, replace=TRUE),
a30mvxigxkghc5cdsvxvyv0ja = sample(LETTERS[1:3], 100, replace=TRUE),
value = rnorm(100)
)
# get the columns we want to average within
columns = names(data)[-3]
# plyr - works
ddply(data, columns, summarize, value=mean(value))
# dplyr - raises error
data %.%
group_by(columns) %.%
summarise(Value = mean(value))
#> Error in eval(expr, envir, enclos) : index out of bounds
Czego mi brakuje, aby przetłumaczyć przykład plyr na składnię dplyr?
Edycja 2017 : Dplyr został zaktualizowany, więc dostępne jest prostsze rozwiązanie. Zobacz aktualnie wybraną odpowiedź.
group_by_
teraz wyjaśnionego wvignette("nse")
.dots
. Oto rozwiązanie dostosowane na podstawie odpowiedzi @hadleya poniżej:df %>% group_by_(.dots=list(quote(asihckhdoydk), quote(a30mvxigxkgh))) %>% summarise(n = n())
Odpowiedzi:
Odkąd to pytanie zostało opublikowane, dplyr dodał wersje z określonym zakresem
group_by
( dokumentacja tutaj ). Dzięki temu możesz używać tych samych funkcji, których używałbyś zselect
, na przykład:Wynik twojego przykładowego pytania jest zgodny z oczekiwaniami (zobacz porównanie z plyr powyżej i wyjście poniżej):
Zwróć uwagę, że ponieważ
dplyr::summarize
w danym momencie usuwa się tylko jedną warstwę grupowania, w wynikowym tibble nadal zachodzi pewne grupowanie (które może czasem zaskoczyć ludzi później). Jeśli chcesz się całkowicie zabezpieczyć przed nieoczekiwanym zachowaniem związanym z grupowaniem, zawsze możesz dodać%>% ungroup
do potoku po podsumowaniu.źródło
0.7.0
aby system quote-unquote był dostępny z kilkoma kolumnami?.dots
argumentówgroup_by()
jako takie:data %>% group_by(.dots = columns) %>% summarize(value = mean(value))
.one_of()
zrobienia czegoś tutaj? Myślę, że jest to zbędne w tym kontekście, ponieważ wyrażenie jest opakowane w wywołanievars()
.one_of()
jest zbędne w tym kontekścieselect
składni, zobacz nowąacross
funkcję: dplyr.tidyverse.org/reference/across.html W twoim przypadku wyglądałoby tosummarize(across(all_of(c(''value_A", "value_B")), mean))
Aby napisać cały kod, oto aktualizacja odpowiedzi Hadley z nową składnią:
wynik:
źródło
asihckhdoydk
...dots <- lapply(names(df)[-3], function(x) as.symbol(x))
do tworzenia.dots
argumentu.dots=
była kluczowym krokiem. jeśli ktoś dobrze orientuje się, dlaczego jest to wymagane wgroup_by
rozmowie, czy możesz edytować tę odpowiedź? teraz jest to trochę nieodgadnione.vignette("nse")
wskazuje, że istnieją trzy sposoby cytowania, które są dopuszczalne: wzór, cytat i znak. O ile nie martwisz się o to, z jakiego środowiska będzie pochodzić, prawdopodobnie możesz uciecgroup_by_(.dots=grp_cols)
Obsługa tego w dplyr jest obecnie dość słaba, ostatecznie myślę, że składnia będzie wyglądać mniej więcej tak:
Ale to prawdopodobnie nie będzie przez jakiś czas (ponieważ muszę przemyśleć wszystkie konsekwencje).
W międzyczasie możesz użyć
regroup()
, który pobiera listę symboli:Jeśli masz wektor znaków nazw kolumn, możesz przekonwertować je na właściwą strukturę za pomocą
lapply()
ias.symbol()
:źródło
as.symbol
rozwiązuje to. Dzięki! W przypadku, gdy pomaga to w rozwoju: ten scenariusz jest dla mnie bardzo powszechny. Zagreguj wynik liczbowy dla każdej kombinacji innych zmiennych.regroup
jest również przestarzała (przynajmniej od wersji 0.4.3).Specyfikacja łańcuchów kolumn w programie
dplyr
jest teraz obsługiwana przez wariantydplyr
funkcji z nazwami zakończonymi podkreśleniem. Na przykład, odpowiadającagroup_by
funkcji istniejegroup_by_
funkcja, która może przyjmować argumenty w postaci łańcuchów. Ta winieta szczegółowo opisuje składnię tych funkcji.Poniższy fragment jednoznacznie rozwiązuje problem, który pierwotnie postawił @sharoz (zwróć uwagę na potrzebę zapisania
.dots
argumentu):(Zauważ, że dplyr używa teraz
%>%
operatora i%.%
jest przestarzały).źródło
Dopóki dplyr nie będzie w pełni obsługiwał argumentów łańcuchowych, być może ta treść jest przydatna:
https://gist.github.com/skranz/9681509
Zawiera kilka funkcji opakowujących, takich jak s_group_by, s_mutate, s_filter itp., Które używają argumentów łańcuchowych. Można je mieszać z normalnymi funkcjami programu dplyr. Na przykład
źródło
Działa, jeśli przekażesz mu obiekty (cóż, nie jesteś, ale ...), a nie jako wektor znakowy:
gdzie
df
był twójdata
.?group_by
mówi:które interpretuję jako oznaczające nie wersje znakowe imion, ale sposób, w jaki można się do nich odnieść
foo$bar
;bar
nie jest tutaj cytowany. Albo jak chcesz odwołać się do zmiennych w formule:foo ~ bar
.@Arun wspomina również, że możesz:
Ale nie możesz przekazać czegoś, co nie zostało ocenione jako nazwa zmiennej w obiekcie danych.
Przypuszczam, że jest to spowodowane wewnętrznymi metodami, których Hadley używa do wyszukiwania rzeczy, które przekazujesz za pomocą
...
argumentu.źródło
źródło
Jeden (mały) przypadek, którego brakuje w odpowiedziach tutaj, który chciałem wyjaśnić, to sytuacja, gdy zmienne do grupowania są generowane dynamicznie w potoku:
To w zasadzie pokazuje, jak używać
grep
w połączeniu z,group_by_(.dots = ...)
aby to osiągnąć.źródło
Ogólny przykład użycia
.dots
argumentu jako wejścia wektora znakowego dodplyr::group_by
funkcji:Lub bez zakodowanej na stałe nazwy zmiennej grupującej (zgodnie z zapytaniem OP):
Na przykładzie PO:
Zobacz także winietę dplyr dotyczącą programowania, która wyjaśnia zaimki, quasi-cudzysłowy, kłamstwa i tidyeval.
źródło