Nevyplněné a speciální hodnoty a co dělat, když jsou ve faktorech

Je to velmi široké téma a my se naučíme jenom to, jak tyto hodnoty detekovat a nahradit je jinými, nebo eliminovat datové elementy, kde se vyskytují. Speciálních hodnot je několik druhů podle toho, jak vznikly.

NA - “Not Available”

Excel: “#N/A”, “”

Inf - “Infinite value”

 + možná odlehlá hodnota?
 + nedělím někde nulou?

NaN - “Not a Number”

  • možná špatně definovaná proměnná?

Detekce nevyplněných hodnot (NA)

tabulka <- data.frame(pocet_deti = c(3, NA, NA, NA), rok_narozeni = c(1940, 2015, 2001, 2003), dosazene_vzdelani = c("VŠ", NA, "ZŠ", NA)) 

Testovací funkce is.na() vrátí data.frame o stejných rozměrech s hodnotami TRUE nebo FALSE v každé buňce.

is.na(tabulka)
##      pocet_deti rok_narozeni dosazene_vzdelani
## [1,]      FALSE        FALSE             FALSE
## [2,]       TRUE        FALSE              TRUE
## [3,]       TRUE        FALSE             FALSE
## [4,]       TRUE        FALSE              TRUE

Když tuto funkci zkombinujeme s funkcí any(), dostaneme okamžitou odpověď na otázku, zda se v datech vyskytují nějaké hodnoty NA. To se hodí například do podmínek.

any(is.na(tabulka))
## [1] TRUE

Kolik jich je?

sum(is.na(tabulka))
## [1] 5

Už taky víme, jak si udělat rychlý přehled “pro lidské oko” pomocí summary().

summary(tabulka)
##    pocet_deti  rok_narozeni  dosazene_vzdelani
##  Min.   :3    Min.   :1940   VŠ  :1           
##  1st Qu.:3    1st Qu.:1986   ZŠ  :1           
##  Median :3    Median :2002   NA's:2           
##  Mean   :3    Mean   :1990                    
##  3rd Qu.:3    3rd Qu.:2006                    
##  Max.   :3    Max.   :2015                    
##  NA's   :3

Pokud jde o tabulky, víme, že pozorování bývají v řádcích a proměnné ve sloupcích. Statistiky jednotlivých proměnných se počítají z jednotlivých řádků. Pokud budeme provádět nějakou analýzu, která nesnese hodnotu NA v proměnné, budeme muset odstranit všechny řádky, v kterých některá proměnná nabývá hodnoty NA. Jak je snadno detekujeme? Pomocí funkce complete.cases(). Ta vydá TRUE nebo FALSE pro každý řádek tabulky, jestli je “kompletní”, tj. _bez hodnoty NA .

Podobně můžeme použít funkci table() na každý sloupec:

table(tabulka$pocet_deti)
## 
## 3 
## 1
table(tabulka$rok_narozeni)
## 
## 1940 2001 2003 2015 
##    1    1    1    1
table(tabulka$dosazene_vzdelani, useNA = "ifany")
## 
##   VŠ   ZŠ <NA> 
##    1    1    2
complete.cases(tabulka)
## [1]  TRUE FALSE FALSE FALSE

Jediným kompletním případem byl ten první, protože ostatní měli NA ve vzdělání nebo/a počtu dětí. Tato funkce nepodává informaci o tom, v kterém sloupci to NA je.

Mimochodem, porovnávací a třídící funkce nepovažují dvě NA za shodné hodnoty! S NA prostě nefunguje nic rozumného!

Eliminace nevyplněných hodnot NA

Odstranění řádků je snadné pomocí subsetu s funkcí complete.cases() jako logickým testem. Jde to oběma způsoby - přes hranatou závorku i přes funkci subset(), kam se ani nemusí psát == TRUE.

tabulka[complete.cases(tabulka),]
##   pocet_deti rok_narozeni dosazene_vzdelani
## 1          3         1940                VŠ
subset(tabulka, complete.cases(tabulka))
##   pocet_deti rok_narozeni dosazene_vzdelani
## 1          3         1940                VŠ

Ještě na to taky existuje speciální funkce na.omit()

na.omit(tabulka)
##   pocet_deti rok_narozeni dosazene_vzdelani
## 1          3         1940                VŠ

Doplnění NA na místa prázdných hodnot

Odbočka - využijeme toho, že potřebujeme tabulku, která má místo hodnot NA něco jiného a vyrobíme si takovou z naší původní tabulky, aniž bychom její sloupce konvertovali na znakové vektory (protože teď jsou to faktory, samozřejmě).

Editování faktorů je dobré proto, že by při konverzi ze znakového vektoru mohlo dojít ke zmatku, zda se hodnota NA načte správně, nebo jako řetězec "NA", což by data znehodnotilo.

Připravíme si tabulku pojmenovanou tabulka2, která bude mít ve sloupci vzdělání místo NA slovo “žádné”. Je to taky příležitost k nahlédnutí do editace faktorů (skoro se to nedá a nikdo to nedělá, když nemusí!!!)

tabulka2 <- tabulka
tabulka2$dosazene_vzdelani <- factor(tabulka2$dosazene_vzdelani, levels = c(levels(tabulka2$dosazene_vzdelani), "")) 
str(tabulka2)
## 'data.frame':    4 obs. of  3 variables:
##  $ pocet_deti       : num  3 NA NA NA
##  $ rok_narozeni     : num  1940 2015 2001 2003
##  $ dosazene_vzdelani: Factor w/ 3 levels "VŠ","ZŠ","": 1 NA 2 NA

