5.2 Atomické matice

Atomická matice je matice (tj. dvourozměrná tabulka), jejíž všechny prvky mají stejný datový typ (např. celé číslo). Pro datovou analýzu nejsou matice příliš důležité, někdy se však hodí pro rychlou maticovou algebru a také některé funkce vracejí nebo očekávají jako vstup matice.

Nejjednodušší způsob, jak vytvořit atomickou matici je pomocí funkce matrix(). Prvním parametrem je vektor, který obsahuje data. Další parametry určují počet řádků a počet sloupců matice, způsob, jak budou data do matice skládaná (zda podle řádků či sloupců; implicitně se data do matic skládají po sloupcích) a pojmenování dimenzí matice. Není potřeba zadávat všechny parametry, pokud R dokáže odhadnout hodnotu jednoho parametru z hodnot ostatních parametrů. R např. umí z délky zadaného vektoru a zadaného počtu řádků odhadnout počet sloupců.

matrix(1:12, nrow = 3)  # matice se třemi řádky a čtyřmi sloupci, po sloupcích
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
matrix(1:12, ncol = 4, byrow = TRUE)  # stejný rozměr, data po řádcích
##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    5    6    7    8
## [3,]    9   10   11   12

Při tvorbě matic R recykluje data. To znamená, že pokud je zadaných hodnot méně, než vyžadují rozměry matice, R začne číst datový vektor znovu od začátku. To může být zdrojem nepříjemných chyb. Naštěstí R vypíše varování, ovšem pouze v případě, že počet prvků matice není celočíselným násobkem délky zadaného vektoru.

matrix(1:9, nrow = 3, ncol = 4)
## Warning in matrix(1:9, nrow = 3, ncol = 4): data length [9] is not a sub-
## multiple or multiple of the number of columns [4]
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7    1
## [2,]    2    5    8    2
## [3,]    3    6    9    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().

Zjistit rozměry matice je možné pomocí následujících funkcí: nrow() vrátí počet řádků matice, ncol() vrátí počet sloupců matice, dim() vrací vektor s počtem řádků a sloupců matice a length() vrací počet prvků matice. (Pro vektory vrací funkce nrow(), ncol() a dim() hodnotu NULL.)

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
dim(m)
## [1] 3 4
length(m)
## [1] 12

Matice a podobné objekty je možné skládat pomocí funkcí rbind() a cbind(). První (rbind() od “row bind”) spojuje matice po řádcích (tj. skládá je pod sebe), druhá (cbind() od “column bind”) po sloupcích (tj. skládá je vedle sebe):

A <- matrix(1:12, nrow = 3)
B <- matrix(101:112, nrow = 3)
rbind(A, B)
##      [,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)
##      [,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

Matice mohou mít následující atributy: dim je celočíselný vektor rozměrů (viz výše), jména řádků (čte i nastavuje se funkcí rownames()), jména sloupců (čte i nastavuje se funkcí colnames()) a jména dimenzí včetně jmen řádků a sloupců (čte i nastavuje se funkcí dimnames()):

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

Podobně lze zrušením atributu dim převést matici zpět na vektor (matice se vektorizuje po sloupcích). Stejného výsledku jde dosáhnout pomocí funkce as.vector():

as.vector(M)
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12
dim(M) <- NULL
M
##  [1]  1  2  3  4  5  6  7  8  9 10 11 12

Protože matice je atomický vektor, který má přiřazený atribut dim, funkce is.atomic() vrací pro matici hodnotu TRUE; funkce is.vector() však samozřejmě vrací FALSE, protože testuje, zda je v proměnné uložen vektor.

M <- matrix(1:12, nrow = 3)
is.atomic(M)
## [1] TRUE
is.vector(M)
## [1] FALSE

5.2.1 Maticová aritmetika

Obyčejné symboly násobení (*), dělení (/) a umocňování (^) pracují “po prvcích”. Při násobení se např. vynásobí odpovídající prvky matice. Matice tedy musejí mít stejné rozměry (stejný počet řádků a sloupců).

A * B
##    variables
## id  Alpha Beta Gamma Delta
##   A   101  416   749  1100
##   B   204  525   864  1221
##   C   309  636   981  1344
A ^ 2
##    variables
## id  Alpha Beta Gamma Delta
##   A     1   16    49   100
##   B     4   25    64   121
##   C     9   36    81   144

Pro skutečné maticové násobení se používá operátor %*%. Inverzní matici vrací funkce solve() (obecně tato funkce řeší soustavy lineárních rovnic). K transponování matice slouží funkce t(). Hlavní diagonálu matice vrací funkce diag().

Speciální matice:

diag(1, nrow = 3, ncol = 3)  # jednotková matice
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    1    0
## [3,]    0    0    1
matrix(0, nrow = 3, ncol = 3)  # nulová matice (využívá recyklace)
##      [,1] [,2] [,3]
## [1,]    0    0    0
## [2,]    0    0    0
## [3,]    0    0    0

Příklad inverze:

M <- matrix(c(1:8, 0), nrow = 3)
invM <- solve(M)
E <- diag(1, nrow = nrow(M), ncol = ncol(M))
all.equal(M %*% invM, E)
## [1] TRUE
all.equal(invM %*% M, E)
## [1] TRUE

5.2.2 Subsetování matic

Subsetování matic je podobné jako u atomických vektorů s jedním rozdílem: protože má matice řádky a sloupce, je třeba subsetovat 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 nejen vybírat hodnoty, ale také měnit jejich pořadí. Zadáním indexů můžeme např. otočit pořadí sloupců matice:

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
M[, 4:1]
##      [,1] [,2] [,3] [,4]
## [1,]    4    6    2    8
## [2,]    9   12    3    5
## [3,]   10    1   11    7

Stejným způsobem můžeme dosáhnout i zajímavějších efektů: např. seřadit řádky nebo sloupce podle hodnot vybraného vektoru nebo je náhodně permutovat. Funkce order() vrací indexy uspořádané podle velikosti původního vektoru. Funkce např. umožňuje setřídit hodnoty všech sloupců matice podle jednoho sloupce:

# 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. (Nemělo by vám být divné, že je možné hranatým závorkám přidávat parametry – jako vše v R je i použití hranatých závorek volání funkce – a funkce mohou mít parametry.)

M[, 1]
## [1] 8 5 7
M[, 1, drop = FALSE]
##      [,1]
## [1,]    8
## [2,]    5
## [3,]    7