11  Práce s řádky

Obdobně jako je funkce select() neocenitelným pomocníkem pro práci se sloupci dataframů, její příbuzná filter() nám dobře poslouží pro filtrování řádků. Tato kapitola je věnována právě jí, ale také rodině funkcí slice() a funkci arrange().

11.1 Filtrování řádků

Pro filtrování řádků je třeba trocha výrokové logiky. Základními logickými operátory v R jsou == (EQUAL), | (OR) a & (AND). Nepřekvapivě, pro HIGHER THAN používám >=, naopak pro LOWER THAN slouží <=. Negace se provádí pomocí vykřičníku, tedy například NOT EQUAL je !=.

Vybaveni těmito znalostmi, filtrování řádků není obtížný úkol. Hlavní funkcí je zde filter():

filter(countries, postsoviet == "yes" & gdp > 100000)
# A tibble: 5 × 17
  country code       gdp population   area eu_member postsoviet life_exp uni_prc
  <chr>   <chr>    <dbl>      <dbl>  <dbl> <chr>     <chr>         <dbl>   <dbl>
1 Czechia CZ     207772.   10610055  78867 yes       yes            79.2   0.217
2 Germany DE    3386000    82792351 357022 yes       yes            81     0.252
3 Hungary HU     131935.    9778371  93028 yes       yes            76     0.217
4 Poland  PL     496462.   37976687 312685 yes       yes            77.8   0.272
5 Romania RO     202884.   19530631 238391 yes       yes            75.2   0.155
# ℹ 8 more variables: poverty_risk <dbl>, material_dep <dbl>, hdi <dbl>,
#   foundation_date <date>, maj_belief <chr>, dem_index <dbl>, di_cat <chr>,
#   hd_title_name <chr>

Podmínky filtrování lze kombinovat, například vyfiltrovat pouze postsovětské země s hrubým domácím produktem větším než 100 000 miliónů euro.

Tip%in% místo |

Občas je naším cílem vyfiltrovat řádky obsahující některou z vybraných hodnot kategoriální proměnné, například všechny náboženské skupiny spadající pod křesťanství. Jednou možností je:

filter(countries, maj_belief == "catholic" | maj_belief == "orthodox" | maj_belief == "protestantism")

Tento přístup funguje, je ale zbytečně květnatý. Místo něj je možné aplikovat operátor %in%, pomocí kterého můžeme vyfiltrovat všechny hodnoty objevující se ve zvoleném vektoru:

filter(countries, maj_belief %in% c("catholic", "orthodox", "protestantism"))

Oba tyto příkazy vedou ke stejnému výsledku, ten druhý je ale výrazně kompaktnější.

Zároveň se může stát, že je někdy jednodušší vyjmenovat hodnoty, které ve výběru nechceme, než ty, které tam chceme. I pro to existuje elegantní řešení, které využívá znak !, jehož význam v jazyce R je negace čili logické NOT. Například pokud bychom chtěli všechny země, které nemají jako majoritní některé z křesťanských nábožesntví:

filter(countries, !maj_belief %in% c("catholic", "orthodox", "protestantism"))

Jak si jistě dokážete představit, funkce select() a filter() jsou často využívané dohromady:

countries %>% 
  filter(postsoviet == "yes") %>% 
  select(country, postsoviet, life_exp)
# A tibble: 16 × 3
   country                postsoviet life_exp
   <chr>                  <chr>         <dbl>
 1 Bulgaria               yes            74.8
 2 Czechia                yes            79.2
 3 Germany                yes            81  
 4 Estonia                yes            77.8
 5 Croatia                yes            78.3
 6 Latvia                 yes            75  
 7 Lithuania              yes            75  
 8 Hungary                yes            76  
 9 Poland                 yes            77.8
10 Romania                yes            75.2
11 Slovenia               yes            80.9
12 Slovakia               yes            77.4
13 North Macedonia        yes            75.9
14 Albania                yes            76.4
15 Serbia                 yes            76.3
16 Bosnia and Herzegovina yes            77.3