Na faktorech je zrádné i to, že s názvy úrovní se nedá manipulovat mimo parametr levels ve funkci factor(). Sice existuje funkce levels(), ale ta je obecnější a u faktorů nedělá, co bychom mysleli. Zatímco u pojmenování sloupců je snad úplně jedno, jestli je pojmenujete už při vytvoření data.framu parametrem col.names, nebo dodatečně funkcí colnames(), u faktoru to jedno není. Tak proto jsme zopakovali funkci factor na něčem, co už faktor bylo – jen abychom tomu změnili počet a názvy parametru levels!

tabulka2$dosazene_vzdelani[which(is.na(tabulka2$dosazene_vzdelani))] <- ""

Nutné dodržet:

+ přidat novou úroveň do parametru ```levels``` ve funkci ```factor```
+ pak v samotném faktoru vybrané elementy nahradit tou slovní hodnotou, *ne její numerickou reprezentací*. To v našem příkladu znamená, že do něčeho, co vypadá jako vektor samých čísel, opravdu přidáte prázdný řetězec ```""```, jakkoli divně to vypadá!

Naše tabulka teď vypadá takhle a je plná faktorů.

tabulka2
##   pocet_deti rok_narozeni dosazene_vzdelani
## 1          3         1940                VŠ
## 2         NA         2015                  
## 3         NA         2001                ZŠ
## 4         NA         2003
str(tabulka2)
## 'data.frame':    4 obs. of  3 variables:
##  $ pocet_deti       : num  3 NA NA NA
##  $ rok_narozeni     : num  1940 2015 2001 2003
##  $ dosazene_vzdelani: Factor w/ 3 levels "VŠ","ZŠ","": 1 3 2 3

A teď to doplnění NA na místa, kde je prázdný řetězec

Na doplnění hodnot NA místo prázdného řetězce nebo jiného zástupce hodnot NA, s kterým by si R nevědělo rady vlastně potřebujeme pouze vyhodit název té úrovně ze seznamu úrovní. V našem sloupečku (a možná obecně ve faktorech) se hodnota "" uvádí na posledním, třetím, místě. Připomeňme si, že se hodnoty defaultně řadí abecedně.

levels(tabulka2$dosazene_vzdelani)
## [1] "VŠ" "ZŠ" ""

Nám tedy stačí, když tento řetězec z levels(tabulka2$dosazene_vzdelani) odebereme. Pozor, opět se to musí udělat pomocí parametru funkce factor(), protože R nesnese, že se objekty na levé a pravé straně liší délkou. Vypadla by tato hláška:

  > levels(tabulka2$dosazene_vzdelani) <- levels(tabulka2$dosazene_vzdelani)[-3]
  Error in `levels<-.factor`(`*tmp*`, value = c("VŠ", "ZŠ")) : 
  number of levels differs

Takže použijeme celou funkci factor(). Raději si na tuhle operaci založíme další tabulku, tentokrát s číslem 3.

tabulka3 <- tabulka2
tabulka3$dosazene_vzdelani <- factor(tabulka3$dosazene_vzdelani, levels = levels(tabulka3$dosazene_vzdelani)[-3])
tabulka3
##   pocet_deti rok_narozeni dosazene_vzdelani
## 1          3         1940                VŠ
## 2         NA         2015              <NA>
## 3         NA         2001                ZŠ
## 4         NA         2003              <NA>

I když se ve faktorovém sloupci hodnoty NA vytisknou ve špičatých závorkách, nic to neznamená. Struktura je správná - v hodnotách sloupce dosazene_vzdelani figurují hodnoty NA, zatímco v seznamu úrovní už není prázdný řetězec. R už tedy bude moci standardně detekovat a zpracovávat chybějící hodnoty.

str(tabulka3$dosazene_vzdelani)
##  Factor w/ 2 levels "VŠ","ZŠ": 1 NA 2 NA
is.na(tabulka3$dosazene_vzdelani)
## [1] FALSE  TRUE FALSE  TRUE

Jen tak na okraj, funkce factor() má parametr exclude, který je defaultně nastaven na NA. Tím jsou nevyplněné hodnoty vyloučeny ze seznamu úrovní. Když se ale parametr nastaví na NULL, tak se vypne a nevyplněné hodnoty se stanou součástí seznamu úrovní a v interní reprezentaci budou nevyplněné hodnoty reprezentovány vlastní číslicí:

tabulka4 <- tabulka3
tabulka4$dosazene_vzdelani <- factor(tabulka4$dosazene_vzdelani, exclude = NULL)
str(tabulka4$dosazene_vzdelani)
##  Factor w/ 3 levels "VŠ","ZŠ",NA: 1 3 2 3

Tím se ale Rku řekne, že je nemá detekovat jako NA, což je docela zrada, protože v tom seznamu nejsou v uvozovkách a člověk by myslel, že jsou to prostě pořád poctivé NA!

is.na(tabulka4$dosazene_vzdelani)
## [1] FALSE FALSE FALSE FALSE

Faktory jsou prostě potvory. To, že se špatně editují, je prý nápověda uživatelům, že se editovat nemají, a je to také ochrana před náhodnou typografickou chybou zanesenou do dat během statistické analýzy. Počítá se s tím, že v této fázi práce už se vložená data jenom čtou, ale nic se do nich nezapisuje.