14.1 Práce s tidyverse

14.1.1 Trubky/pipes

S pomocí tidyverse je možné psát velmi dobře srozumitelný kód. Hadley Wickham, který stojí za vytvořením podstatné části tidyverse, při popisu balíků mluví o konceptu “gramatiky práce s daty” a “gramatice vizualizace dat.”

Průběh datové analýzy můžeme popsat jako sekvenci úkonů. Například:

  1. Načti data.
  2. Vezmi načtenou tabulku a vyber z ní několik sloupců.
  3. Vezmi upravenou tabulku a vyber pouze řádky, které splňují určité podmínky.
  4. Vezmi upravenou tabulku a na jejím základě vykresli obrázek.
  5. Výsledek ulož do proměnné x.

Každý krok přitom využívá výsledek kroku předchozího. Pro podobné řetezení kroků využívá tidyverse speciální funkci %>% (tzv. trubku/pipe), které spojuje dva kroky. Výstup prvního kroku vkládá jako vstup do následujícího kroku. Předchozí sekvenci kroků bychom tedy mohli schématicky zapsat následujícím způsobem:

x <- read_tsv() %>%  # Načti data
  select() %>%       # Vyber sloupce
  filter() %>%       # Vyber řádky
  ggplot()           # Vykresli data

Ukázka kódu není funkční – funkce nemají zadané žádné parametry, ale ukazuje logiku celého přístupu. Výsledný kód svou strukturou připomíná strukturu psaného jazyka. Intrukce přehledně plyne zleva do prava, podobně jako text v knize.

Bez použití funkce %>% by postup vypadal následovně:

x <- read_tsv()
x <- select(x)
x <- filter(x)
x <- ggplot(x)

Výsledek by byl zcela identický (a provedení kódu u velkých tabulek o maličko rychlejší). Výhodou trubek je však čitelnost a přehlednost. Praxe ukazuje, že mít jasný a čístý kód je v praxi datové analýzy často důležitější než marginální ztráta rychlosti.

V tomto kurzu budeme od této chvíle často používat funkci %>%. Pokud si oblíbíte používání trubek, můžete se podívat na balík magrittr, který kromě %>% implementuje i další trubkoidní funkce.

14.1.1.1 Placeholder “.”

Funkce %>% ja nastavená tak, že obsah, který ji protéká vždy umisťuje do prvního parametru přijímající funkce. To je skoro vždy žádoucí chování, ale ne vždy. Modifikovat je ho možné s použítím symbolu ., který určuje místo, na které má trubka přenášený obsah umístit.

Můžeme si například představit situaci, kdy máme vektory x a w. Chceme spočítát vážený průměr x, ale trubkou nám putuje vektor vah w. Požadovaného výsledku dosáhneme takto:

w %>% weighted.mean(x,.)

14.1.2 Subsetování

tidyverse, konkrétně balík dplyr obsahuje funkce pro subsetování. Zběžně se nyní seznámí s funkcí select(), která slouží k výběru sloupců. Na jejím příkladě si ukážeme, jak se v tidyverse zachází se jmény sloupců.

Základní syntaxe select() je triviální:

select(.data, ...)

Prvním parametrem je vstupní tabulka. V parametru ... jsou specifikovány sloupce.

Jako ukázkovou tabulku budeme používat us_rent_income z balíku tidyr:

us_rent_income
## # A tibble: 104 × 5
##    GEOID NAME       variable estimate   moe
##    <chr> <chr>      <chr>       <dbl> <dbl>
##  1 01    Alabama    income      24476   136
##  2 01    Alabama    rent          747     3
##  3 02    Alaska     income      32940   508
##  4 02    Alaska     rent         1200    13
##  5 04    Arizona    income      27517   148
##  6 04    Arizona    rent          972     4
##  7 05    Arkansas   income      23789   165
##  8 05    Arkansas   rent          709     5
##  9 06    California income      29454   109
## 10 06    California rent         1358     3
## # … with 94 more rows

Poznámka: Speciální metody výběru sloupců jsou implementovány v balíku tidyselect, Ten si však nemusíte vždy loadovat. Balíky z tidyverse si vše vyřeší samy.

14.1.2.1 Non-standard evaluation a identifikace jménem sloupce

tidyverse používá tzv. nestandardní evaluaci. Ta je výhodná zvláště při interaktivní práci s daty. Praktickým dopadem je, že se jména sloupců píšou bez úvozovek. První možností jak identifikovat sloupec je tedy jménem bez úvozovek. Můžeme vybrat jeden:

us_rent_income %>% 
  select(variable)
## # A tibble: 104 × 1
##    variable
##    <chr>   
##  1 income  
##  2 rent    
##  3 income  
##  4 rent    
##  5 income  
##  6 rent    
##  7 income  
##  8 rent    
##  9 income  
## 10 rent    
## # … with 94 more rows

Nebo více sloupců:

us_rent_income %>% 
  select(variable,estimate)
## # A tibble: 104 × 2
##    variable estimate
##    <chr>       <dbl>
##  1 income      24476
##  2 rent          747
##  3 income      32940
##  4 rent         1200
##  5 income      27517
##  6 rent          972
##  7 income      23789
##  8 rent          709
##  9 income      29454
## 10 rent         1358
## # … with 94 more rows

