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. Zachovává tedy počet řádků v tabulce a přidává nové sloupce. Syntax mutate()
je podobně jako u dalších funkcí z tidyverse poměrně střídmá:
mutate(.data, ...)
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"
#%>% )
## # A tibble: 3,322 × 11
## 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, and 2 more variables: seats_per_engine <dbl>,
## # turbo_prop_plane <lgl>
#select(seats_per_engine, turbo_prop_plane, everything())
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. Verze 1.0.0 umožňuje nastavit, kde se v tabulce nové sloupce vytvoří, nicméně tato funkcionalita je stále ve fázi vývoje.
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:
%>%
planes mutate(
year = log(year)
)
## # A tibble: 3,322 × 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
.
<- TRUE
x
%>%
planes mutate(
this_is_true = x
%>%
) select(this_is_true, everything())
## # A tibble: 3,322 × 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 Fixed win… EMBRAER EMB-… 2 55 NA
## 2 TRUE N102UW 1998 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 3 TRUE N103US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 4 TRUE N104UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 5 TRUE N10575 2002 Fixed win… EMBRAER EMB-… 2 55 NA
## 6 TRUE N105UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 7 TRUE N107US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 8 TRUE N108UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 9 TRUE N109UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 10 TRUE N110UW 1999 Fixed win… AIRBUS INDUS… 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):
<- c(TRUE, TRUE, TRUE)
x
%>%
planes mutate(
this_is_true = x
%>%
) select(this_is_true, everything())
## Error: Problem with `mutate()` column `this_is_true`.
## ℹ `this_is_true = x`.
## ℹ `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:
<- 1:nrow(planes)
x
%>%
planes mutate(
new_variable = x
%>%
) select(new_variable, everything())
## # A tibble: 3,322 × 10
## new_variable tailnum year type manufacturer model engines seats speed
## <int> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 1 N10156 2004 Fixed win… EMBRAER EMB-… 2 55 NA
## 2 2 N102UW 1998 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 3 3 N103US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 4 4 N104UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 5 5 N10575 2002 Fixed win… EMBRAER EMB-… 2 55 NA
## 6 6 N105UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 7 7 N107US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 8 8 N108UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 9 9 N109UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 10 10 N110UW 1999 Fixed win… AIRBUS INDUS… 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.
%>%
planes mutate(
new_variable = rnorm(1)
%>%
) select(new_variable, everything())
## # A tibble: 3,322 × 10
## new_variable tailnum year type manufacturer model engines seats speed
## <dbl> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 0.328 N10156 2004 Fixed win… EMBRAER EMB-… 2 55 NA
## 2 0.328 N102UW 1998 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 3 0.328 N103US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 4 0.328 N104UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 5 0.328 N10575 2002 Fixed win… EMBRAER EMB-… 2 55 NA
## 6 0.328 N105UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 7 0.328 N107US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 8 0.328 N108UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 9 0.328 N109UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 10 0.328 N110UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
%>%
planes mutate(
new_variable = rnorm(nrow(planes))
%>%
) select(new_variable, everything())
## # A tibble: 3,322 × 10
## new_variable tailnum year type manufacturer model engines seats speed
## <dbl> <chr> <int> <chr> <chr> <chr> <int> <int> <int>
## 1 3.02 N10156 2004 Fixed win… EMBRAER EMB-… 2 55 NA
## 2 -0.147 N102UW 1998 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 3 -0.544 N103US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 4 -1.02 N104UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 5 0.0999 N10575 2002 Fixed win… EMBRAER EMB-… 2 55 NA
## 6 0.563 N105UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 7 0.876 N107US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 8 -0.130 N108UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 9 -0.619 N109UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 10 1.05 N110UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## # … with 3,312 more rows, and 1 more variable: engine <chr>
%>%
planes mutate(
new_variable = rnorm(3)
%>%
) select(new_variable, everything())
## Error: Problem with `mutate()` column `new_variable`.
## ℹ `new_variable = rnorm(3)`.
## ℹ `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:
<- TRUE
tailnum
%>%
planes mutate(
this_is_true = tailnum
%>%
) select(this_is_true, everything())
## # A tibble: 3,322 × 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 Fixed win… EMBRAER EMB-… 2 55 NA
## 2 N102UW N102UW 1998 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 3 N103US N103US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 4 N104UW N104UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 5 N10575 N10575 2002 Fixed win… EMBRAER EMB-… 2 55 NA
## 6 N105UW N105UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 7 N107US N107US 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 8 N108UW N108UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 9 N109UW N109UW 1999 Fixed win… AIRBUS INDUS… A320… 2 182 NA
## 10 N110UW N110UW 1999 Fixed win… AIRBUS INDUS… 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:
%>%
planes mutate(
mean_year = mean(year, na.rm = TRUE)
%>%
) select(mean_year, everything())
## # A tibble: 3,322 × 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.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 × 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.