16.1 Slovesa pracující s jednou tabulkou

16.1.1 Výběr řádků (pozorování)

Základní funkcí, která umožňuje výběr řádků je filter(). Podobně jako většina funkcí z balíku dplyr má extrémně jednoduchou syntax:

filter(.data, ...)

Vstupem funkce je tabulka (.data) a jeden nebo více logických predikátů. Výstupem funkce je podmnožina řádků, která splňuje všechny zadané predikáty.

Například se můžeme chtít podívat na letadla, která vyrobil Airbus nebo Boeing a mají více než dva motory:

planes %>% 
    filter(manufacturer %in% c("AIRBUS INDUSTRIE","BOEING"), engines > 2)
## # A tibble: 2 x 9
##   tailnum  year type           manufacturer   model  engines seats speed engine 
##   <chr>   <int> <chr>          <chr>          <chr>    <int> <int> <int> <chr>  
## 1 N281AT     NA Fixed wing mu… AIRBUS INDUST… A340-…       4   375    NA Turbo-…
## 2 N670US   1990 Fixed wing mu… BOEING         747-4…       4   450    NA Turbo-…

Vybrány byly pouze řádky splňující všechny podmínky najednou. Následující volání filter(), které spojuje dvě výše použité podmínky do jedné logickým AND (&) proto vrátí stejný výsledek:

planes %>% 
    filter(manufacturer %in% c("AIRBUS INDUSTRIE","BOEING") & engines > 2)
## # A tibble: 2 x 9
##   tailnum  year type           manufacturer   model  engines seats speed engine 
##   <chr>   <int> <chr>          <chr>          <chr>    <int> <int> <int> <chr>  
## 1 N281AT     NA Fixed wing mu… AIRBUS INDUST… A340-…       4   375    NA Turbo-…
## 2 N670US   1990 Fixed wing mu… BOEING         747-4…       4   450    NA Turbo-…

Podmínky použité ve funkci filter() musí po vyhodnocení vracet logické hodnoty TRUE/FALSE. Ve filter() tedy můžeme používat funkce, které vracejí logickou hodnotu.

Například nás mohou zajímat všechna letadla z rodiny A340. Budeme tedy chtít vybrat všechny řádky, u nichž proměnná model začíná na “A340”. Kromě balíku dplyr budeme potřebovat i stringr:

library(stringr)

planes %>% 
    filter(str_detect(model,"^A340"))
## # A tibble: 1 x 9
##   tailnum  year type           manufacturer   model  engines seats speed engine 
##   <chr>   <int> <chr>          <chr>          <chr>    <int> <int> <int> <chr>  
## 1 N281AT     NA Fixed wing mu… AIRBUS INDUST… A340-…       4   375    NA Turbo-…

Je možné používat i funkce, které nevracejí logické hodnoty. V takové případě je však nutné jejich výsledek na logickou proměnou transformovat. Řekněme, že by nás zajímala letadla, kde na jeden motor připadá méně než 10 sedadel:

planes %>% 
    filter(seats/engines < 10)
## # A tibble: 39 x 9
##    tailnum  year type          manufacturer model   engines seats speed engine  
##    <chr>   <int> <chr>         <chr>        <chr>     <int> <int> <int> <chr>   
##  1 N201AA   1959 Fixed wing s… CESSNA       150           1     2    90 Recipro…
##  2 N202AA   1980 Fixed wing m… CESSNA       421C          2     8    90 Recipro…
##  3 N315AT     NA Fixed wing s… JOHN G HESS  AT-5          1     2    NA 4 Cycle 
##  4 N347AA   1985 Rotorcraft    SIKORSKY     S-76A         2    14    NA Turbo-s…
##  5 N350AA   1980 Fixed wing m… PIPER        PA-31-…       2     8   162 Recipro…
##  6 N364AA   1973 Fixed wing m… CESSNA       310Q          2     6   167 Recipro…
##  7 N365AA   2001 Rotorcraft    AGUSTA SPA   A109E         2     8    NA Turbo-s…
##  8 N376AA   1978 Fixed wing s… PIPER        PA-32R…       1     7    NA Recipro…
##  9 N377AA     NA Fixed wing s… PAIR MIKE E  FALCON…       1     2    NA Recipro…
## 10 N378AA   1963 Fixed wing s… CESSNA       172E          1     4   105 Recipro…
## # … with 29 more rows

