- atomické vektory
- atomické matice
- seznamy
- datasety
- indexování a subsetting
- (tibble)
Základní datové struktury podle dvou charakteristik:
dimenze | homogenní | heterogenní |
---|---|---|
1 | atomický vektor | seznam |
2 | matice | dataset |
více | pole | \(\strut\) |
Nejzákladnější datovou strukturou je v R atomický vektor (R nemá skalár – skalár je atomický vektor s jediným prvkem).
Atomický vektor je vektor hodnot, jehož všechny prvky mají stejný typ (např. celé číslo).
Atomické vektory se vytvářejí funkcí c()
(od "concatenate"), která "slepí" jednotlivé hodnoty dohromady, přičemž provede automatickou konverzi (pokud je potřeba).
x <- c(1, 2, 3, 17) print(x)
## [1] 1 2 3 17
c()
Pomocí funkce c()
je možné "slepit" i celé vektory:
x1 <- c(1, 2, 3) x2 <- c(4, 5, 6, NA) x <- c(x1, x2) print(x)
## [1] 1 2 3 4 5 6 NA
Všechny prvky atomického vektoru musejí mít stejný typ. Pokud tedy při tvorbě atomického vektoru smícháte proměnné různých typů, dojde k automatické konverzi:
c(TRUE, 1, "ahoj") # výsledek je vektor tří řetězců
## [1] "TRUE" "1" "ahoj"
c()
: pojmenované prvky (1)Jednotlivé prvky atomických vektorů mohou mít jména – atribut names
. Je možné je zadat ve funkci c()
, pomocí funkce attr()
nebo pomocí funkce names()
:
x <- c(a = 1, "good parameter" = 7, c = 17) x
## a good parameter c ## 1 7 17
attr(x, "names") <- c("A", "Good Parameter", "C") x
## A Good Parameter C ## 1 7 17
c()
: pojmenované prvky (2)names(x) <- c("aa", "bb", "cc") names(x)
## [1] "aa" "bb" "cc"
x
## aa bb cc ## 1 7 17
Délku vektoru je možné zjistit pomocí funkce length()
:
x
## aa bb cc ## 1 7 17
length(x)
## [1] 3
Atomický vektor (i další datové struktury) mohou mít v R nulové rozměry (nulovou délku, nulový počet řádků apod.):
x <- 1:9 y <- x[x > 10] # vybereme prvky větší než 10, viz dále length(y)
## [1] 0
y
## integer(0)
Konstrukce prázdného numerického vektoru:
z <- numeric(0) # parametr je délka vektoru
Vytvořte vektory:
v1
= (T, F, T)v2
= (1, 2, 3)Spojte je dohromady: v
= (v1
, v2
).
Je vektor v
atomický? Pokud ano, jaký má typ?
Jakou má vektor v
délku?
1:10 # vektor celých čísel 1 až 10
## [1] 1 2 3 4 5 6 7 8 9 10
10:1 # vektor celých čísel sestupně 10 až 1
## [1] 10 9 8 7 6 5 4 3 2 1
1:0 # pozor!
## [1] 1 0
Problematické:
for (k in 1:length(x)) udělej_něco_s(x[k])
seq(from = 1, to = 10, by = 3) # s daným krokem
## [1] 1 4 7 10
seq(from = 1, to = 10, length.out = 4) # s danou délkou výsledku
## [1] 1 4 7 10
seq_along(c(1, 3, 17, 31)) # celá čísla od 1 do délky zadaného vektoru
## [1] 1 2 3 4
seq_len(7) # celá čísla od 1 nahoru se zadanou nezápornou délkou
## [1] 1 2 3 4 5 6 7
# opakování hodnot ve vektoru rep(c(1, 3), times = 5) # celý vektor 5 krát
## [1] 1 3 1 3 1 3 1 3 1 3
rep_len(c(1, 3), length.out = 5) # celý vektor do délky 5
## [1] 1 3 1 3 1
rep(c(1, 3), each = 3) # každý prvek 3 krát
## [1] 1 1 1 3 3 3
rep(1:6, each = 2, times = 3)
## [1] 1 1 2 2 3 3 4 4 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 ## [36] 6
Vytvořte vektory
Jednotlivé prvky se skládají vedle sebe do řádku. Pokud se všechny hodnoty na řádek nevejdou, začne se vypisovat na dalším řádku.
1:31
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ## [24] 24 25 26 27 28 29 30 31
I když se vektory vypisují na obrazovku po řádcích, nejsou ani řádkové (ani sloupcové).
Veškeré aritmetické a logické operace se na vektorech provádí po prvcích:
x <- 1:6 y <- 2:7 x * y
## [1] 2 6 12 20 30 42
x ^ 2
## [1] 1 4 9 16 25 36
Pokud se délka vektorů liší, pak R automaticky "recykluje" kratší vektor. (R vydá varování jen v případě, že délka delšího vektoru není celočíselným násobkem délky kratšího vektoru):
x <- 1:2 y <- 1:6 x + y
## [1] 2 4 4 6 6 8
y <- 1:7 x + y
## Warning in x + y: longer object length is not a multiple of shorter object ## length
## [1] 2 4 4 6 6 8 8
K otestování, zda je proměnná atomický vektor slouží funkce is.atomic()
:
is.atomic(x)
Funkce is.vector()
vrací logickou hodnotu TRUE
pro atomický vektor i pro neatomický vektor (seznam):
is.atomic(list(1, TRUE, "ahoj"))
## [1] FALSE
is.vector(list(1, TRUE, "ahoj"))
## [1] TRUE
Atomická matice je matice (tj. dvourozměrná tabulka), jejíž všechny prvky mají stejný datový typ (např. celé číslo).
Lze vytvořit pomocí funkce matrix()
:
matrix(1:9, nrow = 3)
## [,1] [,2] [,3] ## [1,] 1 4 7 ## [2,] 2 5 8 ## [3,] 3 6 9
Data se recyklují:
matrix(1:9, nrow = 3, ncol = 4, byrow = TRUE)
## Warning in matrix(1:9, nrow = 3, ncol = 4, byrow = TRUE): data length [9] ## is not a sub-multiple or multiple of the number of columns [4]
## [,1] [,2] [,3] [,4] ## [1,] 1 2 3 4 ## [2,] 5 6 7 8 ## [3,] 9 1 2 3
Otestovat, zda je objekt matice, je možné pomocí funkce is.matrix()
.
Převést data na matici je možné pomocí konverzní funkce as.matrix()
.
m <- matrix(1:12, nrow = 3) m
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12
nrow(m)
## [1] 3
ncol(m)
## [1] 4
m
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12
dim(m)
## [1] 3 4
length(m) # délka podkladového vektoru
## [1] 12
(Pro vektory vrací nrow()
, ncol()
a dim()
hodnotu NULL
.)
Matice a podobné objekty je možné skládat pomocí funkcí rbind()
a cbind()
:
A <- matrix(1:12, nrow = 3) B <- matrix(101:112, nrow = 3) rbind(A, B) # položí dvě matice pod sebe
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12 ## [4,] 101 104 107 110 ## [5,] 102 105 108 111 ## [6,] 103 106 109 112
cbind(A, B) # položí dvě matice vedle sebe
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] ## [1,] 1 4 7 10 101 104 107 110 ## [2,] 2 5 8 11 102 105 108 111 ## [3,] 3 6 9 12 103 106 109 112
Vektory se složí do matic:
x1 <- 1:3 x2 <- 4:6 rbind(x1, x2) # pod sebe jako řádkové vektory
## [,1] [,2] [,3] ## x1 1 2 3 ## x2 4 5 6
cbind(x1, x2) # vedle sebe jako sloupcové vektory
## x1 x2 ## [1,] 1 4 ## [2,] 2 5 ## [3,] 3 6
Vytvořte
M1
\(3 \times 3\)M0
\(3 \times 3\)Z obou matic složte blokovou matici tak, že výsledkem bude bloková matice M
\(6 \times 6\):
\[\left(\begin{matrix} M1 & M0 \\ M0 & M1 \end{matrix}\right) = \left(\begin{matrix} 1 & 1 & 1 & 0 & 0 & 0 \\ 1 & 1 & 1 & 0 & 0 & 0 \\ 1 & 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 1 & 1 \\ 0 & 0 & 0 & 1 & 1 & 1 \\ 0 & 0 & 0 & 1 & 1 & 1 \end{matrix}\right)\]
Matice mohou mít následující atributy:
dim
je celočíselný vektor rozměrůrownames
jsou jména řádkůcolnames
jsou jména sloupcůdimnames
jména dimenzí, řádků a sloupcůA <- matrix(1:12, nrow = 3) rownames(A) <- c("a", "b", "c") colnames(A) <- c("alpha", "beta", "gamma", "delta") A
## alpha beta gamma delta ## a 1 4 7 10 ## b 2 5 8 11 ## c 3 6 9 12
A <- matrix(1:12, nrow = 3) dimnames(A) <- list(id = c("A", "B", "C"), variables = c("Alpha", "Beta", "Gamma", "Delta")) A
## variables ## id Alpha Beta Gamma Delta ## A 1 4 7 10 ## B 2 5 8 11 ## C 3 6 9 12
attributes(A)
## $dim ## [1] 3 4 ## ## $dimnames ## $dimnames$id ## [1] "A" "B" "C" ## ## $dimnames$variables ## [1] "Alpha" "Beta" "Gamma" "Delta"
Atomická matice je implementována jako atomický vektor, který má přiřazený atribut dim
, který je celočíselný vektor délky dva:
M <- 1:12 M
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
dim(M) <- c(3, 4) M
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12
is.matrix(M)
## [1] TRUE
Zrušením atributu dim
převést matici zpět na vektor (matice se vektorizuje po sloupcích):
dim(M) <- NULL M
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
M <- matrix(1:12, nrow = 3) is.atomic(M)
## [1] TRUE
is.vector(M)
## [1] FALSE
*
)/
)^
)%*%
)solve()
)diag()
)t()
)Rozměry matic přitom musejí být správné.
Atomické pole je vícerozměrná tabulka (tabulka, která má víc než dva rozměry), jehož všechny prvky mají stejný datový typ.
array(1:27, dim = c(2, 2, 2))
## , , 1 ## ## [,1] [,2] ## [1,] 1 3 ## [2,] 2 4 ## ## , , 2 ## ## [,1] [,2] ## [1,] 5 7 ## [2,] 6 8
Neatomické vektory (seznamy) jsou vektory, jejichž jednotlivé prvky mohou mít různé datové typy:
l <- list(1:3, "ahoj", list(1, "bum")) l
## [[1]] ## [1] 1 2 3 ## ## [[2]] ## [1] "ahoj" ## ## [[3]] ## [[3]][[1]] ## [1] 1 ## ## [[3]][[2]] ## [1] "bum"
Seznamy mohou mít atribut names
:
l <- list(a = 1, b = "ahoj", c = 1:3, d = list(1:3, "ahoj")) names(l)
## [1] "a" "b" "c" "d"
l
## $a ## [1] 1 ## ## $b ## [1] "ahoj" ## ## $c ## [1] 1 2 3 ## ## $d ## $d[[1]] ## [1] 1 2 3 ## ## $d[[2]] ## [1] "ahoj"
Délku seznamu zjistíme pomocí funkce length()
:
length(l)
## [1] 4
K otestování, zda je proměnná seznam, slouží funkce is.list(l)
.
is.list(l)
## [1] TRUE
is.vector(l)
## [1] TRUE
Pozor: Funkce is.vector()
vrací hodnotu TRUE
i pro seznamy.
Vytvořte atomický vektor v
a seznam l
, do kterých umístíte pojmenované položky:
a
= TRUE
b
= 1c
= 1:3d
= "ahoj"Jak se v
a l
liší?
Dataset je nejdůležitější datová struktura pro analýzu dat.
Dataset je tabulka, jejichž řádky představují jednotlivá pozorování a sloupce jednotlivé proměnné.
Technicky se jedná o seznam atomických vektorů o stejné délce, které jsou spojené vedle sebe. Každý vektor (sloupec tabulky) může obsahovat proměnné jiného typu.
Chceme zaznamenat údaje o subjektech experimentu. Pro každý subjekt pozorujeme jeho id, výšku a váhu:
experiment <- data.frame(id = c(1, 2, 3, 41), vyska = c(158, 174, 167, 203), vaha = c(51, 110, 68, 97)) experiment
## id vyska vaha ## 1 1 158 51 ## 2 2 174 110 ## 3 3 167 68 ## 4 41 203 97
Při zadávání vektorů do datasetu můžeme zadat jejich jména, která pak R vypíše. R samo přidá jména řádků (automaticky jim dá přirozená čísla od 1 do počtu pozorování).
nrow(experiment) # počet řádků
## [1] 4
ncol(experiment) # počet sloupců
## [1] 3
length(experiment) # počet sloupců
## [1] 3
dim(experiment) # vektor počtu řádků a sloupců
## [1] 4 3
experiment <- data.frame(id = c(1, 2, 3, 41), gender = "muž", vyska = c(158, 174, 167, 203), vaha = c(51, 110, 68, 97), zdravy = c(TRUE, TRUE, FALSE, TRUE), stringsAsFactors = FALSE) experiment
## id gender vyska vaha zdravy ## 1 1 muž 158 51 TRUE ## 2 2 muž 174 110 TRUE ## 3 3 muž 167 68 FALSE ## 4 41 muž 203 97 TRUE
Při zadání dat do dataset pomocí funkce data.frame()
R převede všechny řetězce na faktory. Této konverzi zabrání parametr stringsAsFactors = FALSE
.
Datasety mají standardně tři atributy:
class
(jméno třídy – data set je totiž objekt)names
jména sloupců (tj. jednotlivých proměnných)row.names
obsahuje jména jednotlivých řádkůattributes(experiment)
## $names ## [1] "id" "gender" "vyska" "vaha" "zdravy" ## ## $row.names ## [1] 1 2 3 4 ## ## $class ## [1] "data.frame"
Jména řádků můžete zjistit i změnit pomocí funkcí rownames()
a row.names()
, jména sloupců pomocí funkcí colnames()
nebo names()
:
colnames(experiment) <- c("id", "sex", "height", "weight", "healthy") experiment
## id sex height weight healthy ## 1 1 muž 158 51 TRUE ## 2 2 muž 174 110 TRUE ## 3 3 muž 167 68 FALSE ## 4 41 muž 203 97 TRUE
Jména řádků nepoužívejte.
Třídu objektu neměňte.
as.matrix(experiment) # použije automatickou konverzi na stejný typ
## id sex height weight healthy ## [1,] " 1" "muž" "158" " 51" " TRUE" ## [2,] " 2" "muž" "174" "110" " TRUE" ## [3,] " 3" "muž" "167" " 68" "FALSE" ## [4,] "41" "muž" "203" " 97" " TRUE"
data.matrix(experiment) # použije explicitní konverzi na reálná čísla
## Warning in data.matrix(experiment): NAs introduced by coercion
## id sex height weight healthy ## [1,] 1 NA 158 51 1 ## [2,] 2 NA 174 110 1 ## [3,] 3 NA 167 68 0 ## [4,] 41 NA 203 97 1
Matici lze převést na dataset pomocí funkcí as.data.frame()
i data.frame()
. Pokud má matice pojmenované sloupce, jejich jména jsou v datasetu zachována; v opačném případě je R samo pojmenuje V1
, V2
atd nebo X1
, X2
atd.
M <- matrix(1:12, nrow = 3) colnames(M) <- c("a", "b", "c", "d") as.data.frame(M)
## a b c d ## 1 1 4 7 10 ## 2 2 5 8 11 ## 3 3 6 9 12
Vytvořte dataset pupils
, který bude obsahovat
Jména by měla být uložená jako řetězce, známky jako faktor s hodnotami "A" až "F".
Někdy se hodí vytvořit dataset, který obsahuje všechny možné kombinace hodnot nějakého vektoru:
expand.grid(x = 1:3, y = factor(c("male", "female")), z = c(TRUE, FALSE))
## x y z ## 1 1 male TRUE ## 2 2 male TRUE ## 3 3 male TRUE ## 4 1 female TRUE ## 5 2 female TRUE ## 6 3 female TRUE ## 7 1 male FALSE ## 8 2 male FALSE ## 9 3 male FALSE ## 10 1 female FALSE ## 11 2 female FALSE ## 12 3 female FALSE
Ke zjištění struktury a obsahu datové struktury slouží funkce str()
:
n <- 1:12 str(n)
## int [1:12] 1 2 3 4 5 6 7 8 9 10 ...
l <- list(a = 1, b = 1:3, "ahoj", d = list(1, 1:2, TRUE)) str(l)
## List of 4 ## $ a: num 1 ## $ b: int [1:3] 1 2 3 ## $ : chr "ahoj" ## $ d:List of 3 ## ..$ : num 1 ## ..$ : int [1:2] 1 2 ## ..$ : logi TRUE
d <- data.frame(experiment) str(d)
## 'data.frame': 4 obs. of 5 variables: ## $ id : num 1 2 3 41 ## $ sex : chr "muž" "muž" "muž" "muž" ## $ height : num 158 174 167 203 ## $ weight : num 51 110 68 97 ## $ healthy: logi TRUE TRUE FALSE TRUE
Chceme vybrat jen vybrané prvky datové struktury.
K základnímu subsetování slouží hranaté závorky ([]
). V nich se určí indexy prvků, které je třeba vybrat:
Hranaté závorky vrací objekt stejné třídy, jako je původní objekt.
Operátor dvojitých hranatých závorek ([[]]
), který extrahuje prvky ze seznamů, datasetů a podobných struktur. Podobnou funkci plní i operátor dolar ($
).
Subsetování lze použít nejen k získání vybraných prvků z datové struktury, ale také k jejich nahrazení nebo doplnění.
Prvky jsou číslované přirozenými čísly \(1,\ldots,N\).
Indexování pomocí kladných a záporných čísel nelze míchat. Index 0 se tiše ignoruje.
# vektor letters obsahuje 26 malých písmen anglické abecedy x <- letters[1:12] # prvních dvanáct písmen abecedy x
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l"
x
## [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l"
x[1] # první prvek
## [1] "a"
x[3] # třetí prvek
## [1] "c"
x[length(x)] # poslední prvek
## [1] "l"
x[3:6] # třetí až šestý prvek včetně
## [1] "c" "d" "e" "f"
x[c(2, 3, 7)] # druhý, třetí a sedmý prvek
## [1] "b" "c" "g"
x[c(-1, -3)] # vynechají se první a třetí prvek
## [1] "b" "d" "e" "f" "g" "h" "i" "j" "k" "l"
Pokud mají prvky jména, je možné vybírat pomocí vektoru jejich jmen (minus nefunguje – R nemá záporné řetězce):
x <- c(c = 1, b = 2, a = 3) x
## c b a ## 1 2 3
x["a"] # prvek s názvem a, tj. zde poslední prvek
## a ## 3
x[c("b", "c")] # prvky s názvy b a c
## b c ## 2 1
R vybere prvky, které jsou indexovány logickou hodnotou TRUE
a vynechá ostatní.
Pokud je logický vektor kratší než subsetovaný vektor, pak se recykluje!
x <- 1:12 x
## [1] 1 2 3 4 5 6 7 8 9 10 11 12
x[c(TRUE, TRUE, FALSE)]
## [1] 1 2 4 5 7 8 10 11
Výběr pomocí logických hodnot je užitečný zejména v situaci, kdy chceme vybrat prvky, které splňují nějakou podmínku:
x[x > 3 & x < 11] # vybere prvky větších než 3 a menších než 11
## [1] 4 5 6 7 8 9 10
x[x < 3 | x > 11] # vybere prvky menší než 3 nebo větší než 11
## [1] 1 2 12
Subsetování lze využít k nahrazení prvků jednoduše tak, že se do výběru uloží nová hodnota, která nahradí starou:
x <- c(1:3, NA, 5:7) x
## [1] 1 2 3 NA 5 6 7
x[7] <- Inf # nahrazení poslední hodnoty nekonečnem x
## [1] 1 2 3 NA 5 6 Inf
x[is.na(x)] <- 0 # nahrazení všech hodnot NA nulou x
## [1] 1 2 3 0 5 6 Inf
x[length(x) + 1] <- 8 # přidání nové hodnoty za konec vektoru x
## [1] 1 2 3 0 5 6 Inf 8
Pozor: postupné rozšiřování datových struktur vždy o několik málo prvků je výpočetně velmi neefektivní. Lepší je naráz alokovat velký blok paměti, do něj postupně uložit hodnoty a blok na konci případně zkrátit, viz lecture notes.
Vytvořte vektor v
čísel 1 až 26 a prvky pojmenujte (pomocí names()
a letters
malými písmeny anglické abecedy).
Vyberte
Nahraďte
NA
NA
hodnotou 0Vynechte z vektoru všechny nulové hodnoty.
Matice se subsetují pomocí dvou indexů: první index vybírá řádky, druhý sloupce:
M <- matrix(1:12, nrow = 3) M
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12
M[2, 3] # prvek ve druhém řádku a třetím sloupci
## [1] 8
M[1:2, c(1,4)] # prvky na prvních dvou řádcích a v prvním a čtvrtém sloupci
## [,1] [,2] ## [1,] 1 10 ## [2,] 2 11
M[-1, -1] # matice bez prvního řádku a sloupce
## [,1] [,2] [,3] ## [1,] 5 8 11 ## [2,] 6 9 12
Pokud je jeden z indexů prázdný, vybírá celý řádek nebo sloupec:
M[1:2, ] # celé první dva řádky
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11
M[, c(1, 3)] # první a třetí sloupec
## [,1] [,2] ## [1,] 1 7 ## [2,] 2 8 ## [3,] 3 9
M[M[, 1] >= 2, ] # všechny řádky, ve kterých je prvek v prvním sloupci >= 2
## [,1] [,2] [,3] [,4] ## [1,] 2 5 8 11 ## [2,] 3 6 9 12
M[M[, 1] >= 2, M[1, ] < 6] # submatice
## [,1] [,2] ## [1,] 2 5 ## [2,] 3 6
M[ , ] # celá matice M
## [,1] [,2] [,3] [,4] ## [1,] 1 4 7 10 ## [2,] 2 5 8 11 ## [3,] 3 6 9 12
Pokud se matice indexuje jen jedním indexem, R ji tiše převede na jeden vektor (spojí sloupce matice za sebe) a vybere prvky z takto vzniklého vektoru:
M[4] # vrací 1. prvek ve 2. sloupci, protože je to 4. prvek vektoru
## [1] 4
M[c(1, 4:7)]
## [1] 1 4 5 6 7
Subsetování může měnit pořadí prvků.
Funkce order()
vrací indexy uspořádané podle velikosti původního vektoru. Umožňuje setřídit hodnoty všech sloupců matice podle jednoho sloupce:
M <- matrix(c(8, 5, 7, 2, 3, 11, 6, 12, 1, 4, 9, 10), nrow = 3) M
## [,1] [,2] [,3] [,4] ## [1,] 8 2 6 4 ## [2,] 5 3 12 9 ## [3,] 7 11 1 10
# indexy prvků 1. sloupce matice M seřazené podle velikosti prvků, # tj. na 1. místě je 2. prvek původního vektoru (5), pak 3. prvek (7) atd. order(M[, 1])
## [1] 2 3 1
M[order(M[, 1]), ] # řádky matice seřazené podle prvního sloupce
## [,1] [,2] [,3] [,4] ## [1,] 5 3 12 9 ## [2,] 7 11 1 10 ## [3,] 8 2 6 4
Funkce sample()
náhodně permutuje zadaná čísla. Lze jí tak mimo jiné využít k náhodné permutaci sloupců matice:
o <- sample(ncol(M)) # čísla 1:ncol(M) v náhodném pořadí o
## [1] 1 2 3 4
M[, o]
## [,1] [,2] [,3] [,4] ## [1,] 8 2 6 4 ## [2,] 5 3 12 9 ## [3,] 7 11 1 10
Subsetování se vždy snaží snížit rozměry matice – pokud počet řádků nebo sloupců klesne na 1, matice se změní ve vektor. Pokud tomu chceme zabránit, je třeba přidat parametr drop = FALSE
.
M[, 1]
## [1] 8 5 7
M[, 1, drop = FALSE]
## [,1] ## [1,] 8 ## [2,] 5 ## [3,] 7
Z vektoru 1:16 vytvořte matici M
\(4 \times 4\).
Vyberte submatici, která obsahuje
Změňte pořadí sloupců tak, že hodnoty v prvním řádků budou uspořádané od nejvyšší po nejnižší.
Nahraďte hodnoty ve druhém řádku hodnotami NA
.
Subsetování pomocí hranatých závorek zachovává mód proměnné:
l <- list(a = 1, b = 1:3, c = "ahoj") l
## $a ## [1] 1 ## ## $b ## [1] 1 2 3 ## ## $c ## [1] "ahoj"
l[1]
## $a ## [1] 1
is.list(l[1])
## [1] TRUE
l[1:2]
## $a ## [1] 1 ## ## $b ## [1] 1 2 3
Pokud chceme získat vlastní prvek seznamu, musíme použít dvojité hranaté závorky:
l[[2]]
## [1] 1 2 3
is.list(l[[2]])
## [1] FALSE
is.numeric(l[[2]])
## [1] TRUE
Pokud je argumentem vektor, nevrací dvojité hranaté závorky vektor hodnot, nýbrž se vektor přeloží na rekurentní volání dvojitých hranatých závorek:
l[[2]][[3]] # třetí prvek vektoru, který je druhým prvkem seznamu
## [1] 3
l[[2:3]] # totéž
## [1] 3
l[[2]][3] # v tomto případě totéž
## [1] 3
Pokud jsou prvky seznamu pojmenované, nabízí R zkratku ke dvojitým hranatým závorkám: operátor dolar ($
): l[["b"]]
je totéž jako l$b
:
l[["b"]] # prvek se jménem b
## [1] 1 2 3
l$b # totéž (uvozovky se zde neuvádějí)
## [1] 1 2 3
Použití dolaru od dvojitých závorek v jednom ohledu liší: pokud máme jméno prvku, který chceme získat uloženo v proměnné, je třeba použít hranaté závorky – operátor dolar zde nelze použít:
element <- "c" # element není v uvozovkách, protože vybíráme hodnotu, # která je v něm uložená: l[[element]]
## [1] "ahoj"
Pokud indexujeme jménem prvek seznamu, který v seznamu chybí, dostaneme hodnotu NULL
. Pokud jej však indexujeme číselným indexem, dostaneme chybu:
l[[4]]
Error in l[[4]] : subscript out of bounds
l[["d"]]
## NULL
l$d
## NULL
Seznamy umožňují "partial matching":
l <- list(prvni_prvek = 1, druhy_prevk = 2) l$p # s dolarem je zapnutý
## [1] 1
l[["p"]] # s hranatými závorkami vypnutý
## NULL
l[["p", exact = FALSE]] # ale jde zapnout
## [1] 1
Partial matching nepoužívejte – je zdrojem špatně dohledatelných chyb!
Vytvořte seznam l
s prvky a
= 1
, b
= 1:3
a c
= letters
.
Získejte
l
l
l
c
pomocí závorekc
pomocí dolaruc
Nahraďte 5. až 7. prvek vektoru c
v seznamu l
mezerami.
Datasety jsou "kříženec" mezi seznamy a maticemi, takže je na ně možné je subsetovat jako matice i jako seznamy.
Pokud použijete jeden index, pak je indexujete jako seznam (po sloupcích) a [
vrátí dataset.
Pokud použijete dva indexy, pak je indexujete jako matice a [
vrátí
Dolar vrací jeden sloupec, tj. vektor.
d <- data.frame(x = 1:7, y = c(3, 1, NA, 7, 5, 12, NA)) d
## x y ## 1 1 3 ## 2 2 1 ## 3 3 NA ## 4 4 7 ## 5 5 5 ## 6 6 12 ## 7 7 NA
Výsledek je vektor:
d$x # vektor x
## [1] 1 2 3 4 5 6 7
d[["x"]] # totéž
## [1] 1 2 3 4 5 6 7
d[[1]] # totéž
## [1] 1 2 3 4 5 6 7
Výsledek je dataset s jedním sloupcem:
d["x"] # dataset s jediným sloupcem
## x ## 1 1 ## 2 2 ## 3 3 ## 4 4 ## 5 5 ## 6 6 ## 7 7
d[1] # opět dataset s jediným sloupcem
## x ## 1 1 ## 2 2 ## 3 3 ## 4 4 ## 5 5 ## 6 6 ## 7 7
Výsledek je vektor, ledaže bychom zakázali redukci rozměrů:
d[1:2, "x"] # vektor prvních dvou hodnot z vektoru x
## [1] 1 2
d[1:2, 1] # totéž
## [1] 1 2
d[1:2, 1, drop = FALSE] # dataset složený z prvních dvou hodnot vektoru x
## x ## 1 1 ## 2 2
Výsledek je dataset:
d[1:2, 1:2] # dataset složený z prvních dvou řádků
## x y ## 1 1 3 ## 2 2 1
d[1:2, c("x", "y")] # dataset složený z prvních dvou řádků
## x y ## 1 1 3 ## 2 2 1
d[1:2, ] # dataset složený z prvních dvou řádků
## x y ## 1 1 3 ## 2 2 1
Samozřejmě je možné použít i indexování pomocí logických hodnot:
d[d[, "y"] < 7, ] # výběr řádků, kde je hodnota y menší než 7
## x y ## 1 1 3 ## 2 2 1 ## NA NA NA ## 5 5 5 ## NA.1 NA NA
d[d$y < 7 , ] # totéž
## x y ## 1 1 3 ## 2 2 1 ## NA NA NA ## 5 5 5 ## NA.1 NA NA
Výběr zachová i řádky, kde je hodnota \(y\) NA
. To jde vyřešit např. takto:
# vybíráme pouze prvky, kde y zároveň není NA a # zároveň je menší než 7 nebo d[!is.na(d$y) & d$y < 7, ]
## x y ## 1 1 3 ## 2 2 1 ## 5 5 5
K vyřazení neúplných hodnot z datasetu a podobných struktur slouží funkce complete.cases()
. V případě datasetu vrací vektor logických hodnot, který je TRUE
pro každý řádek datasetu, který má všechny hodnoty známé, a FALSE
jinak.
complete.cases(d)
## [1] TRUE TRUE FALSE TRUE TRUE TRUE FALSE
d[complete.cases(d), ]
## x y ## 1 1 3 ## 2 2 1 ## 4 4 7 ## 5 5 5 ## 6 6 12
Do existujícího datasetu přidáte novou proměnnou (nový sloupec) tak, že do nové proměnné přidáte hodnoty vektoru:
d$z <- letters[1:nrow(d)] d
## x y z ## 1 1 3 a ## 2 2 1 b ## 3 3 NA c ## 4 4 7 d ## 5 5 5 e ## 6 6 12 f ## 7 7 NA g
Nová proměnná se přidá jako poslední sloupec.
Pokud do existující proměnné přiřadíte hodnotu NULL
, vyřadíte tím proměnnou z datasetu:
d$z <- NULL d
## x y ## 1 1 3 ## 2 2 1 ## 3 3 NA ## 4 4 7 ## 5 5 5 ## 6 6 12 ## 7 7 NA
Jiná možnost, jak vynechat proměnnou nebo změnit jejich pořadí, je využít subsetování sloupců datasetu.
Vytvořte dataset pupils
, který bude obsahovat
Vyberte z něj:
Přidejte do datasetu sloupec smart
s logickou hodnotou, která bude TRUE
u studentů s IQ vyšší než 100 a FALSE
u ostatních.
Později se podíváme na balík dplyr, který (mimo jiné) výrazně zjednodušuje subsetování datasetů, tvorbu nových proměnných a mnoho jiných kouzel.
Kromě data.frame
existuje v ještě několik typů datasetů.
Později budete potřebovat ještě typ tibble
, do kterého převádí datasety balíky dplyr a tidyr.
Tento typ datasetu má některé velmi příjemné vlastnosti.
Detailní popis této třídy najdete zde:
library(tibble) ds <- tibble(x = 1:1e6, y = 2 * x, zed = x / 3 + 1.5 * y - 7) ds
## # A tibble: 1,000,000 × 3 ## x y zed ## <int> <dbl> <dbl> ## 1 1 2 -3.6666667 ## 2 2 4 -0.3333333 ## 3 3 6 3.0000000 ## 4 4 8 6.3333333 ## 5 5 10 9.6666667 ## 6 6 12 13.0000000 ## 7 7 14 16.3333333 ## 8 8 16 19.6666667 ## 9 9 18 23.0000000 ## 10 10 20 26.3333333 ## # ... with 999,990 more rows
Ke konverzi jiných tříd na tibble
slouží funkce as_tibble()
a as_data_frame()
.
Ke konverzi tibble
na data.frame
slouží funkce as.data.frame()
.
Vytvoření tibble
se od vytvoření data.frame
v několika ohledech liší: tibble
tibble
pomocí as_tibble()
je rychlejší než převod na data.frame
pomocí as.data.frame()
Oproti data.frame
zobrazí tibble
navíc rozměr datasetu a typ jednotlivých proměnných. Naopak vypíše jen prvních deset řádků a jen takový počet sloupců, které se vejdou na obrazovku. Počet vypsaných řádků je možné ovlivnit bud ve funkci print()
, nebo v options()
, viz viněta:
print(ds, n = 5)
## # A tibble: 1,000,000 × 3 ## x y zed ## <int> <dbl> <dbl> ## 1 1 2 -3.6666667 ## 2 2 4 -0.3333333 ## 3 3 6 3.0000000 ## 4 4 8 6.3333333 ## 5 5 10 9.6666667 ## # ... with 1e+06 more rows
Při subsetování tibble
nikdy nezahazuje zbytečné rozměry a ani je nepřidává, tj. []
vždy vrací tibble
, zatímco [[]]
a $
vždy vrací vektor. Navíc tibble
nikdy nepodporuje partial matching:
ds <- ds[1:6, ] # omezíme ds na prvních 6 řádků ds[, 1]
## # A tibble: 6 × 1 ## x ## <int> ## 1 1 ## 2 2 ## 3 3 ## 4 4 ## 5 5 ## 6 6
ds[[1]]
## [1] 1 2 3 4 5 6
ds$z
## Warning: Unknown column 'z'
## NULL
Vstupní data budou většinou dataset. Vámi zpracovaná data můžete umístit do jakékoli struktury. Tuto strukturu byste si měli dopředu pořádně rozmyslet.
Ve většině případů doporučuji používat datasety:
Práce s ostatními datovými strukturami je mnohem méně standardizovaná, takže si víc kódu budete muset napsat sami.
Máte dvě matice se záznamy ze dvou lékařských studií. Obě matice mají stejný formát. Vašimi úkoly je:
data.frame
num_obese
uložíte počet obézních lidí