14.1.2.2 Identifikace pozicí

Vedle jména je možné pro identifikaci sloupce použít číslo jeho pozice:

us_rent_income %>% 
  select(1,2,4)
## # A tibble: 104 × 3
##    GEOID NAME       estimate
##    <chr> <chr>         <dbl>
##  1 01    Alabama       24476
##  2 01    Alabama         747
##  3 02    Alaska        32940
##  4 02    Alaska         1200
##  5 04    Arizona       27517
##  6 04    Arizona         972
##  7 05    Arkansas      23789
##  8 05    Arkansas        709
##  9 06    California    29454
## 10 06    California     1358
## # … with 94 more rows

14.1.2.3 Speciální funkce

Funkce, které potřebují specifikaci sloupců umí pracovat se speciálními funkcemi, které budou fungovat pouze v jejich rámci. Základní speciální funkce jsou dvě: - a :.

Funkce - umožňuje negativní výběr – “vyber všechno až na.” Následující volání funkce select() tak vrátí všechny sloupce až na GEOID a NAME:

us_rent_income %>% 
  select(-GEOID,-NAME)
## # A tibble: 104 × 3
##    variable estimate   moe
##    <chr>       <dbl> <dbl>
##  1 income      24476   136
##  2 rent          747     3
##  3 income      32940   508
##  4 rent         1200    13
##  5 income      27517   148
##  6 rent          972     4
##  7 income      23789   165
##  8 rent          709     5
##  9 income      29454   109
## 10 rent         1358     3
## # … with 94 more rows

Funkce : umožňuje specifikovat rozsah sloupců. To lze využít pokud chceme například vybrat sloupce GEOID a všechny sloupce mezi variable a moe:

us_rent_income %>% 
  select(GEOID, variable:moe)
## # A tibble: 104 × 4
##    GEOID variable estimate   moe
##    <chr> <chr>       <dbl> <dbl>
##  1 01    income      24476   136
##  2 01    rent          747     3
##  3 02    income      32940   508
##  4 02    rent         1200    13
##  5 04    income      27517   148
##  6 04    rent          972     4
##  7 05    income      23789   165
##  8 05    rent          709     5
##  9 06    income      29454   109
## 10 06    rent         1358     3
## # … with 94 more rows

Speciální funkce fungují i při identifikace sloupců jejich pozicí…

us_rent_income %>% 
  select(-1,-2)
## # A tibble: 104 × 3
##    variable estimate   moe
##    <chr>       <dbl> <dbl>
##  1 income      24476   136
##  2 rent          747     3
##  3 income      32940   508
##  4 rent         1200    13
##  5 income      27517   148
##  6 rent          972     4
##  7 income      23789   165
##  8 rent          709     5
##  9 income      29454   109
## 10 rent         1358     3
## # … with 94 more rows
us_rent_income %>% 
  select(1,3:5)
## # A tibble: 104 × 4
##    GEOID variable estimate   moe
##    <chr> <chr>       <dbl> <dbl>
##  1 01    income      24476   136
##  2 01    rent          747     3
##  3 02    income      32940   508
##  4 02    rent         1200    13
##  5 04    income      27517   148
##  6 04    rent          972     4
##  7 05    income      23789   165
##  8 05    rent          709     5
##  9 06    income      29454   109
## 10 06    rent         1358     3
## # … with 94 more rows

…a je možné je kombinovat

us_rent_income %>% 
  select(-variable:-moe)
## # A tibble: 104 × 2
##    GEOID NAME      
##    <chr> <chr>     
##  1 01    Alabama   
##  2 01    Alabama   
##  3 02    Alaska    
##  4 02    Alaska    
##  5 04    Arizona   
##  6 04    Arizona   
##  7 05    Arkansas  
##  8 05    Arkansas  
##  9 06    California
## 10 06    California
## # … with 94 more rows

14.1.2.4 Funkce pomocníčci: select helpers

Balík tidyselect obshauje funkce, které umožňují identifikovat sloupce jinak než přímým zadáním jména nebo pozice:

  • starts_with() vybírá sloupce, jejichž jméno začíná na řetězec, který je argumentem funkce starts_with()
  • ends_with() vybírá sloupce, jejichž jméno končí na řetězec, který je argumentem funkce ends_with()
  • contains() vybírá sloupce, jejichž jméno obsahuje řetězec, který je argumentem funkce contains()
  • matches() vybírá sloupce, jejichž jméno odpovídá zadanému regulárnímu výrazu
  • num_range() slouží pro výběr sloupců, jejichž jméno je tvořeno kombinací řetězce a čísla – například trial_1, trial_2,…
  • one_of() vrátí sloupce, jejichž jména jsou obsažena ve vektoru, který je vstupem funkce
  • everything() vrací všechny sloupce
  • last_col() vrací poslední sloupec

Tyto funkce opět fungují jenom “uvnitř” kompatibilních funkcí. K subsetování se v mírně větším detailu vrátíme znovu v kapitole věnované balíku dplyr.