--- title: "Tidy data s nástroji z balíku tidyr" author: "Štěpán Mikula" documentclass: article output: pdf_document: default html_document: theme: cerulean toc: yes toc_float: yes fontsize: 10pt classoption: a4paper --- # Správně formátovaná data a balík `tidyr` {#kap:tidyr} *"It is often said that 80 % of data analysis is spent on the cleaning and preparing data."* *"Tidy datasets are all alike but every messy dataset is messy in its own way."* – Hadley Wickham Představte si výzkum vývoje dětí. Z populace si vybereme vzorek dětí, které budeme sledovat a následně u každého z nich každý měsíc naměříme řadu ukazatelů: výšku, váhu, počet červených krvinek, motorické a kognitivní schopnosti, počet prstů, atp. Získáme tak soubor dat s mnoha pozorováními a mnoha dimenzemi. Jedno pozorování můžeme chápat jako moment měření -- definuje ho tedy identita pozorovaného subjektu (průřezová jednotka) a čas pozorování (věk). Každá sledovaná charakteristika potom představuje samostatnou dimenzi. Množství pozorování a dimenzí umožňuje nejrůznější organizaci naměřených dat. Data jsou typicky organizována do formátu pravoúhlé tabulky, kde jsou data zapsána v buňkách organizovaných v řádcích a sloupcích. Tabulky však mohou být různě vnitřeně organizované. Mohou se lišit v tom, které údaje se zapisují do sloupců, které do řádků a podobně V této lekci se naučíte: - Jak vhodně organizovat data do tabulek -- tzv. *tidy* formát - S pomocí nástrojů z balíku *tidyr* upravovat data do *tidy* formátu Balík *tidyr* je součástí *tidyverse* a je třeba si ho nejprve načíst do paměti. ## Tidy data {#sec:tidy-data-def} Formát *"tidy data"* popisuje organizační strukturu dat v tabulkách. Data v tidy formátu splňují následující charakteristiky: 1. Každé pozorování je popsáno jedním řádkem 1. Každá proměnná je obsažena v jednom sloupci 1. Každý typ pozorování má vlastní tabulku Wickham (2016) ilustruje tidy fromát pomocí následujícího schématu: ![Struktura tidy dat (Wickham, 2016)](figs/tidyr/tidy-1.png){width=100%} Uvažujme příklad statistik o trhu práce. Statistický úřad sleduje na roční bázi počet nezaměstnaných a velikost dopělé populace pro obce, okresy a kraje. Pokud by ukládal data v tidy struktuře potom by: 1. Data byla skladována ve třech tabulkách -- v jedné tabulce by byly údaje pro kraje, v druhé pro okresy a ve třetí pro obce. 1. Struktura každé tabulky by byla následující: ``` ## # A tibble: 6 x 4 ## area year adult_population unemployment_rate ## ## 1 Kostelec 2001 301 9 ## 2 Kostelec 2002 305 7.3 ## 3 Kostelec 2003 295 8.2 ## 4 Valtrovice 2001 656 9.6 ## 5 Valtrovice 2002 650 7.6 ## 6 Valtrovice 2003 660 9.7 ``` Každé pozorování je identifikováno správní jednotkou (`area`) a rokem (`year`). Každá sledovaná proměnná je potom uložena ve vlastním sloupci. ## Transformace tabulek do tidy formátu Ne všechny dostupné datasety jsou organizované v tidy formátu. Součástí *tidyverse* je balíček *tidyr*, který obsahuje nástroje pro transformaci tabulek do tidy formátu. Základními funkcemi v balíku *tidyr*, které zvládnou většinu obvyklých problémů, jsou `pivot_wider()` a `pivot_longer()`. #### Poznámka 1 Funkce `pivot_wider()` a `pivot_longer()` přišly do *tidyr* od verze 1.0.0 (podzim 2019). Ve streších verzích balíku jejich funkci plnily funkce `gather()` a `spread()`, které byly vlastně speciálním případem obecnějších `pivot_`* funkcí. Funkce `gather()` a `spread()` byly v balíku podrženy pouze pro zachování zpětné kompatibility. #### Poznámka 2 Existují balíky, které mají podobné funkcionality jako *tidyr*. Zejména jde o *reshape* a *reshape2*. Oba balíky jsou v podstatě starými evolučními verzemi balíku *tidyr*. Zejména *reshape2* je stále v závislostech mnoha dalších balíků. *tidyr* je však obecně pokročilejší (co do rychlosti, elegance i rozsahu funkcí). ### Transformace mnoha sloupců do jednoho s funkcí `pivot_longer()` Mnoho datasetů obsahuje sloupce, jejichž jména nejsou samostatné proměnné, ale ve skutečnosti jde o hodnoty jedné proměnné. Jako příklad můžeme použít tabulku `table4a` z balíku *tidyr*, která zachycuje počet pozorovaných případů v několika letech a zemích: ```r print(table4a) ``` ``` ## # A tibble: 3 x 3 ## country `1999` `2000` ## * ## 1 Afghanistan 745 2666 ## 2 Brazil 37737 80488 ## 3 China 212258 213766 ``` V tomto formátu obsahuje jeden řádek hned dvě pozorování (dvě pozorování z jedné země) a dva sloupce obsahují stejnou proměnnou (počet případů). Pro transformaci takové tabulky do tidy formátu slouží funkce `pivot_longer()`. `pivot_longer()` skládá hodnoty z vybraných sloupců do nově vytvořeného sloupce. Jména vybraných sloupců vytvoří další dodatečný sloupec. `pivot_longer()` tak nahradí vybrané sloupce dvěma novými: ![Fungování `pivot_longer()` (RStudio, 2015)](figs/tidyr/gather-1.png){width=40%} Výsledná tabulka je proto "delší". Pro snadnější zapamatování se se proto funkce jmenuje `pivot_longer()`. Ukázkou praktické aplikace `pivot_longer()` může být transformace tabulky `table4a`: ```r table4a %>% pivot_longer(-country) ``` ``` ## # A tibble: 6 x 3 ## country name value ## ## 1 Afghanistan 1999 745 ## 2 Afghanistan 2000 2666 ## 3 Brazil 1999 37737 ## 4 Brazil 2000 80488 ## 5 China 1999 212258 ## 6 China 2000 213766 ``` Funkce `pivot_longer()` provedla transformaci ilustrovanou následujícím obrázkem: ![Fungování `gather()` (Wickham, 2016)](figs/tidyr/gather-2.png) Původní tabulka měla 3 řádky. Nyní jich má 6. Každý původní řádek se rozpadl na dva nové. Funkce `pivot_longer()` má následující syntax a parametry (více viz `?pivot_longer`): ```r pivot_longer(data, cols, names_to = "name", names_prefix = NULL, names_sep = NULL, names_pattern = NULL, names_ptypes = list(), names_repair = "check_unique", values_to = "value", values_drop_na = FALSE, values_ptypes = list() ) ``` Základní parametry jsou následující: - `data`...vstupní tabulka (data frame), která má projít transformací, - `cols`...identifikace sloupců, které mají být transformovány, - `names_to`...jméno sloupce, který ve výsledné tabulce bude obsahovat jména transformovaných sloupců, - `values_to`...jméno sloupce, který v transformované tabulce bude obsahovat hodnoty z původních sloupců. Nyní se vraťme k úvodnímu příkladu: ```r table4a %>% pivot_longer(-country) ``` Vstupem do funkce `pivot_longer()` byla tabulka `table4a`. Parametr `cols` byl s využitím pomocné funkce `-` nastaven na hodnotu `-country`. To znamená, že transformovány byly všechny sloupce až na `country`. Nově vytvořená tabulka má tři sloupce: netransformovaný sloupec `country` a nově vytvořené sloupce `name` a `value`. Jména těchto sloupců jsou dána defaultním nastavením funkce `pivot_longer()`. Nyní se podíváme na složitější případ. Pro ilustraci upravenou tabulku `table4a`, které přidáme sloupec obsahující ID: ``` ## # A tibble: 3 x 4 ## country `1999` `2000` id ## ## 1 Afghanistan 745 2666 1 ## 2 Brazil 37737 80488 2 ## 3 China 212258 213766 3 ``` Tabulku chceme transformovat tak, aby se sloupce s hodnotami (1999 a 2000) transformovaly do sloupců `year` a `value`. Je jasné, že chceme sáhnout po `pivot_longer()`: ```r table4a %>% # Tento řádek vytvoří nový sloupec s číslem řádku mutate(id = row_number()) %>% pivot_longer(-country, -id) ``` Toto nebude fungovat, protože parametr `cols` má jenom jednu pozici -- v jejím rámci musíme identifikovat všechny sloupce, které se mají transformovat. ```r # Použití negativní identifikace table4a %>% mutate(id = row_number()) %>% pivot_longer(-c(country,id)) ``` ``` ## # A tibble: 6 x 4 ## country id name value ## ## 1 Afghanistan 1 1999 745 ## 2 Afghanistan 1 2000 2666 ## 3 Brazil 2 1999 37737 ## 4 Brazil 2 2000 80488 ## 5 China 3 1999 212258 ## 6 China 3 2000 213766 ``` V tomto případě byl do jednomístného slotu vložen vektor vytvořený funkcí `c()`. Všiměte si, že i v něm jsou jména sloupců uvedena bez úvozovek. Hint: V reálném nasazení je vždy užitečné zvážit použití negtivní identifikace sloupců. Představte si například situaci, kdy Vašim zdrojeme je databáze, do které každý rok přibude další sloupec. Pozitivní identifikace sloupců by způsobila, že Vaše skripty by po prvním updatu přestaly správně fungovat. Negativní identifikace tímto problémem netrpí. Výše uvedená možnost není jediná možná. Následující příklady by vedly ke stejným výsledkům: ```r # Použití pozitivní identifikace table4a %>% mutate(id = row_number()) %>% pivot_longer(c(`1999`,`2000`)) # Použití pozitivní identifikace a speciální funkce `:` table4a %>% mutate(id = row_number()) %>% pivot_longer(`1999`:`2000`) # Použití select helpers table4a %>% mutate(id = row_number()) %>% pivot_longer(matches("\\d{4}")) ``` ### Transformace dvojice sloupců do mnoha sloupců s funkcí `pivot_wider()` Funkce `pivot_wider()` je inverzní k funkci `pivot_longer()`. Použijeme ji v případě, že sloupec ve skutečnosti neobsahuje hodnoty jedné proměnné, ale hodnoty mnoha proměnných. Funkce `pivot_wider()` transforumje dvojici sloupců do mnoha nových sloupců. Hodnoty prvního z původních sloupců obsahují určení proměnné a v druhém sloupci jsou uloženy jejich hodnoty. Příkladem takového datasetu může být tabulka `table2` z balíku *tidyr*: ``` ## # A tibble: 12 x 4 ## country year type count ## ## 1 Afghanistan 1999 cases 745 ## 2 Afghanistan 1999 population 19987071 ## 3 Afghanistan 2000 cases 2666 ## 4 Afghanistan 2000 population 20595360 ## 5 Brazil 1999 cases 37737 ## 6 Brazil 1999 population 172006362 ## 7 Brazil 2000 cases 80488 ## 8 Brazil 2000 population 174504898 ## 9 China 1999 cases 212258 ## 10 China 1999 population 1272915272 ## 11 China 2000 cases 213766 ## 12 China 2000 population 1280428583 ``` Pozorování je opět identifikováno hodnotami ve sloupcích `country` a `year`. Nicméně jedno pozorování je roztaženo do dvou řádků a hodnoty pro počet případů (`count`) a velikost populace (`population`) jsou obsaženy v jednom sloupci `count`. Pro převední takové tabulky do tidy fromátu je potřeba provést operaci popsanou následujícím schématem: ![Fungování `pivot_wider()` (RStudio, 2015)](figs/tidyr/spread-1.png) Funkce `pivot_wider()` použije hodnoty z prvního sloupce (`key`) jako jména nově vytvořených sloupců. Nově vytvořené buňky jsou potom vyplněny hodnotami z druhého sloupce (`value`) v původní tabulce: ```r table2 %>% pivot_wider(names_from = type, values_from = count) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 37737 172006362 ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` Funkce `pivot_wider()` provedla transformaci ilustrovanou následujícím obrázkem: ![Fungování `pivot_wider()` (Wickham, 2016)](figs/tidyr/spread-2.png) Funkce `pivot_wider()` má následující syntax a parametry (více viz `?pivot_wider`): ```r pivot_wider(data, id_cols = NULL, names_from = name, names_prefix = "", names_sep = "_", names_repair = "check_unique", values_from = value, values_fill = NULL, values_fn = NULL ) ``` Klíčové parametry jsou následující: - `data`...vstupní tabulka (data frame), která má projít transformací - `id_cols`...sloupce, které identifikují jedno pozorování. V defaultní nastevením (tedy `NULL`) se k tomuto účelu použijí všechny sloupce, které neprocházejí transformací. - `names_from`...sloupec (nebo sloupce), ze kterého se mají vytvořit jména nově vytvořených sloupců, - `values_from`...sloupec (nebo sloupce), ze kterých se mají vzít hodnoty pro naplnění nově vytvořených sloupců. Jak to funguje, pokud je parametr `names_from` delší než 1? Předpokládejme, že chceme vytvořit tabulku, ve které budou sloupce definovány kombinací roku a proměnné: ```r table2 %>% pivot_wider(names_from = c(type,year), values_from = count) ``` ``` ## # A tibble: 3 x 5 ## country cases_1999 population_1999 cases_2000 population_2000 ## ## 1 Afghanistan 745 19987071 2666 20595360 ## 2 Brazil 37737 172006362 80488 174504898 ## 3 China 212258 1272915272 213766 1280428583 ``` Jméno sloupců je teď vytvořené z kombinace `type` a `year`. Výslednou podobu jmen upravuje parametr `names_sep` z `pivot_wider()`. ### Praktické procvičení `pivot_longer()` a `pivot_wider()` I Uvažujme tabulku vytvořenou v předchozím případě. Jak z ní vytvoříme tidy dataset? Tabulka byla vytvořena s `pivot_wider()`. V prvním kroku tedy sáhneme tedy po inverzní funkci `pivot_longer()`. V tomto příkladě využijeme řadu zatím nediskutovaných parametrů `pivot_longer()`: ```r table2 %>% pivot_wider(names_from = c(type,year), values_from = count) %>% pivot_longer(-country, names_to = c("type","year"), names_sep = "_", names_transform = list(year = as.integer), names_ptypes = list(type = character()), values_to = "count" ) ``` ``` ## # A tibble: 12 x 4 ## country type year count ## ## 1 Afghanistan cases 1999 745 ## 2 Afghanistan population 1999 19987071 ## 3 Afghanistan cases 2000 2666 ## 4 Afghanistan population 2000 20595360 ## 5 Brazil cases 1999 37737 ## 6 Brazil population 1999 172006362 ## 7 Brazil cases 2000 80488 ## 8 Brazil population 2000 174504898 ## 9 China cases 1999 212258 ## 10 China population 1999 1272915272 ## 11 China cases 2000 213766 ## 12 China population 2000 1280428583 ``` Co se v nově použitých parametrech stalo? Parametr `names_to` je nyní délky 2. To znamená, že jména transformovaných sloupců se rozpadnou do dvou sloupců se zadanými jmény. Jak se má tento rozpad provést určuje parametr `names_sep` (u složitějších případů `names_pattern`). V současném nastavení říká, že znaky před `_` mají být přeneseny do sloupce `type` a znaky za `_` do sloupce `year`. Bylo by také vhodné, aby hodnoty ve sloupci `type` byly character a ve sloupci `year` integer. Tato konverze se nastavuje parametrem `names_ptypes`. Ten obsahuje pojmenovaný list. Jména odpovídají jménům nově vytvořených sloupců ke ketrým je přiřazen prázdný vektor požadovaného datového typu. Tato transformace zvrátila účinky `pivot_wider()`. Nicméně data stále nejsou tidy. Potřebujeme mít dva nové sloupce `cases` a `population` s hodnotami ze sloupce `count`. A job for `pivot_wider()`: ```r table2 %>% pivot_wider(names_from = c(type,year), values_from = count) %>% pivot_longer(-country, names_to = c("type","year"), names_sep = "_", names_transform = list(year = as.integer), names_ptypes = list(type = character()), values_to = "count" ) %>% pivot_wider( id_cols = c(country,year), # V tomto případě ekvivalenttní k NULL names_from = type, values_from = count ) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 37737 172006362 ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` ...and here we go. Výsledek odpovídá formátu tidy data. ## Další funkce z *tidyr* Kromě funkcí `pivot_*()`, které jsou bezesporu nejvíce používané při čistění a transformaci dat, obsahuje *tidyr* řadu dalších funkcí, které pomáhají s: 1. Odstraněním méně obvyklých případů při transformaci tabulek do tidy fromátu. 1. Nakládáním s chybějícími hodnotami. 1. Konstrukcí vlastních tabulek. ### Různé typy pozorování v jedná tabulce: `nest()` a `unnest()` Definice tidy formátu vyžaduje, aby byl každý typ pozorování uchován v oddělené tabulce. ``` ## `summarise()` ungrouping output (override with `.groups` argument) ``` Tabulka `population_world` obsahuje data, která toto kritérium nesplňují. Obsahuje pozorování jak za jednotlivá pozorování, tak jejich agregované hodnoty: ```r print(population_world) ``` ``` ## # A tibble: 9 x 5 ## country observation year Female Male ## ## 1 Iceland unit 2005 148. 149. ## 2 Iceland unit 2010 158. 160. ## 3 Iceland unit 2015 164. 165. ## 4 Malta unit 2005 201. 196. ## 5 Malta unit 2010 207. 205. ## 6 Malta unit 2015 210. 208. ## 7 World aggregate 2005 348. 346. ## 8 World aggregate 2010 365. 365. ## 9 World aggregate 2015 375. 374. ``` Pomocí funkce `nest()` je možné vytvořit datovou strukturu, která tento problém vyřeší. `nest()` vytvoří "tabulku tabulek". Můžeme ji použít pro vytvoření tabulky, která bude obsahovat jednotlivé tabulky v tidy formátu: ```r population_world_nested <- population_world %>% nest(data = -observation) print(population_world_nested) ``` ``` ## # A tibble: 2 x 2 ## observation data ## ## 1 unit ## 2 aggregate ``` Tabulky v tidy formátu jsou obsaženy v nově vytvořeném sloupci `data`: ```r print(population_world_nested$data) ``` ``` ## [[1]] ## # A tibble: 6 x 4 ## country year Female Male ## ## 1 Iceland 2005 148. 149. ## 2 Iceland 2010 158. 160. ## 3 Iceland 2015 164. 165. ## 4 Malta 2005 201. 196. ## 5 Malta 2010 207. 205. ## 6 Malta 2015 210. 208. ## ## [[2]] ## # A tibble: 3 x 4 ## country year Female Male ## ## 1 World 2005 348. 346. ## 2 World 2010 365. 365. ## 3 World 2015 375. 374. ``` Fungování `nest()` ilustruje následující diagram: ![Fungování `nest()`](figs/tidyr/nest-1.png) Hlavním praktickým využitím `nest()` je vytvoření datové struktury, která může sloužit pro následnou datovou analýzu s pomocí nástrojů, které nejsou plně kompatibilní s logikou *tidyverse*. Zejména u vysoce specializivaných aplikací je takových funkcí překvapivě mnoho. Na některé případy narazíme zejména na konci kurzu. Syntaxe funkce `nest()` je velmi jednoduchá (viz `?nest`): ```r nest(data, ...) ``` - `data`...vstupní tabulka (data frame) - `...`...identifikace sloupců, které mají být součástí nově vytvořených (pod)tabulek. Podobně jako v případě `pivot_longer()` lze využít více způsobů, jak sloupce specifikovat: select helpers, atp. Základním způsobem identifikace sloupců je podle jejich jmen: ``` ## # A tibble: 3 x 3 ## country observation data ## ## 1 Iceland unit ## 2 Malta unit ## 3 World aggregate ``` Jméno vektoru `data` se použije jako název nově vytvořeného sloupce. Pokud vektor nijak nepojmenujete, vrátí Vám `nest()` varování a nový sloupec pojmenuje právě `data`. Na příkladech výše bylo ukázán příklad výběru sloupců s pomocí speciální funkce `-`. Funkční by měly být všechny způsoby identifikace podle *tidyselect*. Datovou strukturu vytvořenou funkcí `nest()` lze transformovat do původního stavu pomocí funkce `unnest()`: ```r population_world_nested %>% unnest(data) ``` ``` ## # A tibble: 9 x 5 ## observation country year Female Male ## ## 1 unit Iceland 2005 148. 149. ## 2 unit Iceland 2010 158. 160. ## 3 unit Iceland 2015 164. 165. ## 4 unit Malta 2005 201. 196. ## 5 unit Malta 2010 207. 205. ## 6 unit Malta 2015 210. 208. ## 7 aggregate World 2005 348. 346. ## 8 aggregate World 2010 365. 365. ## 9 aggregate World 2015 375. 374. ``` Syntaxe funkce `unnest()` je následující: ```r unnest(data, cols, ..., keep_empty = FALSE, ptype = NULL, names_sep = NULL, names_repair = "check_unique" ) ``` Základní parametry jsou: - `data`...je vstupní tabulka, - `cols`...je parametr vymezující sloupce, které se mají transformovat (obsahujících tabulky, které se mají "rozbalit"). Funkce `nest()` a `unnest()` se od *tidyr* 1.0.0 významně změnily. Navíc k nim přibyly bratříčci `chop()` a `unchop()`. Ty se od `nest()`/`unnest()` liší v tom, že nevytvářejí nový sloupec tabulek, ale ponechávají původní sloupce, jen transformují jejich obsah na vektor: ``` ## # A tibble: 3 x 5 ## country observation year Female Male ## > > > ## 1 Iceland unit [3] [3] [3] ## 2 Malta unit [3] [3] [3] ## 3 World aggregate [3] [3] [3] ``` Volba mezi `nest()`/`chop()` závisí čistě na potřebách následné analýzy. ### Více hodnot v jedné buňce Některé tabulky obsahují v jedné buňce hodnoty více proměnných. Jako příklad může sloužit tabulka `tidyr::table3`: ```r print(table3) ``` ``` ## # A tibble: 6 x 3 ## country year rate ## * ## 1 Afghanistan 1999 745/19987071 ## 2 Afghanistan 2000 2666/20595360 ## 3 Brazil 1999 37737/172006362 ## 4 Brazil 2000 80488/174504898 ## 5 China 1999 212258/1272915272 ## 6 China 2000 213766/1280428583 ``` Ve sloupci `rate` je obsažen podíl počtu případů (cases) na celkové populaci (population). Proměnná `rate` je navíc nutně uložena jako text (`character`). S takovou proměnnou nelze rozumně pracovat. *tidyr* obsahuje nástroje, pomocí kterých je možné taková data převést do tidy formátu, který vyžaduje, aby obsahem jedné buňky byla vždy hodnota právě jedné proměnné. #### Rozdělení jednoho sloupce do mnoha se `separate()` Základní funkcí je `separate()`, která umožňuje jeden sloupec rozdělit do mnoha nových sloupců. V případě tabulky `table3` například rozdělit sloupec `rate` na nové sloupce `cases` (číslo před "/") a `population` (číslo za "/"): ```r table3 %>% separate(rate, c("cases","population"), sep="/") ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 37737 172006362 ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` `separate()` provádí operaci ilustrovanou následujícím digramem: ![Fungování `separate()` (Wickham, 2016)](figs/tidyr/separate-1.png) Funkce `separate()` má následující syntaxi a parametry (viz `?separate`): ```r separate(data, col, into, sep = "[^[:alnum:]]+", remove = TRUE, convert = FALSE, extra = "warn", fill = "warn", ...) ``` - `data`...vstupní tabulka (data frame) - `col`...specifikace sloupce, který se má rozdělit. Sloupec je specifikován jako jméno bez úvozovek. - `into`...jména nově vytvářených sloupců specifikovaná jako vektor (character vector) - `sep`...udává rozdělení vstupního sloupce na výstupní sloupce. Může být specifikován jako číslo (pozice, na které se hodnoty v buňce rozdělí) a zejména jako regulární výraz. - `remove`...Má být vstupní sloupec zachován ve výstupní tabulce? - `convert`...pokud je nastaveno na `TRUE`, potom se funkce pokusí o automatickou konverzi výstupních sloupců. Pokud by například byla tato možnost použita v případě `table3`, potom by výstupní sloupce byly konvertovány do celých čísel (integer). - `extra`...udává, co se má stát, pokud vstupní řetezec obsahuje *více* hodnot, než je specifikováno výstupních sloupců. - `fill`...udává, co se má stát, pokud vstupní řetězec obsahuje *méně* hodnot, než je specifikováno výstupních sloupců. Při výchozím nastavení je parametr `extra` nastaven na hodnotu `warn`. To znamená, že v přítomnosti většího počtu hodnot než je specifikováno nově vytvářených sloupců vrátí `seprate()` varování a zahodí přebytečné hodnoty. ```r table3 %>% separate(rate, c("cases"), sep="/", remove=FALSE) ``` ``` ## Warning: Expected 1 pieces. Additional pieces discarded in 6 rows [1, 2, 3, 4, ## 5, 6]. ``` ``` ## # A tibble: 6 x 4 ## country year rate cases ## ## 1 Afghanistan 1999 745/19987071 745 ## 2 Afghanistan 2000 2666/20595360 2666 ## 3 Brazil 1999 37737/172006362 37737 ## 4 Brazil 2000 80488/174504898 80488 ## 5 China 1999 212258/1272915272 212258 ## 6 China 2000 213766/1280428583 213766 ``` Toto chování lze změnit. V případě nastavení `extra` na `drop` provede ve výsledku stejnou opraci, ale nevypíše varování. V případě nastavení parametru na `merge` rozdělí vstupní hodnotu pouze na stejný počet skupin, jako je zadáno výstupních sloupců. V následujícím případě bude tedy výstup (ve sloupci `cases`) stejný jako vstup (ve sloupci `rate`): ```r table3 %>% separate(rate, c("cases"), sep="/", extra="merge", remove=FALSE) ``` ``` ## # A tibble: 6 x 4 ## country year rate cases ## ## 1 Afghanistan 1999 745/19987071 745/19987071 ## 2 Afghanistan 2000 2666/20595360 2666/20595360 ## 3 Brazil 1999 37737/172006362 37737/172006362 ## 4 Brazil 2000 80488/174504898 80488/174504898 ## 5 China 1999 212258/1272915272 212258/1272915272 ## 6 China 2000 213766/1280428583 213766/1280428583 ``` Může se také stát, že vstupní hondota obsahuje méně skupin, než je specifikováno výstupních sloupců. V následujícím příkladě se snaží `separate()` rozdělit údaje ze sloupce `rate` do tří nových sloupců: ```r table3 %>% separate(rate, c("cases","population","witches"), sep="/") ``` ``` ## Warning: Expected 3 pieces. Missing pieces filled with `NA` in 6 rows [1, 2, 3, ## 4, 5, 6]. ``` ``` ## # A tibble: 6 x 5 ## country year cases population witches ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 37737 172006362 ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` Vstupní data však obsahují pouze dva bloky. Při výchozím nastavení parametru `fill` (`warn`) vrátí `separate()` varování a vyplní sloupce zprava. Alternativní nastavení `right` a `left` nevrací varování, a vyplňují sloupce zprava respektive zleva: ```r table3 %>% separate(rate, c("cases","population","witches"), sep="/", fill="left") ``` ``` ## # A tibble: 6 x 5 ## country year cases population witches ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 37737 172006362 ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` Funkce `separate()` má blízké příbuzné v podobě funkcí `extract()` (pozor na maskování `extract` balíkem `magrittr`) a `separate_rows()`. `extract()` umožňuje specifikovat jednotlivé skupiny ve vstupním sloupci pomocí regulárních výrazů. Pokud některá skupina ve vstupním výrazu chybí, potom je ve výstupním sloupci kódována jako `NA`. `separate_rows()` nerozkládá vstupní řetězec do sloupců, ale do řádků: ```r table3 %>% separate_rows(rate, sep="/") ``` ``` ## # A tibble: 12 x 3 ## country year rate ## ## 1 Afghanistan 1999 745 ## 2 Afghanistan 1999 19987071 ## 3 Afghanistan 2000 2666 ## 4 Afghanistan 2000 20595360 ## 5 Brazil 1999 37737 ## 6 Brazil 1999 172006362 ## 7 Brazil 2000 80488 ## 8 Brazil 2000 174504898 ## 9 China 1999 212258 ## 10 China 1999 1272915272 ## 11 China 2000 213766 ## 12 China 2000 1280428583 ``` Použití `separate_rows()` na `table3` nemá smysl. Hodí se například v situaci, kdy jsou v buňce obsaženy identifikátory více různých stavů. Praktickým příkladem může být údaj o zatržení různých checkboxů ve formuláři -- takto je obsahují např. CSV exportované z Google Forms. #### Sloučení mnoha sloupců do jednoho s `unite()` *tidyr* obsahuje funkci, které umožňuje provádět inverzní operaci -- tedy slučovat více sloupců do jednoho. Tabulka `tidyr::table5` obsahuje rok pozorování rozložený na století a rok: ```r print(table5) ``` ``` ## # A tibble: 6 x 4 ## country century year rate ## * ## 1 Afghanistan 19 99 745/19987071 ## 2 Afghanistan 20 00 2666/20595360 ## 3 Brazil 19 99 37737/172006362 ## 4 Brazil 20 00 80488/174504898 ## 5 China 19 99 212258/1272915272 ## 6 China 20 00 213766/1280428583 ``` Kompletní letopočet můžeme složit pomocí funkce `unite()`: ```r table5 %>% unite(year,century,year, sep="") ``` ``` ## # A tibble: 6 x 3 ## country year rate ## ## 1 Afghanistan 1999 745/19987071 ## 2 Afghanistan 2000 2666/20595360 ## 3 Brazil 1999 37737/172006362 ## 4 Brazil 2000 80488/174504898 ## 5 China 1999 212258/1272915272 ## 6 China 2000 213766/1280428583 ``` `unite()` má obdobné rozhraní a parametry jako funkce určené k rozdělování hodnot (viz `?unite`): ```r unite(data, col, ..., sep = "_", remove = TRUE) ``` - `data`...vstupní tabulka (data frame) - `col`...jméno nově vytvořeného sloupce (prosté jméno bez úvozovek) - `...`...sloupce, ze kterých má být nově vytvořený sloupec vytvořen (viz `dplyr::select`) - `sep`...znak oddělující hodnoty z jednotlivých sloupců - `remove`...mají být původní sloupce odstraněny? ## Implicitní a explicitní chybějící hodnoty Tabulky často nejsou úplné -- některá pozorování chybějí. Chybějící pozorování je účelné rozdělit na *implicitní* a *explicitní*. Rozdíl mezi nimi je demonstrován na následujících tabulkách vytvořených z `table1`. První tabulka `table1_expl` obsahuje explicitní chybějící hodnoty. Pozorování (Brazílie v roce 1999) je v tabulce přítomno, ale místo naměřených hodnot vidíme `NA`: ```r table1_expl <- table1 table1_expl[table1_expl$country == "Brazil" & table1_expl$year == 1999, c("cases","population")] <- NA table1_expl[table1_expl$country == "Afghanistan" & table1_expl$year == 1999, "cases"] <- NA print(table1_expl) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 NA 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 NA NA ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` Tabulka `table1_impl` obsahuje implicitní chybějící hodnoty. Pozorování s nenaměřenými chybami v tabulce vůbec není přítomno: ```r table1_impl <- table1 table1_impl <- table1_impl[!(table1_impl$country == "Brazil" & table1_impl$year == 1999),] print(table1_impl) ``` ``` ## # A tibble: 5 x 4 ## country year cases population ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 2000 80488 174504898 ## 4 China 1999 212258 1272915272 ## 5 China 2000 213766 1280428583 ``` Implicitní chybějící hodnoty jsou při analýze dat velmi zákeřné -- nejsou viditelné "pouhým okem" a ani testem na přítomnost `NA`: ```r table1_impl[!complete.cases(table1_impl),] ``` ``` ## # A tibble: 0 x 4 ## # … with 4 variables: country , year , cases , population ``` #### Odstranění implicitních chybějících hodnot s `complete()` Při analýze dat je proto vhodné konvertovat implicitní chybějící hodnoty na explicitní. Pro tento účel je možné použít funkci `complete()`: ```r complete(table1_impl, country, year) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 NA NA ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` Syntaxe funkce `complete()` je velmi přímočará: ```r complete(data, ..., fill = list()) ``` - `data`...vstupní tabulka (data frame) - `...`...sloupce, ze které definují (jednoznačně identifikují) pozorování (v příkladu výše `country` a `year`) Ve výchozím nastavení jsou implicitní chybějící hodnoty nahrazeny `NA`. Toto chování lze změnit parametrem `fill`. Můžeme například vědět, že pokud není žádný případ zaznamenán, tak statistický úřad pozorování nezapisuje -- i když by měl správně zapsat hodnotu 0. (Takto skutečně v některých případech postupuje ČSÚ.) Znalost dat nás tedy vede k tomu, že chybějící pozorování ve sloupci `cases` jsou ve skutečnosti nulová pozorování. Správně doplněné chybějící hodnoty je tedy možné získat nastavením parametru `fill`: ```r complete(table1_impl, country, year, fill = list(cases = 0)) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 745 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 0 NA ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` Do parametru `fill` se vkládá `list` s pojmenovanými položkami. Jména položek musí odpovídat jménům sloupců v tabulce a musí obsahovat právě jednu hodnotu. Ta je použita pro nahrazení chybějících hodnot. V příkladu výše zůstalo chybějící pozorování v `population` nahrazeno `NA`. Pokud není pravidlo pro náhradu explicitně stanoveno ve `fill`, zůstává v platnosti výchozí nastavení. #### Odstranění explicitních chybějících hodnot s `drop_na()` V některých případech je naopak vhodné odstranit explicitní chybějící hodnoty a pracovat s tabulkou, ve které jsou implicitní chybějící hodnoty. Pro to je možné využít funkci `drop_na()`: ```r drop_na(table1_expl) ``` ``` ## # A tibble: 4 x 4 ## country year cases population ## ## 1 Afghanistan 2000 2666 20595360 ## 2 Brazil 2000 80488 174504898 ## 3 China 1999 212258 1272915272 ## 4 China 2000 213766 1280428583 ``` Ve výchozím nastavení `drop_na()` zahazuje všechny řádky, na nichž se vyskytla chybějící hodnota -- a to v libovolném sloupci. Toto chování lze změnit pomocí jediného dodatečného parametru funkce `...`, který umožňuje specifikovat, které sloupce mají být brány v potaz. Sloupce mohou být identifikovány všemi způsoby srozumitelnými pro `dplyr::select()`. V následujícím příkladě je vypuštěn pouze řádek, ve kterém je chybějící hodnota ve sloupci `population`: ```r drop_na(table1_expl, population) ``` ``` ## # A tibble: 5 x 4 ## country year cases population ## ## 1 Afghanistan 1999 NA 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 2000 80488 174504898 ## 4 China 1999 212258 1272915272 ## 5 China 2000 213766 1280428583 ``` #### Nahrazení explicitních chybějících hodnot s `fill()`, `replace_na()` První funkcí pro nahrazování explicitních chybějících pozorování je `replace_na()`. Její syntaxe a fungování je analogické k parametru `fill` funkce `complete()`. (`complete()` je nakonec pouze wrapper okolo `replace_na()` a několika dalších funkcí.) Následující použití `replace_na()` nahradí chybějící pozorování ve sloupci `cases` nulami a v `population` nekonečnem (`Inf`): ```r replace_na(table1_expl, replace = list(cases = 0, population = Inf)) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 0 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 0 Inf ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` `replace_na()` je užitečná ve velmi omezeném množství případů (viz `complete()`). Častěji je pravděpoodbně v praxi využívána funkce `fill()`. `fill()` nahrazuje chybějící hodnotu hodnotou z předcházejícího (výchozí možnost) nebo následujícího řádku. Pozor, `fill()` pracuje pouze tehdy, pokud jsou chybějící hodnoty explicitní! Funkci `fill()` je nutné v parametru `...` specifikovat sloupce, u kterých se má nahrazení chybějících hodnot provést. (`fill()` opět rozumí všem možnostem dostupným v `dplyr::select()`.) Následující ukázka demonstruje úskalí používání funkce `fill()`: ```r fill(table1_expl, cases) ``` ``` ## # A tibble: 6 x 4 ## country year cases population ## ## 1 Afghanistan 1999 NA 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 2666 NA ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` 1. Chybějící hodnota v prvním řádku nebyla nahrazena -- neexistuje totiž žádný předcházející řádek. 1. Údaj pro Brazilii byl nahrazen údajem pro Afganistán. První problém samozřejmě nemá řešení. Výzkumník může zvážit nahrazení hodnotou z následujícího řádku (pomocí parametru `.direction = "up"`). Pro druhý problém je řešení následující: 1. Rozdělit tabulku na mnoho dílčích tabulek podél proměnné `country`. 1. Provést nahrazení v každé z nich. 1. Tabulky složit zpátky. Takový úkol je jistě proveditelný, ale velmi složitý. Naštěstí právě takovou funkcionalitu poskytuje `group_by()` z balíku `dplyr`. `group_by()` umožňuje každou definovanou skupinu zpracovat odděleně: ``` ## # A tibble: 6 x 4 ## # Groups: country [3] ## country year cases population ## ## 1 Afghanistan 1999 NA 19987071 ## 2 Afghanistan 2000 2666 20595360 ## 3 Brazil 1999 NA NA ## 4 Brazil 2000 80488 174504898 ## 5 China 1999 212258 1272915272 ## 6 China 2000 213766 1280428583 ``` V tomto případě je výsledek v pořádku -- Brazílie "nedědí" hodnoty Afganistánu. ## Konstrukce vlastních tabulek s `crossing()` V některých případech je užitečné vytvořit si vlastní tabulku. Typickým příkladem může být vytvoření "kostry" tabulky, která bude obsahovat všechny možné varinty (identifikátory) pozorování, které se ve výsledné tabulce mohou vyskytnout. Například můžeme chtít vytvořit panelová data pro země V4 a pro roky 2000--2001. Tento úkol je možné efektivně vyřešit pomocí `crossing()`: ``` ## # A tibble: 8 x 2 ## country year ## ## 1 Czech Republic 2000 ## 2 Czech Republic 2001 ## 3 Hungary 2000 ## 4 Hungary 2001 ## 5 Poland 2000 ## 6 Poland 2001 ## 7 Slovakia 2000 ## 8 Slovakia 2001 ```