Ve speciálních případech je užitečné vybírat řádky ne podle splnění určitých podmínek, ale podle jejich polohy. Pro tyto případy je v balíku dplyr obsažena funkce slice(), která jako argument přijímá čísla řádku, nebo rozsah řádků:

planes %>% 
    slice(1L:5L)
## # A tibble: 5 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 mu… EMBRAER        EMB-1…       2    55    NA Turbo-…
## 2 N102UW   1998 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
## 3 N103US   1999 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
## 4 N104UW   1999 Fixed wing mu… AIRBUS INDUST… A320-…       2   182    NA Turbo-…
## 5 N10575   2002 Fixed wing mu… EMBRAER        EMB-1…       2    55    NA Turbo-…

16.1.2 Výběr sloupců (proměnných)

Pro výběr sloupců slouží funkce select(). Syntax je podobná jako v případě filter():

select(.data, ...)

Do select() vstupuje tabulka a identifikace sloupců, které mají být vybrány. Například:

planes %>% 
    select(tailnum, manufacturer)
## # A tibble: 3,322 x 2
##    tailnum manufacturer    
##    <chr>   <chr>           
##  1 N10156  EMBRAER         
##  2 N102UW  AIRBUS INDUSTRIE
##  3 N103US  AIRBUS INDUSTRIE
##  4 N104UW  AIRBUS INDUSTRIE
##  5 N10575  EMBRAER         
##  6 N105UW  AIRBUS INDUSTRIE
##  7 N107US  AIRBUS INDUSTRIE
##  8 N108UW  AIRBUS INDUSTRIE
##  9 N109UW  AIRBUS INDUSTRIE
## 10 N110UW  AIRBUS INDUSTRIE
## # … with 3,312 more rows

Příklad ukazuje první a základní možnost, jak identifikovat sloupec – a to jeho jménem. select() však umožňuje specifikovat sloupec i pomocí čísla pozice.

Následující volání funkce select() tak vrací stejný výsledek, jako tomu byl v případě identifikace sloupců jejich jménem.

planes %>% 
    select(1,4)
## # A tibble: 3,322 x 2
##    tailnum manufacturer    
##    <chr>   <chr>           
##  1 N10156  EMBRAER         
##  2 N102UW  AIRBUS INDUSTRIE
##  3 N103US  AIRBUS INDUSTRIE
##  4 N104UW  AIRBUS INDUSTRIE
##  5 N10575  EMBRAER         
##  6 N105UW  AIRBUS INDUSTRIE
##  7 N107US  AIRBUS INDUSTRIE
##  8 N108UW  AIRBUS INDUSTRIE
##  9 N109UW  AIRBUS INDUSTRIE
## 10 N110UW  AIRBUS INDUSTRIE
## # … with 3,312 more rows
planes %>% names
## [1] "tailnum"      "year"         "type"         "manufacturer" "model"       
## [6] "engines"      "seats"        "speed"        "engine"

16.1.2.1 Funkce select() a speciální funkce

Při identifikaci sloupců je možné využít speciální funkce. Některé fungují pouze “uvnitř” select() a některých dalších funkcí z tidyverse.

První taková funkce je :. Umožňuje specifikovat rozsah sloupců, místo vypisování všech prvků. Všechny následující volání tak vrací stejný výsledek:

planes %>% 
    select(1,2,3,4,8)

planes %>% 
    select(tailnum, year, type, manufacturer, speed)

planes %>% 
    select(1:4, 8)

planes %>% 
    select(tailnum:manufacturer, speed)

Další speciální funkcí je - (mínus). Tato funkce umožňuje “negativní” výběr. Při jejím použití není sloupec zahrnut, ale naopak vypuštěn:

planes %>% 
    select(-tailnum, -year, -type, -manufacturer, -speed)
