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:
## [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ší:
quality <- factor(c("poor", "satisfactory", "excelent"),
levels = c("poor", "satisfactory", "excelent"),
ordered = TRUE)
quality
## [1] poor satisfactory excelent
## Levels: poor < satisfactory < excelent
## [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:
## [1] female male female
## Levels: female male
## [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()
:
grades <- c(1.05, 3.31, 2.57, 1.75, 2.15) # studijní průměry
students <- cut(grades, breaks = c(0, 1.2, 2.5, Inf), right = TRUE)
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]
## [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ě:
## [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:
## [1] 747 737 777 747
## Levels: 737 747 777
## [1] 2 1 3 2
## [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:
x <- rnorm(100) # sto čísel náhodně vybraných z normovaného norm. rozdělení
h <- cut(x, # faktor nařezaný od -10 po +10 po dvou, jméno binu je střed intervalu
breaks = seq(from = -10, to = 10, by = 2),
labels = seq(from = -9, to = 9, by = 2))
h
## [1] -1 1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 1 1 -1 1 1 -1 -1 1 1 -3 1
## [26] 1 -1 1 1 1 -1 -1 -1 1 1 -1 1 1 1 -1 1 -1 -1 1 3 -1 -1 1 1 -1
## [51] 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
## [76] 1 -1 -1 1 1 -1 1 1 1 1 -1 -1 -1 3 1 -1 -3 -1 1 1 1 -1 1 3 -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:
## [1] 5.51
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:
## [1] 0.02
## [1] 0.02
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] -1 1 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] -1 1 1 -1 -1
## Levels: -1 1
Druhou častou úpravou je spojování dvou vektorů faktorů. Na první pohled by se mohlo zdát, že by mělo stačit použít funkci pro spojení atomických vektorů c()
. To však nebude fungovat, protože funkce c()
převede faktory na celá čísla (jejich úrovně) a nálepky úrovní zahodí. Pokud se navíc úrovně faktorů liší, tento fakt bude zcela zapomenut:
## [1] 1 2 3 1 2 3
Spojení faktorů je tedy třeba provést tak, že se před spojením faktory převedou na své úrovně a po spojení opět na faktory:
## [1] a b c x y z
## Levels: a b c x y z
## [1] a b c x y z
## Levels: a b c x y z
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):
## [1] -1 1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 1 1 -1 1 1 -1 -1 1 1 -3 1
## [26] 1 -1 1 1 1 -1 -1 -1 1 1 -1 1 1 1 -1 1 -1 -1 1 3 -1 -1 1 1 -1
## [51] 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
## [76] 1 -1 -1 1 1 -1 1 1 1 1 -1 -1 -1 3 1 -1 -3 -1 1 1 1 -1 1 3 -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()
, read.csv()
apod. Pokud tyto funkce používáte a chcete automatickému převodu řetězců na faktory zabránit, musíte o to R explicitně požádat (např. ve funkci data.frame()
pomocí parametru stringsAsFactors
). Rozhodně doporučuji, abyste to udělali – a pokud chcete řetězce na faktory opravdu převést, abyste je převedli sami funkcí factor()
a při tom zadali úrovně faktorů explicitně. Alternativou je používat modernější funkce ze skupiny tidyverse, které řetězce na faktory automaticky nepřevádějí.
References
Wickham, Hadley, and Garrett Grolemund. 2017. R forData Science. 1st ed. Sebastopol, California, USA: O'Reilly. http://r4ds.had.co.nz/.