11.2 Řezání dataframů

V některých případech budeme chtít filtrovat na základě pořadí řádků dataframů. K tomu nám poslouží rodina funkcí slice z balíčku dplyr.

Prvním členem této rodiny je funkce slice(). Její aplikace je velmi podobná klasickému indexování pomocí hranatých závorek. Například výběr prvního řádku v dataframu:

slice(countries, 1)

Je ekvivalentní countries[1, ] a vrátí první řádek dataframu. Obdobně podobné jsou i funkce slice(countries, -1) a countries[-1, ], které vrátí všechny řádky kromě prvního. Funkce slice() je však pouze základem pro řadu dalších užitečných funkcí.

Další dvě funkce, které nám již svým fungováním budou povědomé jsou slice_head() a slice_tail(). Ty, obdobně jako funkce head() a tail(), vrátí prvních n řádků v dataframů. Na rozdíl od svých příbuzných ze základní instalace R, ovšem slice funkce umožňují vybrat nejen absolutní, ale i relativní počet řádků. Například pro vybrání prvních deseti procent dataframu:

slice_head(countries, prop = 0.1)

Pro vybrání absolutního počtu řádku slouží argument n.

O něco zajímavější jsou funkce slice_max() a slice_min(). Ty umožňují vybrat n řádků s nejvyšší, respektive nejnižší, hodnou dané proměnné. Pomocí těchto funkcí můžeme například jednoduše zjistit, které tři země v našem dataframu mají nejvyšší naději na dožití:

slice_max(countries, order_by = life_exp, n = 3) %>% 
  select(country, life_exp)
# A tibble: 3 × 2
  country     life_exp
  <chr>          <dbl>
1 Switzerland     83.3
2 Spain           83.1
3 France          82.9

a které naopak nejnižší:

slice_min(countries, order_by = life_exp, n = 3) %>% 
  select(country, life_exp)
# A tibble: 3 × 2
  country   life_exp
  <chr>        <dbl>
1 Bulgaria      74.8
2 Latvia        75  
3 Lithuania     75  

Funkce slice_max() a slice_min() jsme zde zkombinovali s funkcí select(), abychom vybrali jen relevantní proměnné.

Posledním členem rodiny je funkce slice_sample(), která vybere náhodné řádky dataframu. Tato funkce najde uplatnění zejména v simulačních studiích a technikách.

slice_sample(countries, n = 3)

11.3 Podskupiny v datech

V tuto chvíli si možná někteří čtenáři říkají, jaké je využití slice funkcí oproti jejich klasickým variantám, jako je head() nebo tail(). Jednou z jejich předností je možnost kombinovat je s funkcionalitou by, což je možnost, jak můžeme různým funkcím z balíku dplyr přikázat, aby požadovanou operaci provedly zvlášť pro různé podskupiny.

Funkcionalita se vyvolá použitím argumentu by uvnitř funkce. Podskupiny jsou definované kategorickou proměnnou v dataframu. Tímto způsobem můžeme zjistit, nejen které země se těší nejvyšší naději na dožití obecně, ale i to, jak jsou na tom postsovětské a ostatní země zvlášť:

countries %>% 
  slice_max(order_by = life_exp, n = 3, by = postsoviet) %>% 
  select(country, postsoviet, life_exp)
# A tibble: 6 × 3
  country     postsoviet life_exp
  <chr>       <chr>         <dbl>
1 Switzerland no             83.3
2 Spain       no             83.1
3 France      no             82.9
4 Germany     yes            81  
5 Slovenia    yes            80.9
6 Czechia     yes            79.2

Zatímco mezi nepostsovětskými zeměmi vedou Švýcarsko, Španělsko a Francie, v postsovětské skupině je to Německo, Slovinsko a Česká republika. Třídit je možné i pomocí většího počtu proměnných, například pro třídění podle postsovětské historie a členství v Evropské unii takto:

countries %>% 
  slice_max(order_by = life_exp, n = 1, by = c(postsoviet, eu_member)) %>% 
  select(country, postsoviet, eu_member, life_exp)