## # A tibble: 3,322 x 4
##    model     engines seats engine   
##    <chr>       <int> <int> <chr>    
##  1 EMB-145XR       2    55 Turbo-fan
##  2 A320-214        2   182 Turbo-fan
##  3 A320-214        2   182 Turbo-fan
##  4 A320-214        2   182 Turbo-fan
##  5 EMB-145LR       2    55 Turbo-fan
##  6 A320-214        2   182 Turbo-fan
##  7 A320-214        2   182 Turbo-fan
##  8 A320-214        2   182 Turbo-fan
##  9 A320-214        2   182 Turbo-fan
## 10 A320-214        2   182 Turbo-fan
## # … with 3,312 more rows

Speciální funkce je možné kombinovat – je například možné vypustit sloupce identifikované rozsahem (:):

planes %>% 
    select(-tailnum:-manufacturer, -speed)
## # A tibble: 3,322 x 4
##    model     engines seats engine   
##    <chr>       <int> <int> <chr>    
##  1 EMB-145XR       2    55 Turbo-fan
##  2 A320-214        2   182 Turbo-fan
##  3 A320-214        2   182 Turbo-fan
##  4 A320-214        2   182 Turbo-fan
##  5 EMB-145LR       2    55 Turbo-fan
##  6 A320-214        2   182 Turbo-fan
##  7 A320-214        2   182 Turbo-fan
##  8 A320-214        2   182 Turbo-fan
##  9 A320-214        2   182 Turbo-fan
## 10 A320-214        2   182 Turbo-fan
## # … with 3,312 more rows

Výsledné tabulky jsou pochopitelně shodné.

Obě tyto speciální funkce vyžadují přesnou specifikaci jména nebo pozice sloupce. V reálném životě občas pracujeme s poněkud vágnějším zadáním. Mohli bychom chtít například vybrat všechny sloupce, které obsahují informace o motorech. Ty jsou v tabulce planes dva engine (typ motoru) a engines (počet motorů).

První možností je samozřejmě možné použít následující volání a vybrat sloupce jejich výčtem:

planes %>% 
    select(engine,engines)

To však není praktické v případě, že pracujeme s větším množstvím sloupců, jejichž názvy jsou systematické. V tom případě je užitečné sáhnout po select helpers (funkcích pomocníčcích chcete-li). dplyr jich nabízí hned několik:

  • 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 – užitečné zejména při řazení sloupců

Pro výběr proměnných se vztahem k motorům lze použít hned tři funkce:

planes %>% 
    select(starts_with("engine"))

planes %>% 
    select(contains("engine"))

planes %>% 
    select(matches("^engine"))

První a třetí varianta vybere všechny sloupce, které začínají na “engine”. Druhé variantě postačí k výběru, že řetězec “engine” se vyskytuje kdekoliv ve jméně sloupce.

Select helpers mohou být kombinováni se všemi ostatními způsoby identifikace sloupců:

planes %>% 
    select(tailnum, starts_with("engine"))
## # A tibble: 3,322 x 3
##    tailnum engines engine   
##    <chr>     <int> <chr>    
##  1 N10156        2 Turbo-fan
##  2 N102UW        2 Turbo-fan
##  3 N103US        2 Turbo-fan
##  4 N104UW        2 Turbo-fan
##  5 N10575        2 Turbo-fan
##  6 N105UW        2 Turbo-fan
##  7 N107US        2 Turbo-fan
##  8 N108UW        2 Turbo-fan
##  9 N109UW        2 Turbo-fan
## 10 N110UW        2 Turbo-fan
## # … with 3,312 more rows

Select helper s velmi specifickým využitím je everything(), které slouží k vybrání všeho. Nebo lépe všeho ostatního. Pokud z nějakého důvodu chceme změnit pořadí sloupců v tabulce, potom se hodí právě everything().

planes %>% 
    select(engine, engines, everything())
