16.2 Tvorba a úprava obsahu
Balík dplyr obsahuje dvě základní funkce pro vytváření a agregaci obsahu v tabulkách: mutate()
a summarise()
16.2.1 Tvorba nových sloupců s mutate()
Funkce mutate()
vytváří nové sloupce, proměnné, v tabulce. Syntax mutate()
je podobně jako u dalších funkcí z tidyverse poměrně střídmá:
Funkce přijímá vstupní tabulku a specifikaci sloupců, které se mají vytvořit v ...
. Fungování mutate()
může být ilustrováno následujícím (mírně zjednodušujícím) schématem:
mutate()
může být použito i pro modifikaci stávajících sloupců. V tomto případě však mutate()
interně nejprve vytvoří nový sloupec a až následně jím nahradí sloupec původní. Při modifikaci sloupce na opravdu velkých tabulkách tak může mutate()
spotřebovávat nečekané množství systémových zdrojů.
Praktické využití mutate()
je možné ilustrovat na příkladu. Například můžeme chtít pro každé pozorování (řádek, letadlo) v tabulce planes
spočítat, kolik sedadel připadá na jeden motor a zjistit, zda se jedná o vrtulové letadlo:
planes %>%
mutate(
seats_per_engine = (seats/engines) %>% round(),
turbo_prop_plane = engine == "Turbo-prop"
) %>%
select(seats_per_engine, turbo_prop_plane, everything())
## # A tibble: 3,322 x 11
## seats_per_engine turbo_prop_plane tailnum year type manufacturer model
## <dbl> <lgl> <chr> <int> <chr> <chr> <chr>
## 1 28 FALSE N10156 2004 Fixe… EMBRAER EMB-…
## 2 91 FALSE N102UW 1998 Fixe… AIRBUS INDU… A320…
## 3 91 FALSE N103US 1999 Fixe… AIRBUS INDU… A320…
## 4 91 FALSE N104UW 1999 Fixe… AIRBUS INDU… A320…
## 5 28 FALSE N10575 2002 Fixe… EMBRAER EMB-…
## 6 91 FALSE N105UW 1999 Fixe… AIRBUS INDU… A320…
## 7 91 FALSE N107US 1999 Fixe… AIRBUS INDU… A320…
## 8 91 FALSE N108UW 1999 Fixe… AIRBUS INDU… A320…
## 9 91 FALSE N109UW 1999 Fixe… AIRBUS INDU… A320…
## 10 91 FALSE N110UW 1999 Fixe… AIRBUS INDU… A320…
## # … with 3,312 more rows, and 4 more variables: engines <int>, seats <int>,
## # speed <int>, engine <chr>
mutate()
vytvořilo dva nové sloupce. Sloupec seats_per_engine
obsahuje zaokrouhlený počet sedadel na motor. Za povšimnutí stojí způsob, jakým byl jeho výpočet ve funkci mutate()
specifikován. Na levé straně je jméno nově vytvářeného sloupce. Na pravé straně od “=” je postup, který se má použít pro vytvoření jejího obsahu. Jména sloupců z tabulky se přitom používají jako proměnné. Příklad také ukazuje, že v mutate()
je možné používat komplikované výrazy včetně trubek %>%
.
V jednom volání mutate()
je možné vytvořit více nových sloupců. Jednotlivé specifikace jsou ve volání odděleny čárkou. Druhý vytvořený sloupec ukazuje příklad vytvoření logické proměnné. Ohledně typu zpracovávaných nebo výsledných proměnných nemá mutate()
žádné omezení.
mutate()
přidává nově vytvořené sloupce na konec tabulky. Proto je v příkladu použita funkce select()
, která je přesunuje na začátek tabulky.
U popisu fungování mutate()
je výše zmíněná možnost modifikace stávajících sloupců. V praxi se taková operace provede jednoduše. Předpokládejme, že chceme sloupec year
nahradit jeho vlastním logaritmem:
## # A tibble: 3,322 x 9
## tailnum year type manufacturer model engines seats speed engine
## <chr> <dbl> <chr> <chr> <chr> <int> <int> <int> <chr>
## 1 N10156 7.60 Fixed wing m… EMBRAER EMB-1… 2 55 NA Turbo-…
## 2 N102UW 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 3 N103US 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 4 N104UW 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 5 N10575 7.60 Fixed wing m… EMBRAER EMB-1… 2 55 NA Turbo-…
## 6 N105UW 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 7 N107US 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 8 N108UW 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 9 N109UW 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## 10 N110UW 7.60 Fixed wing m… AIRBUS INDUST… A320-… 2 182 NA Turbo-…
## # … with 3,312 more rows
Pokud jméno nového sloupce odpovídá některému sloupci, který již je v tabulce obsažen, je tento novým sloupcem nahrazen.
mutate()
umí pracovat i s proměnnými, které nejsou součástí tabulky. V následujícím případě je nově vytvořený sloupec this_is_true
naplněn konstantou přiřazenou do proměnné x
.
## # A tibble: 3,322 x 10
## this_is_true tailnum year type manufacturer model engines seats speed
## <lgl> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 TRUE N10156 2004 Fixe… EMBRAER EMB-… 2 55 NA
## 2 TRUE N102UW 1998 Fixe… AIRBUS INDU… A320… 2 182 NA
## 3 TRUE N103US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 4 TRUE N104UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 5 TRUE N10575 2002 Fixe… EMBRAER EMB-… 2 55 NA
## 6 TRUE N105UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 7 TRUE N107US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 8 TRUE N108UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 9 TRUE N109UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 10 TRUE N110UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
Stejného výsledku by bylo dosaženo, kdyby byla konstanta definována přímo v mutate()
tj. this_is_true = TRUE
.
Na proměnnou, která takto do mutate()
vstupuje zvnějšku je uvaleno omezení: musí mít délku jedna, nebo délku odpovídající počtu řádků tabulky. Tato podmínka není v následujícím příkladu splněna (vektor x
má délku 3):
x <- c(TRUE, TRUE, TRUE)
planes %>%
mutate(
this_is_true = x
) %>%
select(this_is_true, everything())
## Error: Problem with `mutate()` input `this_is_true`.
## x Input `this_is_true` can't be recycled to size 3322.
## ℹ Input `this_is_true` is `x`.
## ℹ Input `this_is_true` must be size 3322 or 1, not 3.
Pokud má vektor x
délku 1, potom je tato jedna hodnota přiřazena ke každému řádku. Pokud je délka x
právě rovna počtu řádků, potom je ke každému řádku přiřazena hodnota na odpovídající pozici:
## # A tibble: 3,322 x 10
## new_variable tailnum year type manufacturer model engines seats speed
## <int> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 1 N10156 2004 Fixe… EMBRAER EMB-… 2 55 NA
## 2 2 N102UW 1998 Fixe… AIRBUS INDU… A320… 2 182 NA
## 3 3 N103US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 4 4 N104UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 5 5 N10575 2002 Fixe… EMBRAER EMB-… 2 55 NA
## 6 6 N105UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 7 7 N107US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 8 8 N108UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 9 9 N109UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 10 10 N110UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
Naprosto stejná pravidla platí pro funkce. V příkladu je použita funkce rnorm(n)
, která vrací n
výběrů z normálního rozdělení. První dva příklady jsou vyhodnoceny bez problémů. Poslední je nekorektní a skončí chybou, protože rnorm(3)
vrací vektor o délce 3.
## # A tibble: 3,322 x 10
## new_variable tailnum year type manufacturer model engines seats speed
## <dbl> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 0.442 N10156 2004 Fixe… EMBRAER EMB-… 2 55 NA
## 2 0.442 N102UW 1998 Fixe… AIRBUS INDU… A320… 2 182 NA
## 3 0.442 N103US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 4 0.442 N104UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 5 0.442 N10575 2002 Fixe… EMBRAER EMB-… 2 55 NA
## 6 0.442 N105UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 7 0.442 N107US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 8 0.442 N108UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 9 0.442 N109UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 10 0.442 N110UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
## # A tibble: 3,322 x 10
## new_variable tailnum year type manufacturer model engines seats speed
## <dbl> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 -0.170 N10156 2004 Fixe… EMBRAER EMB-… 2 55 NA
## 2 -0.320 N102UW 1998 Fixe… AIRBUS INDU… A320… 2 182 NA
## 3 3.80 N103US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 4 -1.01 N104UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 5 -0.489 N10575 2002 Fixe… EMBRAER EMB-… 2 55 NA
## 6 -0.0148 N105UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 7 -2.09 N107US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 8 -1.37 N108UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 9 -2.13 N109UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 10 0.548 N110UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
## Error: Problem with `mutate()` input `new_variable`.
## x Input `new_variable` can't be recycled to size 3322.
## ℹ Input `new_variable` is `rnorm(3)`.
## ℹ Input `new_variable` must be size 3322 or 1, not 3.
16.2.1.1 Úskalí mutate()
Výše byl použit příklad, ve kterém byla při stanovení hodnoty použita proměnná definovaná mimo tabulku. Při troše smůly se může stát, že jméno této proměnné se bude shodovat se jménem některého sloupce. V souladu s logikou R dostane přednost obsah sloupce:
## # A tibble: 3,322 x 10
## this_is_true tailnum year type manufacturer model engines seats speed
## <chr> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 N10156 N10156 2004 Fixe… EMBRAER EMB-… 2 55 NA
## 2 N102UW N102UW 1998 Fixe… AIRBUS INDU… A320… 2 182 NA
## 3 N103US N103US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 4 N104UW N104UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 5 N10575 N10575 2002 Fixe… EMBRAER EMB-… 2 55 NA
## 6 N105UW N105UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 7 N107US N107US 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 8 N108UW N108UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 9 N109UW N109UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## 10 N110UW N110UW 1999 Fixe… AIRBUS INDU… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
Další úskalí v použití spočívá v tom, že mutate()
pracuje nad celou tabulkou a ne nad jednotlivými řádky. Toto chování lze změnit pomocí vhodného zgrupování, ale je potřeba ho mít na paměti. Co to znamená v praxi:
## # A tibble: 3,322 x 10
## mean_year tailnum year type manufacturer model engines seats speed engine
## <dbl> <chr> <int> <chr> <chr> <chr> <int> <int> <int> <chr>
## 1 2000. N10156 2004 Fixed … EMBRAER EMB-… 2 55 NA Turbo…
## 2 2000. N102UW 1998 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 3 2000. N103US 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 4 2000. N104UW 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 5 2000. N10575 2002 Fixed … EMBRAER EMB-… 2 55 NA Turbo…
## 6 2000. N105UW 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 7 2000. N107US 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 8 2000. N108UW 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 9 2000. N109UW 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## 10 2000. N110UW 1999 Fixed … AIRBUS INDU… A320… 2 182 NA Turbo…
## # … with 3,312 more rows
mutate()
v tomto případě vypočítal průměrnou hodnotu ze všech roků a tu přiřadil ke všem sloupcům. Opět je to dáno tím, že mean
neprodukuje vektor o délce odpovídající počtu řádků, ale vektor o délce 1.
16.2.1.2 Varinaty mutate()
dplyr obsahuje mutace mutate()
: mutate_if()
, mutate_at()
a mutate_all()
. Jejich použití je podobné jako v případě mutací select()
. V principu umožňují transformovat všechny sloupce (_all
), vyjmenované sloupce (_at
) nebo ty, které splňují určitou podmínku (_if
).
V následujícím příkladu je obsah všech textových proměnných transformován do malých písmen:
## # A tibble: 3,322 x 9
## tailnum year type manufacturer model engines seats speed engine
## <chr> <int> <chr> <chr> <chr> <int> <int> <int> <chr>
## 1 n10156 2004 fixed wing m… embraer emb-1… 2 55 NA turbo-…
## 2 n102uw 1998 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 3 n103us 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 4 n104uw 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 5 n10575 2002 fixed wing m… embraer emb-1… 2 55 NA turbo-…
## 6 n105uw 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 7 n107us 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 8 n108uw 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 9 n109uw 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## 10 n110uw 1999 fixed wing m… airbus indust… a320-… 2 182 NA turbo-…
## # … with 3,312 more rows
Funkce mutate()
má ještě jednu mutaci: transmute()
a její sestry transmute_if()
, transmute_at()
a transmute_all()
. transmute()
poskytuje v podstatě stejnou funkcionalitu jako mutate()
, ale s jedním rozdílem. mutate()
mění pouze vytvářené sloupce a zbytek tabulky nechává v původní podobě. To neplatí pro transmute()
. transmute()
ve výstupní tabulce ponechá jen nově vytvořené sloupce (a sloupce použité ke grupování – viz dále):
planes %>%
transmute(
seats_per_engine = (seats/engines) %>% round(),
turbo_prop_plane = engine == "Turbo-prop"
)
## # A tibble: 3,322 x 2
## seats_per_engine turbo_prop_plane
## <dbl> <lgl>
## 1 28 FALSE
## 2 91 FALSE
## 3 91 FALSE
## 4 91 FALSE
## 5 28 FALSE
## 6 91 FALSE
## 7 91 FALSE
## 8 91 FALSE
## 9 91 FALSE
## 10 91 FALSE
## # … with 3,312 more rows
16.2.2 Agregace proměnných se summarise()
Podstatou agregace je shrnutí obsahu tabulky (jednoho nebo více sloupců) a vytvoření nové tabulky, která obsahuje tyto agregované hodnoty (typicky statistiky jako průměr, medián, minimum, atp.).
Pro tyto účely slouží v dplyr funkce summarise()
. Její použití se v logice velmi podobá mutate()
. To ilustruje následující příklad:
planes %>%
summarise(
min_year = min(year, na.rm = TRUE),
max_year = max(year, na.rm = TRUE),
min_engines = min(engines, na.rm = TRUE),
max_engines = max(engines, na.rm = TRUE)
)
## # A tibble: 1 x 4
## min_year max_year min_engines max_engines
## <int> <int> <int> <int>
## 1 1956 2013 1 4
V tomto volání funkce summarise()
jsou vytvořeny 4 agregované hodnoty: maxima a minima ze sloupců year
a engines
. Výsledkem je tabulka, která podle stanovených pravidel shrnuje celou tabulku do jediného řádku.
16.2.2.1 Varianty summarise()
dplyr obsahuje mutace summarise()
: summarise_if()
, summarise_at()
a summarise_all()
. Jejich použití je podobné jako v případě mutací mutate()
. V principu umožňují transformovat všechny sloupce (_all
), vyjmenované sloupce (_at
) nebo ty, které splňují určitou podmínku (_if
).
Užitečné může být například vypočítat průměr ze všech numerických proměnných:
## # A tibble: 1 x 4
## year engines seats speed
## <dbl> <dbl> <dbl> <dbl>
## 1 2000. 2.00 154. 237.