# A tibble: 4 × 4
  country                postsoviet eu_member life_exp
  <chr>                  <chr>      <chr>        <dbl>
1 Spain                  no         yes           83.1
2 Germany                yes        yes           81  
3 Switzerland            no         no            83.3
4 Bosnia and Herzegovina yes        no            77.3

Využití argumentu by ve spojení s funkcemi pro manipulaci s daty z balíku dplyr má široke využití, které bude dále ilustrováno v různých situacích.

Poznámka

Argument by byl představen teprve ve verzi dplyr 1.1.0 v roce 2023 jako alternativa pro do té doby používanou funkci group_by(). V jejím případě šlo na rozdíl od argumentu by o samostantou funkci, která dataset rozdělila na podskupiny typicky až do odvolání pomocí funkce ungroup(). Ve většině případů nám přijde vhodnější používat argument by, přestože varianta group_by() je také dále dostupná. Pro případ uvedený výše by fungovala takto:

countries %>% 
  group_by(postsoviet, eu_member) |> 
  slice_max(order_by = life_exp, n = 1) %>% 
  select(country, postsoviet, eu_member, life_exp) |> 
  ungroup()
# A tibble: 4 × 4
  country                postsoviet eu_member life_exp
  <chr>                  <chr>      <chr>        <dbl>
1 Switzerland            no         no            83.3
2 Spain                  no         yes           83.1
3 Bosnia and Herzegovina yes        no            77.3
4 Germany                yes        yes           81  

Pokud bychom nepřipojili závěrečné ungroup() dostali bychom stejné hodnoty, výsledek by nicméně zůstal rozdělen na čtyři podksupiny i pro případné další operace.

11.4 Pořadí řádků

Posledním typem operace, kterou si v této kapitole představíme, je řazení řádků pomocí funkce arrange(). Pořadí zemí v dataframu countries podle naděje na dožití získáme jednoduše:

countries %>% 
  arrange(life_exp) %>% 
  select(country, life_exp)
# A tibble: 38 × 2
   country         life_exp
   <chr>              <dbl>
 1 Bulgaria            74.8
 2 Latvia              75  
 3 Lithuania           75  
 4 Romania             75.2
 5 North Macedonia     75.9
 6 Hungary             76  
 7 Serbia              76.3
 8 Albania             76.4
 9 Turkey              76.4
10 Montenegro          76.8
# ℹ 28 more rows

Při bližším pohledu zjistíme, že země jsou seřazený vzestupně. Nejhůře se vede Bulhrasko a Litva s Lotyšskem. Co kdyby nás ale zajímaly země s nejvyšší nadějí na dožití? Pro sestupné řazení zkombinujeme funkci arrange() se znaménkem -:

countries %>% 
  arrange(-life_exp) %>% 
  select(country, life_exp)
# A tibble: 38 × 2
   country     life_exp
   <chr>          <dbl>
 1 Switzerland     83.3
 2 Spain           83.1
 3 France          82.9
 4 Italy           82.8
 5 Norway          82.5
 6 Luxembourg      82.4
 7 Sweden          82.4
 8 Iceland         82.4
 9 Austria         81.9
10 Netherlands     81.6
# ℹ 28 more rows

Nejvyšší naději na dožití se těší Švýcarsko, se Španělskem v těsném závěsu.

::: callout info Alternativně se lze setkat také s využitím funkce desc() ve smyslu anglického slova “descending”. Tuto variantu nepreferujeme, protože zmamená více psaní:

countries %>% 
  arrange(desc(life_exp)) %>% 
  select(country, life_exp)
# A tibble: 38 × 2
   country     life_exp
   <chr>          <dbl>
 1 Switzerland     83.3
 2 Spain           83.1
 3 France          82.9
 4 Italy           82.8
 5 Norway          82.5
 6 Luxembourg      82.4
 7 Sweden          82.4
 8 Iceland         82.4
 9 Austria         81.9
10 Netherlands     81.6
# ℹ 28 more rows

:::