## # A tibble: 3,322 x 9
##    engine   engines tailnum  year type          manufacturer  model  seats speed
##    <chr>      <int> <chr>   <int> <chr>         <chr>         <chr>  <int> <int>
##  1 Turbo-f…       2 N10156   2004 Fixed wing m… EMBRAER       EMB-1…    55    NA
##  2 Turbo-f…       2 N102UW   1998 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
##  3 Turbo-f…       2 N103US   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
##  4 Turbo-f…       2 N104UW   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
##  5 Turbo-f…       2 N10575   2002 Fixed wing m… EMBRAER       EMB-1…    55    NA
##  6 Turbo-f…       2 N105UW   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
##  7 Turbo-f…       2 N107US   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
##  8 Turbo-f…       2 N108UW   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
##  9 Turbo-f…       2 N109UW   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
## 10 Turbo-f…       2 N110UW   1999 Fixed wing m… AIRBUS INDUS… A320-…   182    NA
## # … with 3,312 more rows

Změní pořadí sloupců tak, že na první pozici přesune engine a engines a následně do tabulky vyskládá všechny ostatní sloupce. Díky everything() není nutné jejich jména vypisovat.

16.1.2.2 Výběr a přejmenování sloupce

Jednou ze speciálních funkcí je i =. To slouží v select() pro přejmenování. Například volání

planes %>% 
    select(tailnum, company = manufacturer)
## # A tibble: 3,322 x 2
##    tailnum company         
##    <chr>   <chr>           
##  1 N10156  EMBRAER         
##  2 N102UW  AIRBUS INDUSTRIE
##  3 N103US  AIRBUS INDUSTRIE
##  4 N104UW  AIRBUS INDUSTRIE
##  5 N10575  EMBRAER         
##  6 N105UW  AIRBUS INDUSTRIE
##  7 N107US  AIRBUS INDUSTRIE
##  8 N108UW  AIRBUS INDUSTRIE
##  9 N109UW  AIRBUS INDUSTRIE
## 10 N110UW  AIRBUS INDUSTRIE
## # … with 3,312 more rows

vybere sloupce tailnum a manufacturer. Sloupec manufacturer však zároveň přejmenuje na company.

Speciálně pro přejmenovávání sloupců je v dplyr obsažena funkce rename() (fakticky jde jen o lehkou mutaci select()). Ta sloupce nevybírá, ale jen přejmenovává. Použití = je v ní povinné:

planes %>% 
    rename(tailnum, company = manufacturer)
## Error: All renaming inputs must be named.

Po opravě získáme správný výsledek:

planes %>% 
    rename(company = manufacturer)
## # A tibble: 3,322 x 9
##    tailnum  year type           company      model   engines seats speed engine 
##    <chr>   <int> <chr>          <chr>        <chr>     <int> <int> <int> <chr>  
##  1 N10156   2004 Fixed wing mu… EMBRAER      EMB-14…       2    55    NA Turbo-…
##  2 N102UW   1998 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
##  3 N103US   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
##  4 N104UW   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
##  5 N10575   2002 Fixed wing mu… EMBRAER      EMB-14…       2    55    NA Turbo-…
##  6 N105UW   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
##  7 N107US   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
##  8 N108UW   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
##  9 N109UW   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
## 10 N110UW   1999 Fixed wing mu… AIRBUS INDU… A320-2…       2   182    NA Turbo-…
## # … with 3,312 more rows

Tabulka obsahuje všechny sloupce, ale jeden z nich byl přejmenován.

16.1.2.3 Výběr a přejmenování sloupců podle jejich charakteristik

dplyr obsahuje dodatečné mutace funkce select(). Zajímavé jsou zejména dva.

select_if() umožňuje vybírat sloupce podle toho, zda splňují zadanou podmínku. V následujícím případě jsou vybrány pouze sloupce, které obsahují numerickou (tedy double nebo integer) proměnnou:

planes %>% 
    select_if(is.numeric)
## # A tibble: 3,322 x 4
##     year engines seats speed
##    <int>   <int> <int> <int>
##  1  2004       2    55    NA
##  2  1998       2   182    NA
##  3  1999       2   182    NA
##  4  1999       2   182    NA
##  5  2002       2    55    NA
##  6  1999       2   182    NA
##  7  1999       2   182    NA
##  8  1999       2   182    NA
##  9  1999       2   182    NA
## 10  1999       2   182    NA
## # … with 3,312 more rows

