Matice: vektory spojené do tabulky/vektor nalámaný na sloupečky nebo řádky

Matice je druh tabulky. Má řádky a sloupce. Může mít i jen jeden řádek a/nebo jen jeden sloupec. K čemu je dobrá matice? Často bývá předepsaným vstupem pro nějakou funkci, zejména grafické funkce mají matice v oblibě. Nebo nějaká funkce naopak matici vyplivne na výstupu. Čím se liší od data.frame? Je to jednodušší datová struktura, a hlavně: je to vlastně nalámaný zohýbaný jeden vektor. Z toho plyne omezení, že všechny elementy matice, ať to vezmeme po sloupcích, nebo po řádcích, musí být stejného typu (znaky, čísla, booleovské hodnoty). Matice se snadno převede na data.frame funkcí as.data.frame(). Data.frame se snadno převede na matici funkcí as.matrix(), ale číhá tam ta zrada, že se všechny elementy sjednotí do stejného typu, takže např. jediný znakový sloupec způsobí, že se všechna čísla v číselných sloupcích vašeho data.frame změní ve znaky a nepůjde na nich provádět žádné výpočty.

Z DataCampu ukradneme vzorovou matici:

Napřed dva vektory, které dávají vymyšlenou statistiku návštěvnosti nějakého profilu na dvou sociálních sítích po dobu jednoho týdne

linkedin <- c(16, 9, 13, 5, 2, 17, 14)
facebook <- c(17, 7, 5, 16, 8, 13, 14)

Vytvoření matice pomocí funkce matrix a co všechno se o ní dá zjistit analytickými funkcemi

views <- matrix(c(linkedin, facebook), nrow = 2, byrow = TRUE)
views
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## [1,]   16    9   13    5    2   17   14
## [2,]   17    7    5   16    8   13   14
class(views)
## [1] "matrix"
str(views)
##  num [1:2, 1:7] 16 17 9 7 13 5 5 16 2 8 ...
dim(views)
## [1] 2 7
length(views)
## [1] 14
nrow(views)
## [1] 2
ncol(views)
## [1] 7

U str() je vidět, že je to vlastně numerický vektor se dvěma rozměry. dim() udá číslo pro řádky, resp. sloupce. length udá počet všech elementů (políček v tabulce). První rozměr jsou vždy řádky, druhý rozměr vždy sloupec. Když má taková věc rozměrů ještě víc, říká se tomu array - pole, zásobník… ale stejně se to vždycky prohlíží dvojrozměrně jako tolik párů matic, kolik to dá dvojrozměrných kombinací. Teď na array nemyslet.

Můžeme si pojmenovat řádky a sloupce:

