Menu

Grupowanie i podsumowanie w R (aggregate, tapply, dplyr)

Wszystkie sposoby liczenia statystyk dla grup w R: zliczanie przez table(), tapply() dla jednej statystyki na grupę, formuła w aggregate() oraz group_by() z summarize() z dplyr.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

Zliczanie wierszy w grupach: table()

Najprostsze pytanie przy grupowaniu to "ile jest każdego?", a bazowy R odpowiada na nie jednym wywołaniem. table() zlicza, ile razy pojawia się każda wartość:

Jedna kolumna daje liczebności dla każdej wartości, dwie kolumny dają pełną tabelę krzyżową (regiony w wierszach, plany w kolumnach). Żeby dostać udziały, owiń wynik w prop.table(table(...)). table() to najszybsza droga do odpowiedzi o częstościach w całym R: nie sięgaj po nic cięższego, gdy potrzebujesz tylko liczebności.

Jedna statystyka na grupę: tapply()

tapply(values, groups, function) dzieli pierwszy wektor według drugiego i stosuje funkcję do każdego kawałka:

Wynikiem jest nazwany wektor: etykiety grup są nazwami, statystyki wartościami. Dzięki temu świetnie nadaje się do szybkiego odczytu (means["EU"]). Nazwa pochodzi od "table apply": zastosuj funkcję wzdłuż tabeli grupującej. Należy do tej samej rodziny co sapply() i lapply(), opisanej w artykule o rodzinie apply.

Ograniczeniem tapply() jest kształt: nazwany wektor trudno złączyć z inną tabelą, narysować na wykresie albo dalej przetwarzać. Gdy podsumowanie jest etapem pośrednim, a nie ostateczną odpowiedzią, chcesz dostać z powrotem ramkę danych. Dokładnie to zwraca kolejne narzędzie.

Koń pociągowy z formułą: aggregate()

aggregate() to pełne grupowanie w bazowym R: zwraca ramkę danych, a jego formułę czyta się jak zwykłe zdanie. value ~ group oznacza "value w podziale na group":

Dodanie kolejnej zmiennej grupującej to po prostu + another_column w formule: drugie wywołanie sumuje dla każdej kombinacji regionu i kwartału. Możesz też agregować kilka kolumn wartości naraz przez cbind(a, b) ~ group. Wynik jest zwykłą ramką danych, więc od razu pasuje do złączenia, sortowania albo wykresu. To domyślne narzędzie bazowego R do podsumowań w grupach.

Jedno ciche zachowanie warto znać: formuła usuwa wiersze z NA w dowolnej użytej kolumnie, zanim zacznie agregować. Zwykle właśnie tego chcesz, ale czasem to wyjaśnienie liczebności, która wydaje się zbyt niska.

Sposób dplyr: group_by() + summarize()

Nowoczesnym standardem jest wzorzec dwóch czasowników z dplyr: group_by() deklaruje grupowanie, a summarize() zwija każdą grupę do jednego wiersza i liczy tyle statystyk, ile nazwiesz (przykład statyczny, bo piaskownica uruchamia tylko bazowy R):

library(dplyr)

sales |>
    group_by(region) |>
    summarize(
        n     = n(),
        total = sum(amount),
        avg   = mean(amount)
    )

Tu dplyr naprawdę wygrywa z bazowym R: wiele statystyk na grupę w jednym czytelnym wywołaniu (aggregate() wymaga do tego sztuczek), do tego n() w gratisie, a wynik płynie prosto do kolejnego potoku. (summarise() to ta sama funkcja w brytyjskiej pisowni.)

Jedna rzecz dziwi początkujących: przy kilku zmiennych grupujących summarize() zdejmuje tylko ostatnią, więc wynik nadal jest pogrupowany, a R wypisuje o tym komunikat. Powiedz wprost, czego chcesz, argumentem .groups: summarize(avg = mean(amount), .groups = "drop") zwraca zwykłą, niepogrupowaną ramkę i to jest dobry domyślny nawyk. Pogrupowana ramka, która przemknie do dalszego kodu, sprawia, że mutate() i podobne funkcje po cichu działają w obrębie grup. To klasyczne źródło mylących wyników.

Jak wybrać narzędzie

  • Liczebność: table(), nic nie przebije jednego wywołania.
  • Jedna statystyka, szybki podgląd: tapply() i odczyt odpowiedzi z nazwanego wektora.
  • Ramka danych na wyjściu, tylko bazowy R: aggregate() z formułą.
  • Kilka statystyk, część potoku albo coś ambitniejszego: group_by() |> summarize().

Żadna z tych opcji nie jest błędna, bo wszystkie liczą te same liczby. Dopasowanie narzędzia do kształtu wyniku, którego potrzebujesz, oszczędza jednak późniejszą konwersję. Same średnie, mediany i miary rozrzutu opisuje artykuł o statystyce opisowej.

Przykład: mtcars według liczby cylindrów

Wszystko razem na wbudowanym zbiorze danych: dla każdej liczby cylindrów liczba samochodów oraz ich średnie spalanie i moc:

Jedenaście samochodów 4-cylindrowych ze średnią około 26.7 mpg, siedem 6-cylindrowych w okolicach 19.7, czternaście 8-cylindrowych około 15.1, a moc rośnie w przeciwnym kierunku. Dwa wywołania i cała tabela podsumowania: właśnie na takie pytania odpowiada agregacja w grupach.

Co warto zapamiętać

  • table() do liczebności, prop.table() do udziałów.
  • tapply(values, groups, fn) zwraca nazwany wektor: szybki podgląd, łatwy odczyt.
  • aggregate(value ~ group, data, FUN) zwraca ramkę danych; + dodaje zmienne grupujące, cbind() dodaje kolumny wartości.
  • group_by() |> summarize(n = n(), avg = mean(x), .groups = "drop") z dplyr to nowoczesny standard podsumowań z wieloma statystykami.
  • Wybieraj według kształtu wyniku, bo liczby są wszędzie takie same.

Dalej: łączenie tabel, które mają wspólny klucz, czyli merge() i rodzina złączeń z dplyr.

Najczęściej zadawane pytania

Jak policzyć średnią w grupach w R?

Bazowy R ma dwa narzędzia: tapply(df$value, df$group, mean) zwraca nazwany wektor średnich grup, a aggregate(value ~ group, data = df, FUN = mean) zwraca ten sam wynik jako ramkę danych. W dplyr: df |> group_by(group) |> summarize(avg = mean(value)).

Jak zliczyć wystąpienia w grupach w R?

table(df$group) zlicza wiersze dla każdej wartości grupy w jednym wywołaniu, a table(df$a, df$b) tworzy tabelę krzyżową dwóch kolumn. W dplyr count(df, group) robi to samo i zwraca ramkę danych, którą łatwiej dalej przetwarzać.

Co robi aggregate() w R?

aggregate() dzieli ramkę danych według jednej lub kilku kolumn grupujących, stosuje funkcję do każdego kawałka i zwraca ramkę danych z wynikami. Formułę czyta się naturalnie: aggregate(sales ~ region + quarter, data = df, FUN = mean) oznacza sales, pogrupowane według region i quarter, uśrednione.

Czym różni się tapply od aggregate?

To samo obliczenie, inny kształt wyniku. tapply() zwraca nazwany wektor (albo tablicę przy dwóch zmiennych grupujących), co jest wygodne do szybkiego podglądu. aggregate() zwraca ramkę danych, co jest lepsze, gdy wynik trafia do dalszej analizy, złączenia albo wykresu. W razie wątpliwości wybierz aggregate().

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