6.1 Faktory
Faktory slouží k uchovávání kategoriálních proměnných. Kategoriální proměnné jsou proměnné, kterou mohou nabývat jen určitých předem stanovených úrovní. Tyto úrovně mohou být buď uspořádané (pak se jedná o ordinální proměnné), nebo neuspořádané. Příkladem ordinální kategoriální proměnné je kvalita služeb zjišťovaná v dotazníku. Ta může nabývat např. hodnot “velmi špatná,” “špatná,” “průměrná,” “dobrá” a “výborná.” Jiné úrovně nejsou (v rámci kódování dotazníku) možné. Přitom platí, že hodnoty jsou uspořádané od nejhorší po nejlepší, takže vždy můžeme dvě úrovně porovnat a říci, která je lepší. Příkladem neordinální kategoriální proměnné je např. pohlaví, které může nabývat hodnot “žena” nebo “muž.” Na rozdíl od předchozího případu zde není jasné pořadí, ve kterém by měly být hodnoty uspořádány.
Kategoriální proměnné je možné kódovat např. jako celá čísla: např. muž bude 0 a žena 1, nejhorší kvalita služby bude 0, druhá nejhorší 1 atd. To však není dobrý nápad hned z několika důvodů: 1) je obtížné pamatovat si, co která hodnota znamená, 2) R nebude vědět, jak s takovými proměnnými zacházet a bude je považovat za kardinální veličiny (tj. bude např. kvalitu služby “průměrnou” kódovanou jako 2 považovat za dvakrát lepší než kvalitu “špatnou” kódovanou jako 1, přestože jediné, co víme, je, že “průměrná” kvalita je lepší než “špatná,” ale už ne o kolik nebo kolikrát) a 3) R nebude schopné hlídat, zda není zadána nesmyslná úroveň proměnné (např. kvalita služby 7). Faktory řeší všechny tyto problémy: jednotlivým hodnotám dávají “nálepky,” které ukazují na jejich význam, a zároveň říkají R, že se jedná o kategoriální proměnnou. Ve statistické analýze pak zachází s faktory správně; v ekonometrické analýze např. automaticky vytvoří pro jednotlivé úrovně faktoru potřebné umělé proměnné. R také zná platné úrovně faktorů a hlídá, zda je zadaná úroveň platná.
Faktory se tvoří pomocí funkce factor()
. Ta vyžaduje nutně pouze vektor řetězců, který obsahuje hodnoty, které se mají na faktor převést:
factor(c("žena", "muž", "muž", "žena"))
## [1] žena muž muž žena
## Levels: muž žena
V tomto případě R odhaduje úrovně faktoru z dat, což není příliš bezpečné, protože v konkrétním datovém vzorku může některá platná úroveň faktoru chybět a některá zadaná úroveň nemusí být platná (např. kvůli chybě zapisovatele do dotazníků). Obecně je bezpečnější říct funkci factor()
i to, jakých hodnot může faktor nabývat (pomocí parametru levels
). To umožní zadat i hodnoty, které nyní zadaný vektor neobsahuje, ale obsahovat by je mohl, a také určit pořadí faktorů, které R jinak řadí podle abecedy. (Pořadí úrovní je důležité zejména pro ordinální faktory. Ovšem i u neordinálních faktorů při některých statistických metodách určuje, která hodnota bude brána jako referenční úroveň.) Parametr labels
navíc umožňuje úrovně faktorů překódovat:
factor(c("male", "female", "female", "male", "female"), # hodnoty vektoru
levels = c("female", "male", "asexual"), # možné úrovně
labels = c("žena", "muž", "asexuální")) # co se bude vypisovat
## [1] muž žena žena muž žena
## Levels: žena muž asexuální
Všimněte si, že při vypsání faktor vypisuje nejen hodnoty vektoru, nýbrž i seznam hodnot, kterých mohou nabývat.
Pokud se pokusíte uložit do faktoru hodnotu, která neodpovídá zadaným úrovním, R danou hodnotu tiše nahradí hodnotou NA
:
factor(c("male", "female", "female", "male", "beaver"), # hodnoty vektoru
levels = c("female", "male", "asexual"), # možné úrovně
labels = c("žena", "muž", "asexuální")) # co se bude vypisovat
## [1] muž žena žena muž <NA>
## Levels: žena muž asexuální
To je velmi šikovné, protože to umožňuje hlídat, zda jsou všechny hodnoty zadané správně. Řekněme, že svá data stahujete z nějakého serveru, který s vámi nespolupracuje a může kdykoli bez varování změnit kódování některých kategoriálních hodnot. Jedna možnost, jak to zjistit, je převádět je z řetězců na faktory s pevně zadanými hodnotami úrovní. Pokud se mezi hodnotami faktoru objeví NA
, znamená to, že server změnil kódování dané proměnné.
Implicitně jsou všechny faktory ne-ordinální. Pokud chcete R říci, že faktor je ordinální, přidáte parametr ordered = TRUE
. Pak na faktory funguje porovnání větší a menší:
<- factor(c("poor", "satisfactory", "excelent"),
quality levels = c("poor", "satisfactory", "excelent"),
ordered = TRUE)
quality
## [1] poor satisfactory excelent
## Levels: poor < satisfactory < excelent
1] < quality[3] # quality[i] je i-tý prvek vektoru quality[
## [1] TRUE
Funkce is.ordered()
vrací logickou hodnotu TRUE
, pokud je faktor ordinální.
Pozor! Pokud opravdu dobre nevite, co delate, pouzivejte radeji ne-ordinalni faktory. Ordinalni faktory se ve formulich (tj. napr. v ekonometricke analyze, viz kapitola 18) chovaji jinak, nez byste mozna cekali, viz https://goo.gl/HY3uNf a https://goo.gl/F9Shll, oddíl 11.1.1.
Hodnoty úrovní můžete získat pomocí funkce levels()
; jejich počet pomocí funkce nlevels()
. Funkce levels()
umožňuje i měnit hodnoty úrovní faktoru:
<- factor(c("female", "male", "female"))
f f
## [1] female male female
## Levels: female male
levels(f) <- c("a", "b", "c")
f
## [1] a b a
## Levels: a b c
6.1.1 Tvorba faktoru ze spojité proměnné
Někdy je užitečné rozdělit spojitou škálu do diskrétních hodnot, takže spojitou proměnnou změníte na ordinální faktor. Např. můžeme chtít rozdělit studenty do tří kategorií podle jejich studijního průměru: na excelentní žáky (do průměru 1.2 včetně), běžné žáky (od průměru 1.2 do 2.5 včetně) a ostatní. K tomu slouží funkce cut()
:
<- c(1.05, 3.31, 2.57, 1.75, 2.15) # studijní průměry
grades <- cut(grades, breaks = c(0, 1.2, 2.5, Inf), right = TRUE)
students students
## [1] (0,1.2] (2.5,Inf] (2.5,Inf] (1.2,2.5] (1.2,2.5]
## Levels: (0,1.2] (1.2,2.5] (2.5,Inf]
levels(students) <- c("excelent", "normal", "rest")
students
## [1] excelent rest rest normal normal
## Levels: excelent normal rest
Změnu názvů úrovní je možné nastavit přímo ve funkci cut()
parametrem labels
. Detaily použití funkce cut()
najdete v dokumentaci funkce.
Jako mnoho jiných funkcí ve standardní výbavě R má i funkce cut()
mnoho (na první pohled) složitých parametrů. Balík ggplot2 nabízí tři specializovanějí funkce, které udělají stejnou práci jako cut()
, ale jejich použití je jednodušší: cut_width()
nařeže původní proměnnou na úrovně s danou šířkou, cut_interval()
na daný počet úrovní se stejnou šířkou a cut_number()
na daný počet úrovní se stejným počtem pozorování.
6.1.2 Převod faktorů na čísla
Faktory jsou užitečné, ale i zrádné. Technicky jsou implementované jako vektor celých čísel, který má navíc pojmenované úrovně:
unclass(factor(c("žena", "muž", "muž", "žena")))
## [1] 2 1 1 2
## attr(,"levels")
## [1] "muž" "žena"
Při automatické konverzi se tedy může stát, že se faktor převede na celá čísla – svých úrovní. Většinou to nevadí, existují však zrádné situace, kdy název úrovně faktoru je složen z číslic. Nejdříve si to ukážeme na poněkud legračním příkladu:
<- factor(c("747", "737", "777", "747")) # vektor typů vašich letadel Boeing
f f
## [1] 747 737 777 747
## Levels: 737 747 777
as.integer(f) # chcete dostat zpět typy letadel, ale ouha! dostanete čísla úrovní!
## [1] 2 1 3 2
as.integer(as.character(f)) # je potřebná dvojí konverze!
## [1] 747 737 777 747
Realističtější situace vznikne, když faktory odpovídají nařezané spojité proměnné. Zde si ji vytvoříme, ale typicky už je taková proměnná obsažena v datech:
<- rnorm(100) # sto čísel náhodně vybraných z normovaného norm. rozdělení
x <- cut(x, # faktor nařezaný od -10 po +10 po dvou, jméno binu je střed intervalu
h breaks = seq(from = -10, to = 10, by = 2),
labels = seq(from = -9, to = 9, by = 2))
h
## [1] 1 -3 -1 -1 1 -1 -1 1 1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 1 -1 3 1 -1 3
## [26] 1 -1 1 1 1 1 -1 -1 -1 -1 -1 1 -1 1 1 -1 1 -1 1 -1 -1 -1 1 -1 -1
## [51] -1 1 1 -1 -3 -1 1 -3 1 -1 1 1 1 -1 -1 1 1 1 1 1 -1 -1 1 1 -1
## [76] -1 1 1 1 1 -1 -1 1 -1 -1 -1 1 -1 1 1 1 -1 -1 -1 1 -1 -1 -3 -1 1
## Levels: -9 -7 -5 -3 -1 1 3 5 7 9
Řekněme, že chceme spočítat průměrnou hodnotu pozorování a zkusíme to udělat takto:
mean(as.numeric(h))
## [1] 5.44
V našem případě bychom čekali výsledek někde kolem nuly, takže náš výsledek je očividně nesprávný. V případě skutečných dat s neznámým rozdělením si však nemusíte všimnout ničeho podezřelého. Chybný výsledek vznikl tak, že R prvně převedlo funkcí as.numeric()
faktory na jejich úrovně označeného 1, 2 atd. a z nich následně spočítalo průměr. To, co jsme chtěli dostat, bylo ve skutečnosti toto:
mean(as.numeric(as.character(h)))
## [1] -0.12
mean(as.numeric(levels(h)[h])) # totéž jinými slovy
## [1] -0.12
6.1.3 Úpravy faktorů
Většinou pracujeme s faktory tak, jak jsou. Někdy je však potřebujeme nějakým způsobem transformovat: vyřadit nepoužité úrovně, spojit různé faktory, přejmenovat jejich úrovně apod. Některé z těchto úprav jsou překvapivě netriviální. Naštěstí existuje balík, který tyto úpravy zjednodušuje. Zde se podíváme jen na vybrané základní situace. Pro náročnější situace doporučujeme se podívat na dokumentaci balíku forcats.
Obvykle nejpotřebnější úpravou faktorů je vyřazení nepotřebných úrovní. Pokud totiž z faktoru vybereme jen některá pozorování, zůstanou ve faktoru zachovány všechny úrovně, i ty, kterým ve vektoru už neodpovídá žádné pozorování:
1:5] h[
## [1] 1 -3 -1 -1 1
## Levels: -9 -7 -5 -3 -1 1 3 5 7 9
Pokud chceme nepoužité úrovně vypustit, musíme operátoru hranatá závorka dát parametr drop=TRUE
:
1:5, drop = TRUE] h[
## [1] 1 -3 -1 -1 1
## Levels: -3 -1 1
Druhou častou úpravou je spojování dvou vektorů faktorů. Od verze 4.1 funguje spojování faktorů přesně tak, jak byste očekávali:
<- factor(c("a", "b", "c"))
f1 <- factor(c("x", "y", "z"))
f2 c(f1, f2)
## [1] a b c x y z
## Levels: a b c x y z
Ve starších verzích to nebylo tak jednoduché, protože funkce c()
převedla faktory na celá čísla (jejich úrovně) a nálepky úrovní zahodila. Pokud se navíc úrovně faktorů lišily, tento fakt byl zcela zapomenut. Spojení faktorů pak bylo třeba provést oklikou: před spojením faktory převést na jejich úrovně (řetězce), ty spojit, a výsledek převést opět na faktor:
factor(c(as.character(f1), as.character(f2)))
## [1] a b c x y z
## Levels: a b c x y z
factor(c(levels(f1)[f1], levels(f2)[f2])) # totéž jinými slovy
## [1] a b c x y z
## Levels: a b c x y z
V moderním R to však už naštěstí není potřeba. Faktory jsou díky tomu podstateně bezpečnější.
Poslední obvyklou transformací faktorů je změna pořadí jejich úrovní. K tomu existují v principu dva důvody: Zaprvé, někdy potřebujeme nastavit referenční úroveň faktoru. Např. v ekonometrii R samo vytvoří pro jednotlivé úrovně faktoru potřebné umělé proměnné. Přitom samozřejmě jednu úroveň (referenční úroveň nebo také kontrast) vynechá. R automaticky vynechává první úroveň. Pokud jsme nezadali jména úrovní explicitně, pak R vynechá tu úroveň, která je první v abecedě. To však často není to, co chceme. Změnu referenční úrovně provedeme snadno pomocí funkce relevel()
. Jejím první parametrem je faktor, druhým je nová referenční úroveň (všimněte si pořadí úrovní na konci výpisu faktoru):
relevel(h, "1")
## [1] 1 -3 -1 -1 1 -1 -1 1 1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 1 -1 3 1 -1 3
## [26] 1 -1 1 1 1 1 -1 -1 -1 -1 -1 1 -1 1 1 -1 1 -1 1 -1 -1 -1 1 -1 -1
## [51] -1 1 1 -1 -3 -1 1 -3 1 -1 1 1 1 -1 -1 1 1 1 1 1 -1 -1 1 1 -1
## [76] -1 1 1 1 1 -1 -1 1 -1 -1 -1 1 -1 1 1 1 -1 -1 -1 1 -1 -1 -3 -1 1
## Levels: 1 -9 -7 -5 -3 -1 3 5 7 9
Zadruhe, nekdy chceme seradit urovne faktoru podle nejake charakteristiky dat - napr. proto, ze poradi urovni ovlivnuje poradi, ve kterem jsou data vykreslena v grafu. Toto je prekvapive netrivialni problem. Muzete pouzit bud zakladni funkci reorder()
, ktera je velmi mocna, ale ma ponekud komplikovane ovladani, nebo privetivejsi funkce z baliku forcats. Navod na jejich pouziti najdete v kapitole o baliku **forcats* v knize Wickham and Grolemund (2017) dostupne take na http://r4ds.had.co.nz/factors.html nebo v referencni prirucce baliku, ktera je dostupna na http://forcats.tidyverse.org/.
6.1.4 Poznámka k faktorům
Historicky se faktory používaly velmi často, protože šetřily paměť počítače. Místo vektoru řetězců, kde se hodnoty často opakovaly, zbyl krátký vektor unikátních hodnot řetězců (úrovně levels
) a paměťově úspornější vektor celých čísel, který říkal, která úroveň se právě používá. Dnes to však už není pravda: R skladuje řetězce v jednom velkém skladu, každý z nich pouze jednou a vektory řetězců jsou implementovány jako odkazy do tohoto skladu. Prakticky to znamená, že převedením řetězců na faktory se žádná paměť neušetří.
Nicméně, z těchto historických důvodů se funkce ze základních balíků R často snaží řetězce převádět na faktory. Příkladem takových funkcí jsou např. funkce data.frame()
a read.csv()
, které historicky převáděly řetězce na faktory. Tomu šlo zabránit nastavením parametru stringsAsFactors
na hodnotu FALSE
. R od verze 4.0 však tyto konverze v těchto funkcích neprovádí. Pokud tedy chcete převést řetězec na faktor, musíte buď nastavit explicitně parametr stringsAsFactors
na hodnotu TRUE
, nebo převést proměnnou na faktor ručně pomocí funkce factor()
, což je mnohem rozumnější.