dimnames(views) <- list( c("linkedin", "facebook"), c("Mo", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"))
str(views)
##  num [1:2, 1:7] 16 17 9 7 13 5 5 16 2 8 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:2] "linkedin" "facebook"
##   ..$ : chr [1:7] "Mo" "Tue" "Wed" "Thu" ...

Argumenty funkce matrix: nrow/ncol, byrow, dimnames

views_vertical <- matrix(c(linkedin, facebook), nrow = 7, byrow = TRUE, dimnames = list(c("Mo", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"), c("linkedin", "facebook")))
views_vertical
##     linkedin facebook
## Mo        16        9
## Tue       13        5
## Wed        2       17
## Thu       14       17
## Fri        7        5
## Sat       16        8
## Sun       13       14

Defaultní nastavení byrow je FALSE, tj. matice se bude plnit shora dolů po sloupcích.

Transpozice řádků a sloupců

Řádky a sloupce můžeme transponovat, tj. přehodit orientaci tabulky - co byly řádky, jsou teď sloupce, a naopak.

views_horizontal <- t(views_vertical)
views_horizontal
##          Mo Tue Wed Thu Fri Sat Sun
## linkedin 16  13   2  14   7  16  13
## facebook  9   5  17  17   5   8  14

Vytvoření matice ze samostatných vektorů

Matici ze dvou stejně dlouhých vektorů vyrobíme i vzájemným připojením buď po řádcích, nebo po sloupcích.

Spojení dvou vektorů do matice po řádcích:

spojeni_po_radcich_matice <- rbind(linkedin, facebook)
spojeni_po_radcich_matice
##          [,1] [,2] [,3] [,4] [,5] [,6] [,7]
## linkedin   16    9   13    5    2   17   14
## facebook   17    7    5   16    8   13   14
str(spojeni_po_radcich_matice)
##  num [1:2, 1:7] 16 17 9 7 13 5 5 16 2 8 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:2] "linkedin" "facebook"
##   ..$ : NULL

Spojení dvou vektorů do matice po sloupcích:

spojeni_po_sloupcich_matice <- cbind(linkedin, facebook)
spojeni_po_sloupcich_matice
##      linkedin facebook
## [1,]       16       17
## [2,]        9        7
## [3,]       13        5
## [4,]        5       16
## [5,]        2        8
## [6,]       17       13
## [7,]       14       14
str(spojeni_po_sloupcich_matice)
##  num [1:7, 1:2] 16 9 13 5 2 17 14 17 7 5 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : NULL
##   ..$ : chr [1:2] "linkedin" "facebook"

Pojmenování dimenzí v matici

Řádky a/nebo sloupce můžeme pojmenovat dodatečně, podle toho, co zůstalo nepojmenované. U matic se jména dimenzí skladují v seznamu, jehož prvním elementem jsou vždy jména řádků a druhým elementem vždy jména sloupců. Když pojmenování pro jednu z dimenzí chybí, na jejím místě je NULL. To NULL můžeme nahradit vektorem se jmény elementů, který musí být samozřejmě stejně dlouhý jako dimenze, kterou pojmenováváme.

dimnames(spojeni_po_sloupcich_matice)[[1]] <- c("Mo", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
spojeni_po_sloupcich_matice
##     linkedin facebook
## Mo        16       17
## Tue        9        7
## Wed       13        5
## Thu        5       16
## Fri        2        8
## Sat       17       13
## Sun       14       14

Na matici a názvy jejích dimenzí funguje i rownames() a colnames().

rownames(spojeni_po_sloupcich_matice) <- c("PO", "ÚT", "ST", "ČT", "PÁ", "SO", "NE")
colnames(spojeni_po_sloupcich_matice) <- c("návštěvy LinkedInu", "návštěvy Facebooku")
spojeni_po_sloupcich_matice
##    návštěvy LinkedInu návštěvy Facebooku
## PO                 16                 17
## ÚT                  9                  7
## ST                 13                  5
## ČT                  5                 16
## PÁ                  2                  8
## SO                 17                 13
## NE                 14                 14

Editování hodnot v matici

Úplně stejné jako u vektorů: “vyber” a “nahraď”:

views[1,1] <- 1000
views
##            Mo Tue Wed Thu Fri Sat Sun
## linkedin 1000   9  13   5   2  17  14
## facebook   17   7   5  16   8  13  14
views[1:2, 3:4] <- c(6666, 7777, 8888, 9999)
views
##            Mo Tue  Wed  Thu Fri Sat Sun
## linkedin 1000   9 6666 8888   2  17  14
## facebook   17   7 7777 9999   8  13  14

Ale pozor, ať matice vznikla jakkoli, po řádcích, nebo po sloupcích, hledání a nahrazování defaultně probíhá po sloupcích. Viz předchozí kód. Stejně se budou počítat pozice, když dostaneme odpověď na otázku pomocí funkce which():

which(views > 14) 
## [1]  1  2  5  6  7  8 11
views
##            Mo Tue  Wed  Thu Fri Sat Sun
## linkedin 1000   9 6666 8888   2  17  14
## facebook   17   7 7777 9999   8  13  14

Logické operátory na maticích

tohle je z DataCamp

# When does views equal 13?
views == 13
##             Mo   Tue   Wed   Thu   Fri   Sat   Sun
## linkedin FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## facebook FALSE FALSE FALSE FALSE FALSE  TRUE FALSE
# When is views less than or equal to 14?
views <= 14
##             Mo  Tue   Wed   Thu  Fri   Sat  Sun
## linkedin FALSE TRUE FALSE FALSE TRUE FALSE TRUE
## facebook FALSE TRUE FALSE FALSE TRUE  TRUE TRUE
# How often does facebook equal or exceed linkedin times two?
sum(facebook >= 2 * linkedin)
## [1] 2

Using the relational operators you’ve learned so far, try to discover the following:

When were the views exactly equal to 13? Use the views matrix to return a logical matrix.
For which days was the number of views less than or equal to 14? Again, have R return a logical matrix.

Početní operace na maticích

Podobně jako na vektorech, probíhá recycling kratšího z útvarů. Když je kratším útvarem jedno číslo, provede se s ním daná operace na každém elementu matice:

spojeni_po_sloupcich_matice
##    návštěvy LinkedInu návštěvy Facebooku
## PO                 16                 17
## ÚT                  9                  7
## ST                 13                  5
## ČT                  5                 16
## PÁ                  2                  8
## SO                 17                 13
## NE                 14                 14
spojeni_po_sloupcich_matice * 2
##    návštěvy LinkedInu návštěvy Facebooku
## PO                 32                 34
## ÚT                 18                 14
## ST                 26                 10
## ČT                 10                 32
## PÁ                  4                 16
## SO                 34                 26
## NE                 28                 28
spojeni_po_sloupcich_matice - 10
##    návštěvy LinkedInu návštěvy Facebooku
## PO                  6                  7
## ÚT                 -1                 -3
## ST                  3                 -5
## ČT                 -5                  6
## PÁ                 -8                 -2
## SO                  7                  3
## NE                  4                  4

Jinak musí souhlasit počet dimenzí:

a <- matrix(c(1, 10, 1, 10), ncol = 2, byrow = FALSE)
a
##      [,1] [,2]
## [1,]    1    1
## [2,]   10   10
b <- matrix(c(3,5,3,5,7,7), ncol = 2, byrow = FALSE)
b
##      [,1] [,2]
## [1,]    3    5
## [2,]    5    7
## [3,]    3    7
#a + b

To nepůjde. Ale můžeme ke každému řádku přičíst jiné číslo:

a
##      [,1] [,2]
## [1,]    1    1
## [2,]   10   10
d <- c(6, 8)
a + d
##      [,1] [,2]
## [1,]    7    7
## [2,]   18   18

Výpočty na maticích je před vážným použitím potřeba procvičit metodou pokus-omyl. Patrně je ani nebudeme potřebovat. Jeden výpočet ale určitě užijeme často:

a
##      [,1] [,2]
## [1,]    1    1
## [2,]   10   10
rowSums(a)
## [1]  2 20
colSums(a)
## [1] 11 11
rowMeans(a)
## [1]  1 10
colMeans(a)
## [1] 5.5 5.5

Matice se dají taky násobit, a to jde dvěma způsoby vedoucími k dvěma různým výsledkům - po elementech a “opravdicky matematicky”. Po elementech je to matice * matice a “opravdicky matematicky” je to matice %*% matice.