15.4 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:

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 × 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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:

table1_impl <- table1
table1_impl <- table1_impl[!(table1_impl$country == "Brazil" & table1_impl$year == 1999),]
    
print(table1_impl)
## # A tibble: 5 × 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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:

table1_impl[!complete.cases(table1_impl),]
## # A tibble: 0 × 4
## # … with 4 variables: country <chr>, year <int>, cases <int>, population <int>

15.4.0.1 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():

complete(table1_impl, country, year)
## # A tibble: 6 × 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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á:

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:

complete(table1_impl, country, year, fill = list(cases = 0))
## # A tibble: 6 × 4
##   country      year  cases population
##   <chr>       <int>  <dbl>      <int>
## 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í.

15.4.0.2 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():

drop_na(table1_expl)
## # A tibble: 4 × 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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:

drop_na(table1_expl, population)
## # A tibble: 5 × 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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

15.4.0.3 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):

replace_na(table1_expl, replace = list(cases = 0, population = Inf))
## # A tibble: 6 × 4
##   country      year  cases population
##   <chr>       <int>  <dbl>      <dbl>
## 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():

fill(table1_expl, cases)
## # A tibble: 6 × 4
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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.
  2. Ú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.
  2. Provést nahrazení v každé z nich.
  3. 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 × 4
## # Groups:   country [3]
##   country      year  cases population
##   <chr>       <int>  <int>      <int>
## 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.