16.5 Operace nad skupinami řádků
Všechny předchozí funkce lze s různou mírou elegance nahradit funkcemi ze základního R. Grupované operace však lze nahradit jen obtížně a v žádném případě ne elegantně. Podstatou zgrupované operace je vyhodnocení funkce nad jednotlivými segmenty tabulky. Na obrázku je zgrupovaná operace provedena funkce summarise()
:

Zgrupované operace, příklad summarise()
summarise()
je vykonáno nad jednotlivými barvenými grupami. Výsledky za jednotlivé grupy jsou následně složeny do nové tabulky.
V praktickém nasazení nás například může zajímat minimální, maximální a průměrný počet sedadel v letadlech jednotlivých výrobců.
V prvním kroku je potřeba pomocí funkce group_by()
vytvořit grupování – tj. identifikovat řádky, které tvoří jednu grupu. Následně je možné volat funkci summarise()
:
%>%
planes group_by(manufacturer) %>%
summarise(
min_seats = min(seats, na.rm = TRUE),
mean_seats = mean(seats, na.rm = TRUE),
max_seats = max(seats, na.rm = TRUE)
)
## # A tibble: 35 × 4
## manufacturer min_seats mean_seats max_seats
## <chr> <int> <dbl> <int>
## 1 AGUSTA SPA 8 8 8
## 2 AIRBUS 100 221. 379
## 3 AIRBUS INDUSTRIE 145 187. 379
## 4 AMERICAN AIRCRAFT INC 2 2 2
## 5 AVIAT AIRCRAFT INC 2 2 2
## 6 AVIONS MARCEL DASSAULT 12 12 12
## 7 BARKER JACK L 2 2 2
## 8 BEECH 9 9.5 10
## 9 BELL 5 8 11
## 10 BOEING 100 175. 450
## # … with 25 more rows
Protože nás zajímají počty sedadel v letadlech “jednotlivých výrobců” je pro zgrupování použita proměnná manufacturer
. group_by
však umí vytvořit i grupy tvořené kombinací více proměnných. Například by bylo možné zjistit počty sedadel pro skupinu vymezenou výrobcem a typem letounu:
%>%
planes group_by(manufacturer, type) %>%
summarise(
min_seats = min(seats, na.rm = TRUE),
mean_seats = mean(seats, na.rm = TRUE),
max_seats = max(seats, na.rm = TRUE)
)
## `summarise()` has grouped output by 'manufacturer'. You can override using the `.groups` argument.
## # A tibble: 37 × 5
## # Groups: manufacturer [35]
## manufacturer type min_seats mean_seats max_seats
## <chr> <chr> <int> <dbl> <int>
## 1 AGUSTA SPA Rotorcraft 8 8 8
## 2 AIRBUS Fixed wing multi engine 100 221. 379
## 3 AIRBUS INDUSTRIE Fixed wing multi engine 145 187. 379
## 4 AMERICAN AIRCRAFT INC Fixed wing single engine 2 2 2
## 5 AVIAT AIRCRAFT INC Fixed wing single engine 2 2 2
## 6 AVIONS MARCEL DASSAULT Fixed wing multi engine 12 12 12
## 7 BARKER JACK L Fixed wing single engine 2 2 2
## 8 BEECH Fixed wing multi engine 9 9.5 10
## 9 BELL Rotorcraft 5 8 11
## 10 BOEING Fixed wing multi engine 100 175. 450
## # … with 27 more rows
V group_by()
je možné použít proměnné všech typů (jakkoliv u double to asi příliš často nedává smysl).
Grupované operace pochopitelně nejsou omezeny pouze na summarise()
. Následující příklad ukazuje použití s mutate()
. Jako cvičení můžete kód analyzovat a zjistit, co dělá.
%>%
planes group_by(manufacturer) %>%
mutate(
year_diff = year - mean(year, na.rm = TRUE)
%>%
) select(tailnum, manufacturer, year, year_diff) %>%
arrange(manufacturer, year)
## # A tibble: 3,322 × 4
## # Groups: manufacturer [35]
## tailnum manufacturer year year_diff
## <chr> <chr> <int> <dbl>
## 1 N365AA AGUSTA SPA 2001 0
## 2 N186US AIRBUS 2002 -5.20
## 3 N187US AIRBUS 2002 -5.20
## 4 N188US AIRBUS 2002 -5.20
## 5 N338NB AIRBUS 2002 -5.20
## 6 N339NB AIRBUS 2002 -5.20
## 7 N340NB AIRBUS 2002 -5.20
## 8 N341NB AIRBUS 2002 -5.20
## 9 N342NB AIRBUS 2002 -5.20
## 10 N343NB AIRBUS 2002 -5.20
## # … with 3,312 more rows
V prvním kroku kód přidá zgrupování k tabulce planes. Výsledek této operace můžeme vidět pomocí funkce class()
:
%>%
planes group_by(manufacturer) %>%
class()
## [1] "grouped_df" "tbl_df" "tbl" "data.frame"
Třída tabulky planes
byla rozšířena o grouped_df
. To umožní kompatibilním metodám nakládat s tabulkou speciálním způsobem: provést operaci zgrupovaně. Pokud pro danou funkci není “zgrupovaná” metoda dostupná, provede se funkce jako obvykle nad celou tabulkou:
%>%
planes group_by(manufacturer) %>%
summary()
## tailnum year type manufacturer
## Length:3322 Min. :1956 Length:3322 Length:3322
## Class :character 1st Qu.:1997 Class :character Class :character
## Mode :character Median :2001 Mode :character Mode :character
## Mean :2000
## 3rd Qu.:2005
## Max. :2013
## NA's :70
## model engines seats speed
## Length:3322 Min. :1.000 Min. : 2.0 Min. : 90.0
## Class :character 1st Qu.:2.000 1st Qu.:140.0 1st Qu.:107.5
## Mode :character Median :2.000 Median :149.0 Median :162.0
## Mean :1.995 Mean :154.3 Mean :236.8
## 3rd Qu.:2.000 3rd Qu.:182.0 3rd Qu.:432.0
## Max. :4.000 Max. :450.0 Max. :432.0
## NA's :3299
## engine
## Length:3322
## Class :character
## Mode :character
##
##
##
##
Třída grouped_df()
zůstává u tabulky zachována, dokud není jinou funkcí odstraněna. dplyr umožňuje grupování odstranit funkcí ungroup()
:
%>%
planes group_by(manufacturer) %>%
ungroup() %>%
class()
## [1] "tbl_df" "tbl" "data.frame"
Částečnou výjimkou z tohoto pravidla je funkce summarise()
, která získala parametr .groups
, který umožňuje nastavit, jak má být nastaveno grupování u výstupní tabulky.
V dalším kroku příkladu je volána funkce mutate()
. Ta zvlášť pro každou grupu vypočítá průměrný rok výroby (mean(year, na.rm = TRUE)
) a tuto hodnotu (vektor o délce 1) odečte od všech hodnot v proměnné year
. Výsledkem je tak vektor o délce identické s počtem řádků v grupě. Tento vektor je přidán jako sloupec year_diff
. Tabulka je následně zpřehledněna voláním select()
a mutate()
.
16.5.1 Bezpečné grupování
Zgrupované operace představují mimořádně mocný nástroj, který zásadně zjednodušuje a zpřehledňuje datovou analýzu. Mají však svá rizika a to zejména mezi židlí a klávesnicí. Pokud uživatel zapomene, že ve skutečnosti pracuje se zgrupovanou tabulkou může dostat bez varování zásadně odlišné výsledky. Proto je rozumné tabulku “na konci trubky” odgrupovat.
Potenciální riziko si uvědomují i tvůrci dplyr. Například od verze 1.0.0 vrací summarise()
po operaci nad zgrupovanou tabulkou varování. Od této verze je také možné také parametrem funkce nastavit, zda a jak má summarise()
grupování zachovat. (V případě nastavení tohoto parametru už žádné varování nevrací.)