Parametrem select_if() je funkce vracející logickou hodnotu (TRUE/FALSE), která je použita pro vyhodnocení. Klíčové je, že parametrem je funkce samotná a ne hodnota funkcí vrácená. Co to znamená v praxi napoví následující volání, které se od předchozího příkazu liší pouze minimálně:

planes %>% 
    select_if(is.numeric())
## Error in is.numeric(): 0 arguments passed to 'is.numeric' which requires 1

Výsledek není tabulka s vybranými sloupci, ale chyba. Kde vznikl problém? V korektním volání byla funkce is.numeric použita bez závorek. select_if() si takto zadanou funkci vyhodnotí vnitřně a dodá očekávaný výsledek. V druhém případě se R nejprve pokusí is.numeric() vyhodnotit a výsledek předat select_if(). To nemůže fungovat – funkce neví, nad jakým sloupcem se má vyhodnotit.

V select_if() je možné používat uživatelem definované funkce i lambda funkce – viz následující příklad ve kterém obě volání select_if() budou vracet stejný výsledek: všechny sloupce tabulky planes.

return_true <- function(x) return(TRUE)

planes %>% 
    select_if(return_true)

planes %>% 
    select_if(function(x) return(TRUE))

Kromě funkce, která rozhoduje o vybrání sloupce má select_if() i další argument .funs:

select_if(.tbl, .predicate, .funs = list(), ...)

Tento argument slouží pro přejmenovávání a jeho použití není povinné. Je opět možné použít jméno funkce nebo lambda funkci.

Následující volání vybere všechny numerické sloupce a přejmenuje je – jména sloupců budou napsána velkými písmeny.

planes %>% 
    select_if(is.numeric, toupper)
## # A tibble: 3,322 x 4
##     YEAR ENGINES SEATS SPEED
##    <int>   <int> <int> <int>
##  1  2004       2    55    NA
##  2  1998       2   182    NA
##  3  1999       2   182    NA
##  4  1999       2   182    NA
##  5  2002       2    55    NA
##  6  1999       2   182    NA
##  7  1999       2   182    NA
##  8  1999       2   182    NA
##  9  1999       2   182    NA
## 10  1999       2   182    NA
## # … with 3,312 more rows

Dodatečné argumenty pro funkci, která provádí přejmenování lze předat přes ....

select_if() má variantu rename_if(), která vrátí všechny sloupce, ale jen ty, které odpovídají zadané podmínce jsou přejmenovány:

planes %>% 
    rename_if(is.numeric, toupper)
## # 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

Pokud je potřeba přejmenovat hromadně všechny sloupce a ne jen některé, potom je možné použít select_all() nebo rename_all(). Obě funkce jsou zaměnitelné.

Další užitečnou variantou select() je select_at():

select_at(.tbl, .vars, .funs = list(), ...)

Funkce ze vstupní tabulky .tbl vybere sloupce specifikované v parametru .var. Pro specifikaci může být použit vektor řetězců jmen sloupců, vektor jejich pozic:

planes %>% 
    select_at(c("tailnum","year"))
## # A tibble: 3,322 x 2
##    tailnum  year
##    <chr>   <int>
##  1 N10156   2004
##  2 N102UW   1998
##  3 N103US   1999
##  4 N104UW   1999
##  5 N10575   2002
##  6 N105UW   1999
##  7 N107US   1999
##  8 N108UW   1999
##  9 N109UW   1999
## 10 N110UW   1999
## # … with 3,312 more rows

Další variantou je specifikace sloupců pomocí seznamu (list) generovaného pomocí funkce vars(). Tato varianta je zajímavá zejména pro pokročilejší uživatele a programátory.

Stejného výsledku jako u výše uvedeného příkladu využití select_at() je možné dosáhnout například s pomocí select helper one_of():

planes %>% 
    select(
        one_of(
            c("tailnum","year")
            )
        )

select_at() však přináší možnost vybrané sloupce hromadně přejmenovat s pomocí funkce definované v parametru .funs.