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)
matrix a co všechno se o ní dá zjistit analytickými funkcemiviews <- 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" ...
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.
Řá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
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"
Řá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
Ú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
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.
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.