Macierze
Tworzenie macierzy
Macierze to dwuwymiarowe tablice złożone z danych tego samego typu. Można je utworzyć z każdego ciągu złożonego z n×k elementów za pomocą instrukcji matrix(ciag,nrow=n,ncol=k) zaznaczając w ten sposób, że macierz ma mieć n wierszy i k kolumn. Dane są dzielone wzdłuż kolumn od góry w dół, a kolumny układane od lewej do prawej.
> ciag=rep(1:4,3) > matrix(ciag, ncol=4, nrow=3) [,1] [,2] [,3] [,4] [1,] 1 4 3 2 [2,] 2 1 4 3 [3,] 3 2 1 4 > matrix(ciag, nrow=4, ncol=3) [,1] [,2] [,3] [1,] 1 1 1 [2,] 2 2 2 [3,] 3 3 3 [4,] 4 4 4 > matrix(ciag,6,4) [,1] [,2] [,3] [,4] [1,] 1 3 1 3 [2,] 2 4 2 4 [3,] 3 1 3 1 [4,] 4 2 4 2 [5,] 1 3 1 3 [6,] 2 4 2 4 > matrix(ciag,5,3) [,1] [,2] [,3] [1,] 1 2 3 [2,] 2 3 4 [3,] 3 4 1 [4,] 4 1 2 [5,] 1 2 3 Warning message: In matrix(ciag, 5, 3) : data length [12] is not a sub-multiple or multiple of the number of rows [5] |
Kolejne elementy wektora wypełniają kolumny od góry do dołu i proces wypełniania przechodzi na następna kolumnę. Gdy liczba elementów ciągu jest mniejsza niż komórek w macierzy po dojściu do końca wektora kolejne komórki wypełnią się elementami wektora począwszy od pierwszego elementu. Wszystko jest dobrze, gdy liczba komórek w macierzy jest wielokrotnością liczby elementów w wektorze. Gdy nie jest spełniony ten warunek R generuje komunikat ostrzegawczy, ale macierz tworzy. Można ją zapamiętać pod wybraną nazwą i posługiwać się nią, jako obiektem typu macierz.
Nazwy opcji nrow, ncol mogą być pominięte. Wtedy pierwszą z liczb traktuje się domyślnie jako nrow, a druga jako ncol. Można też skrócić definicje macierzy do formuły matrix(ciąg, ncol=n) lub matrix(ciag,nrow=k).
Czasami wygodnie jest wypełniać macierz elementami wektora rzędami, nie kolumnami. Należy wtedy dopisać opcję byrow=TRUE (byrow=T lub byrow=1) w funkcji matrix().
> ciag=1:10 > matrix(ciag,2,5) [,1] [,2] [,3] [,4] [,5] [1,] 1 3 5 7 9 [2,] 2 4 6 8 10 > matrix(ciag,2,5,byrow=TRUE) [,1] [,2] [,3] [,4] [,5] [1,] 1 2 3 4 5 [2,] 6 7 8 9 10 |
Macierze można tworzyć przez sklejanie wektorów o jednakowej liczbie elementów za pomocą funkcji cbind() (wtedy składowe wektory są kolumnami) lub rbind() (wtedy sklejane wektory są wierszami). Kiedy wektory nie są równej długości, obowiązuje zasada równania do dłuższego wektora poprzez cykliczne powtarzanie wyrazów z krótszego wektora.
> cbind(1:6, rep(3,6), c(2,4,5,3,8,2)) [,1] [,2] [,3] [1,] 1 3 2 [2,] 2 3 4 [3,] 3 3 5 [4,] 4 3 3 [5,] 5 3 8 [6,] 6 3 2 > rbind(1:6, rep(3,6), c(2,4,5,3,8,2)) [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1 2 3 4 5 6 [2,] 3 3 3 3 3 3 [3,] 2 4 5 3 8 2 > rbind(1:6, 1:2) [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1 2 3 4 5 6 [2,] 1 2 1 2 1 2 |
Funkcja outer() pozwala na tworzenie macierzy wypełnianych liczbami zgodnie z wartościami wybranej funkcji, w domyśle jest to funkcja f(x,y)=x*y.
> outer(1:3,1:5) [,1] [,2] [,3] [,4] [,5] [1,] 1 2 3 4 5 [2,] 6 7 8 9 10 [3,] 11 12 13 14 15 > outer(rep(7,3),c(3,1,2)) [,1] [,2] [,3] [1,] 21 7 14 [2,] 21 7 14 [3,] 21 7 14 |
Działanie w funkcji outer() można zmienić dopisując opcje “+”, “/” itd albo zdefiniować własną funkcję wg schematu:
f(x,y) wyrażenie matematyczne
> outer(1:3,1:5,"+") [,1] [,2] [,3] [,4] [,5] [1,] 2 3 4 5 6 [2,] 3 4 5 6 7 [3,] 4 5 6 7 8 > outer(1:3,1:5, function(x,y) log(x^2+y^2)) [,1] [,2] [,3] [,4] [,5] [1,] 0.6931472 1.609438 2.302585 2.833213 3.258097 [2,] 1.6094379 2.079442 2.564949 2.995732 3.367296 [3,] 2.3025851 2.564949 2.890372 3.218876 3.526361 |
Nazywanie wierszy i kolumn macierzy
Przydatną opcją przy tworzeniu macierzy może okazać się “dimnames”. Pozwala ona na nazwanie wierszy i kolumn macierzy odpowiednimi nazwami. Jej wartością jest lista ciągów nazw. Nazwy te nie stają się obiektami R.
> ciag=1:10 > matrix(ciag,2,5,dimnames=list(c("rząd1", "rząd2"), + c("kol1", "kol2", "kol3", "kol4", "kol5" ))) kol1 kol2 kol3 kol4 kol5 rząd1 1 3 5 7 9 rząd2 2 4 6 8 10 |
Mając nazwane wiersze i kolumny można odwoływać się do wartości macierzy używając składni:
> macierz=matrix(`1:10,2,5,dimnames=list(c("rząd1", "rząd2"), + c("kol1", "kol2", "kol3", "kol4", "kol5" ))) > macierz["rząd2","kol3"] [1] 6 > macierz=matrix(`1:10,2,5,dimnames=list(c("rząd1", "rząd2"), + c("kol3", "kol2", "kol3", "kol2", "kol3" ))) > macierz["rząd2","kol3"] [1] 2 |
Nazwy kolumn albo wierszy mogą się powtarzać, ale odwołując się poprzez nazwy do wartości macierzy uzyskujemy tylko pierwszą z możliwych wartości.
Jednocześnie obok opcji dimnames istnieje funkcja dimnames(). Jej argumentem jest macierz z nazwanymi wierszami i kolumnami, a wartością – lista nazw wierszy i kolumn macierzy.
> ciag=1:10 > macierz=matrix(ciag,2,5,dimnames=list(c("rząd1", "rząd2"), + c("kol1", "kol2", "kol3", "kol4", "kol5" ))) > dimnames(macierz) [[1]] [1] "rząd1" "rząd2" [[2]] [1] "kol1" "kol2" "kol3" "kol4" "kol5" |
Mając macierz z nazwanymi wierszami i kolumnami można sprawdzić, który wiersz albo kolumna mają daną nazwę:
> ciag=1:10 > macierz=matrix(ciag,2,5,dimnames=list(c("rząd1", "rząd2"), + c("kol1", "kol2", "kol3", "kol4", "kol5" ))) > #badamy nazwy wierszy kolumny liczby znajdującej się w drugim wierszu i trzeciej kolumnie. > dimnames(macierz)[[1]][2] [1] "rząd2" > dimnames(macierz)[[2]][3] [1] "kol3" |
Macierze zaimplementowane do R
Prostą macierzą jest USPersonalExpenditure zawierającą wykaz wydatków (w milionach dolarów) na wyroby zaliczane do 5 różnych kategorii ponoszonych przez Amerykanów w latach 1940, 1945, 1950, 1955 i 1960.
> USPersonalExpenditure 1940 1945 1950 1955 1960 Food and Tobacco 22.200 44.500 59.60 73.2 86.80 Household Operation 10.500 15.500 29.00 36.5 46.20 Medical and Health 3.530 5.760 9.71 14.0 21.10 Personal Care 1.040 1.980 2.45 3.4 5.40 Private Education 0.341 0.974 1.80 2.6 3.64 |
Macierz WorldPhones pokazuje natomiast liczbę telefonów w różnych częściach świata w latach 1951-1961.
> WorldPhones N.Amer Europe Asia S.Amer Oceania Africa Mid.Amer 1951 45939 21574 2876 1815 1646 89 555 1956 60423 29990 4708 2568 2366 1411 733 1957 64721 32510 5230 2695 2526 1546 773 1958 68484 35218 6662 2845 2691 1663 836 1959 71799 37598 6856 3000 2868 1769 911 1960 76036 40341 8220 3145 3054 1905 1008 1961 79831 43173 9053 3338 3224 2005 1076 |
Inną macierzą jest euro.cross pokazujące przelicznik 11 walut europejskich w końcu grudnia 1998 roku. W krajach tych obowiązywały różne waluty poprzedzające wprowadzenie Euro, których oficjalne skróty są nazwami kolumn i wierszy.
> euro.cross ATS BEF DEM ESP FIM FRF ATS 1.000000000 2.93161486 0.142135709 12.0917422 0.432093050 0.476702543 BEF 0.341108927 1.00000000 0.048483759 4.1246012 0.147390797 0.162607493 DEM 7.035529673 20.62546336 1.000000000 85.0718109 3.040003477 3.353854885 ESP 0.082701069 0.24244768 0.011754775 1.0000000 0.035734557 0.039423810 FIM 2.314316324 6.78468413 0.328946992 27.9841163 1.000000000 1.103240477 FRF 2.097744212 6.14977811 0.298164361 25.3653822 0.906420695 1.000000000 IEP 17.471976881 51.22110711 2.483391826 211.2666399 7.549519785 8.328935807 ITL 0.007106602 0.02083382 0.001010102 0.0859312 0.003070713 0.003387735 LUF 0.341108927 1.00000000 0.048483759 4.1246012 0.147390797 0.162607493 NLG 6.244151907 18.30544854 0.887516960 75.5026750 2.698054644 2.976603092 PTE 0.068636087 0.20121457 0.009755639 0.8299299 0.029657176 0.032718997 IEP ITL LUF NLG PTE ATS 0.0572345080 140.714229 2.93161486 0.160149851 14.5695951 BEF 0.0195232016 47.998880 1.00000000 0.054628544 4.9698190 DEM 0.4026750791 989.999131 20.62546336 1.126739032 102.5048189 ESP 0.0047333550 11.637217 0.24244768 0.013244564 1.2049211 FIM 0.1324587561 325.657236 6.78468413 0.370637415 33.7186519 FRF 0.1200633578 295.182459 6.14977811 0.335953424 30.5632839 |
Inną macirzą (bardzo dużą) zaimplementowaną do R jest volcano. Pokazuje ona wysokość względną wzniesienia terenu wokół wulkanu Maungawhau na Nowej Zelandii dla współrzednych wyznaczanych co 10 m. Macierz ta używana jest do testowania w R funkcji graficznych stosowanych w kartografii.
Odwoływanie się do poszczególnych elementów macierzy
Do poszczególnych komórek macierzy odwołujemy się zgodnie ze schematem: macierz[i,j] gdzie i jest numerem wiersza a j numerem kolumny. Odwołanie macierz[,j] oznacza ciąg złożony z wyrazów j-tej kolumny, a macierz[i,] oznacza ciąg złożony z i-tego wiersza. Aby ciągi macierz[i,] i macierz[,j] traktowane były jako macierze z jednym wierszem lub jedną kolumną konieczna jest opcja drop=FALSE.
> ciag=c(2.1, 3.4, 5.6, 2.8, 3.1, 6.0, 2.9, 3.5, 5.1, 2.1, 3.8, 5.4) > macierz=matrix(ciag,3,4) > macierz [,1] [,2] [,3] [,4] [1,] 2.1 2.8 2.9 2.1 [2,] 3.4 3.1 3.5 3.8 [3,] 5.6 6.0 5.1 5.4 > macierz[2,2] [1] 3.1 > macierz[2,] [1] 3.4 3.1 3.5 3.8 > macierz[2,,drop=FALSE] [,1] [,2] [,3] [,4] [1,] 3.4 3.1 3.5 3.8 |
Odwoływać się można do kilku elementów na raz poprzez tworzenie ciągów w zbiorze indeksów. Ważne by te indeksy nie wyszły poza zakres macierzy.
> mat=matrix(1:12,3,4) > mat [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 > mat[1:2,c(2,4)] [,1] [,2] [1,] 4 10 [2,] 5 11 > mat[,2:4] [,1] [,2] [,3] [1,] 4 7 10 [2,] 5 8 11 [3,] 6 9 12 > mat[c(1,3),] [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 3 6 9 12 > mat[,4:6] Błąd w poleceniu 'mat[, 4:6]':indeks jest poza granicami |
Gdy wiersze lub/i kolumny macierzy zostały nazwane można (ale nie obowiązkowo) odwoływać się poprzez te nazwy do poszczególnych elementów macierzy.
> mac=matrix(letters[1:12],4,3,dimnames=list(c("A","AA","AAA","AAAA"),c("B","BB","BBB"))) > mac B BB BBB A "a" "e" "i" AA "b" "f" "j" AAA "c" "g" "k" AAAA "d" "h" "l" > mac["AA","BBB"] [1] "j" > mac["AA",] B BB BBB "b" "f" "j" > mac[,"BBB"] B BB BBB "b" "f" "j" > mac["C",] Błąd w poleceniu 'mac["C", ]':indeks jest poza granicami |
Odwołanie się do samych nazw wierszy i kolumn umożliwia funkcja dimnames().
> mac=matrix(1:12,4,3,dimnames=list(letters[1:4],LETTERS[1:3])) > mac A B C a 1 5 9 b 2 6 10 c 3 7 11 d 4 8 12 > dimnames(mac) [[1]] [1] "a" "b" "c" # [[2]] [1] "A" "B" "C" "D" # |
Edycja i modyfikowanie macierzy
Zamienienie wartości jednego z elementów macierzy odbywa się poprzez podstawienie macierz[i,j]=x. Można zamieniać całe kolumny lub wiersze na inne wektory.
> macierz=matrix(1:9,3,3) > macierz [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > macierz[1,]=c(7,6,5) > macierz [,1] [,2] [,3] [1,] 7 6 5 [2,] 2 5 8 [3,] 3 6 9 > macierz[,1]=c(7,6,5) > macierz [,1] [,2] [,3] [1,] 7 6 5 [2,] 6 5 8 [3,] 5 6 9 |
Poprzez operacje na indeksach wyrazów można przestawiać wiersze i wyrazy macierzy.
> macierz=matrix(1:9,3,3) > macierz [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > macierz1=macierz[3:1,] > macierz1 [,1] [,2] [,3] [1,] 3 6 9 [2,] 2 5 8 [3,] 1 4 7 > macierz2=macierz[,3:1] > macierz2 [,1] [,2] [,3] [1,] 7 4 1 [2,] 8 5 2 [3,] 9 6 3 |
Usunięcie wybranych wierszy lub kolumn można zrealizować poprzez wymienienie wierszy/kolumn, które mają pozostać albo wierszy lub kolumn, które mają być usunięte.
> macierz=matrix(1:9,3,3) > macierz [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > macierz1=macierz[c(1,3),] > macierz1 [,1] [,2] [,3] [1,] 1 4 7 [2,] 3 6 9 > macierz2=macierz[-2,] > macierz2 [,1] [,2] [,3] [1,] 1 4 7 [2,] 3 6 9 > macierz3=macierz[,c(1,3)] > macierz3 [,1] [,2] [1,] 4 7 [2,] 5 8 [3,] 6 9 > macierz4=macierz[,-2] > macierz4 [,1] [,2] [1,] 4 7 [2,] 5 8 [3,] 6 9 |
Dodanie kolumn do macierzy lub poziome łączenie kilku macierzy w jedną macierz można zrealizować funkcją cbind().
> mat1=matrix(1:6,2,3) > mat1 [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > mat2=matrix(c(7,8),2,3) > mat2 [,1] [,2] [,3] [1,] 7 7 7 [2,] 8 8 8 > cbind(mat1,c(7,8,9)) > cbind(mat1,c(7,8,9)) [,1] [,2] [,3] [,4] [1,] 1 3 5 7 [2,] 2 4 6 8 Komunikat ostrzegawczy: W poleceniu 'cbind(mat1, c(7, 8, 9, 10))': number of rows of result is not a multiple of vector length (arg 2) > cbind(c(7,8,9,10),mat1) [,1] [,2] [,3] [,4] [1,] 7 1 3 5 [2,] 8 2 4 6 Komunikat ostrzegawczy: W poleceniu 'cbind(mat1, c(7, 8, 9, 10))': number of rows of result is not a multiple of vector length (arg 2) > cbind(mat1,mat2) [,1] [,2] [,3] [,4] [,5] [,6] [1,] 1 3 5 7 7 7 [2,] 2 4 6 8 8 8 > mat2=matrix(c(7,8,9),3,3) > mat2 [,1] [,2] [,3] [1,] 7 7 7 [2,] 8 8 8 [3,] 9 9 9 > cbind(mat1,mat2) Błąd w poleceniu 'cbind(mat1, mat2)': liczby wierszy macierzy muszą być zgodne (zobacz argument 2) |
Przy dołączaniu kolumny w postaci wektora liczba wierszy ustala się poprzez liczbę wierszy w macierzy i liczba elementów wektora jest obcięta albo zaczyna się sukcesywnie powtarzać. Natomiast łączenie poziome macierzy o różnej liczbie wierszy nie jest możliwe.
Dodanie wiersza do macierzy albo pionowe połączenie dwóch macierzy można zrealizować funkcją rbind().
> mat1=matrix(1:6,2,3) > mat1 [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > mat2=matrix(c(7,8),2,3) > mat2 [,1] [,2] [,3] [1,] 7 7 7 [2,] 8 8 8 > rbind(mat1,c(7,8)) > mat2 [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 [3,] 7 8 7 Komunikat ostrzegawczy: W poleceniu 'rbind(mat1, c(7, 8))': number of rows of result is not a multiple of vector length (arg 2) > rbind(mat1,mat2) [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 [1,] 7 7 7 [2,] 8 8 8 |
Dołączanie wiersza do macierzy za pomocą funkcji rbind() o innej liczbie elementów niż liczba kolumn w macierzy powoduje dopasowanie liczby jego elementów do liczby kolumn macierzy: ich wielokrotne powtarzanie lub obcięcie. Połączenie dwóch macierzy o nierównej liczbie kolumn nie jest możliwe.
Modyfikowanie nazw wierszy i kolumn można zrealizować za pomocą funkcji dimnames(). Należy nowe wartości wprowadzić w postaci listy, albo modyfikować poszczególne elementy listy dimnames(macierz). Ponadto polecenie dimnames(macierz)=NULL usuwa wszystkie nazwy kolumn i wierszy.
> mat=matrix(1:9,3,3,dimnames=list(1:3,1:3)) > mat 1 2 3 1 1 4 7 2 2 5 8 3 3 6 9 > dimnames(mat)[[1]]=c("L1","L2","L3") > mat 1 2 3 L1 1 4 7 L2 2 5 8 L3 3 6 9 > dimnames(mat)[[2]]=c("C1","C2","C3") > mat C1 C2 C3 L1 1 4 7 L2 2 5 8 L3 3 6 9 > dimnames(mat)=NULL > mat [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > dimnames(mat)=list(c("W1","W2","W3"),c("K1","K2","K3")) > mat K1 K2 K3 W1 1 4 7 W2 2 5 8 W3 3 6 9 |
Funkcje i działania na macierzach
Funkcje mode() i typeof() pokazują typ elementów macierzy, funkcja class() pokazuje typ obiektu (dla macierzy daje odpowiedź “matrix”), a funkcja str() pokazuje strukturę macierzy.
> mac1=matrix(1:12,3,4) > mac1 [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 > mode(mac1) [1] "numeric" > typeof(mac1) [1] "integer" > class(mac1) [1] "matrix" > str(mac1) int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ... > mac2=matrix(letters[1:12],3,4,dimnames=list(1:3,1:4)) > mac2 1 2 3 4 1 "a" "d" "g" "j" 2 "b" "e" "h" "k" 3 "c" "f" "i" "l" > mode(mac2) [1] "character" > typeof(mac1) [1] "character" > class(mac2) [1] "matrix" > str(mac1) chr [1:3, 1:4] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" - attr(*, "dimnames")=List of 2 ..$ : chr [1:3] "1" "2" "3" ..$ : chr [1:4] "1" "2" "3" "4" |
Podstawowe funkcje związane z macierzami pokazują ich budowę i strukturę. Są to:
- dim(macierz) – wymiary macierzy – funkcja dwukrotna (liczba wierszy, liczba kolumn).
- ncol(macierz) – liczba kolumn macierzy.
- nrow(macierz) – liczba wierszy w macierzy.
- length(macierz) – liczba elementów w macierzy.
- dimnames(macierz) – nazwy wierszy i kolumn macierzy w postaci listy)
> mat=matrix(1:10,ncol=2,dimnames=list(letters[1:5],c("K1","K2"))) > dim(mat) [1] 5 2 > ncol(mat) [1] 2 > nrow(mat) [1] 5 > length(mat) [1] 10 > dimnames(mat) [[1]] [1] "a" "b" "c" "d" "e" [[2]] [1] "K1" "K2" > mode(mat) [1] "numeric" > str(mat) int [1:5, 1:2] 1 2 3 4 5 ... - attr(*, "dimnames")=List of 2 ..$ : chr [1:5] "a" "b" "c" "d" ... ..$ : chr [1:2] "K1" "K2" |
Dla macierzy możliwe jest wyświetlanie głównej przekatnej (od górnego lewego rogu w dół po skosie) dzięki funkcji diag(),. Najczęściej operacja ta stosowana jest dla macierzy kwadratowych.
> mac1=matrix(1:12,3,4) > mac1 [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 > diag(mac1) [1] 1 5 9 > mac2=matrix(1:12,4,3) > mac2 [,1] [,2] [,3] [1,] 1 5 9 [2,] 2 6 10 [3,] 3 7 11 [4,] 4 8 12 > diag(mac2) [1] 1 6 11 > mac3=matrix(1:16,4,4) > mac3 [,1] [,2] [,3] [,4] [1,] 1 5 9 13 [2,] 2 6 10 14 [3,] 3 7 11 15 [4,] 4 8 12 16 > diag(mac3) [1] 1 6 11 16 |
W przypadku macierzy o wielu wierszach ich wyświetlenie w całości w konsoli R nie jest możliwe i niepotrzebne. Czasem jednak potrzebne jest zobaczenie kilku wierszy początkowych, co umożliwia funkcja head(macierz) lub końcowych realizowane za pomocą funkcji tail(macierz).
> mat=matrix(1:100,ncol=2,dimnames=list(c(letters,letters)[1:50],c("K1","K2"))) > head(mat) K1 K2 a 1 51 b 2 52 c 3 53 d 4 54 e 5 55 f 6 56 > tail(mat) K1 K2 s 45 95 t 46 96 u 47 97 v 48 98 w 49 99 x 50 100 |
Aby operować elementami macierzy jako wektorem można użyć funkcji as.vector(). Funkcja as.matrix() nie jest do niej odwrotna. Zamienia ona wektor na macierz jednokolumnową.
> macierz=matrix(letters[1:6],3,2,dimnames=list(1:3,1:2)) > macierz 1 2 1 "a" "d" 2 "b" "e" 3 "c" "f" > as.vector(macierz) [1] "a" "b" "c" "d" "e" "f" > as.matrix(as.vector(macierz)) [,1] [1,] "a" [2,] "b" [3,] "c" [4,] "d" [5,] "e" [6,] "f" > macierz=matrix(letters[1:6],3,2,dimnames=list(1:3,1:2),byrow=TRUE) > macierz 1 2 1 "a" "b" 2 "c" "d" 3 "e" "f" > as.vector(macierz) [1] "a" "c" "e" "b" "d" "f" |
Funkcja as.vector() zastosowana do wielokolumnowych macierzy zawsze tworzy wektor łącząc kolumny ze sobą od pierwszej do ostatniej.
W przypadku macierzy o wartościach liczbowych wiele działań jest dla nich tak samo określonych jak na wektorach. Przykładowo zapis macierz+x, macierz*x, macierz^x oznacza, że dla każdego elementu macierzy dodano x, każdy element pomnożono przez x lub każdy element podniesiono do potęgi x. Analogicznie do działań między wektorami przebiegają działania macierz+wektor, macierz*wektor, macierz^wektor itd.
> mat=matrix(1:6,2,3) > mat [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > mat+1 [,1] [,2] [,3] [1,] 2 4 6 [2,] 3 5 7 > mat+c(1,2) [,1] [,2] [,3] [1,] 2 4 6 [2,] 4 6 8 > mat+c(1,2,3) [,1] [,2] [,3] [1,] 2 6 7 [2,] 4 5 9 > mat+c(1,2,3,4) [,1] [,2] [,3] [1,] 2 6 6 [2,] 4 8 8 Komunikat ostrzegawczy: W poleceniu 'mat + c(1, 2, 3, 4)': długość dłuszego obiektu nie jest wielokrotnością długości krótszego obiektu |
W przypadku działań między macierzą a wektorem wykonywane są działania na poszczególnych elementach macierzy i wektora przy czym macierz zostaje zamieniona najpierw na ciąg (standardowo przez sklejenie kolumn jedna za drugą). Jeżeli wektor jest dłuższy od tego ciągu zostanie użyta do działań tylko jego część i pojawi się komunikat ostrzegawczy. Jeżeli wektor jest krótszy zostanie wielokrotnie powtórzony, tak by jego długość była równa liczbie elementów w macierzy. Jeżeli nie jest to możliwe (wielokrotność wektora jest dłuższa niż liczba elementów macierzy), działanie zostanie wykonane, ale pojawi się komunikat ostrzegawczy.
W podobny sposób wykonywane są działania między dwoma macierzami, ale muszą one mieć te same wymiary.
> mat1=matrix(1:6,2,3) > mat1 [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > mat2=matrix(6:1,2,3) > mat2 [,1] [,2] [,3] [1,] 6 4 2 [2,] 5 3 1 > mat1^mat2 [,1] [,2] [,3] [1,] 1 81 25 [2,] 32 64 6 > mat3=matrix(6:1,3,2) > mat3 [,1] [,2] [1,] 6 3 [2,] 5 2 [2,] 4 1 > mat1^mat3 Błąd w poleceniu 'mat1^mat3':niezgodne tablice |
Funkcje matematyczne działają na macierzach tak samo, jak na wektorach. Wykonywane są na każdym elemencie macierzy osobno.
> mat=matrix(1:6,2,3) > mat [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > log(mat) [,1] [,2] [,3] [1,] 0.0000000 1.098612 1.609438 [2,] 0.6931472 1.386294 1.791759 > sin(mat) [,1] [,2] [,3] [1,] 0.8414710 0.1411200 -0.9589243 [2,] 0.9092974 -0.7568025 -0.2794155 |
Większość funkcji statystycznych (min(), max(),sum(), mean(), sd() i inne) działa na macierzach tak, jak na ciągach utworzonych z wyrazów macierzy. Wyjątkiem jest funkcja var(), która tworzy macierz kowariancji dla wektorów utworzonych z poszczególnych kolumn macierzy. Poszczególne elementy tej macierzy wyliczane są ze wzoru:
gdzie jest L-tym elementem w i-tej kolumnie,
jest średnią z elementów i-tej kolumny. Analogicznie dla kolumny j-tej. Na przekątnej tej tabeli lokują się nieobciążone wariancje wyliczone dla kolejnych kolumn macierzy, natomiast pozostałe elementy to kowariancje.
> mat=matrix(1:6,2,3) > mat [,1] [,2] [,3] [1,] 1 3 5 [2,] 2 4 6 > max(mat) [1] 6 > mean(mat) [1] 3.5 > sd(mat) [1] 1.870829 > var(mat) [,1] [,2] [,3] [1,] 0.5 0.5 0.5 [2,] 0.5 0.5 0.5 [3,] 0.5 0.5 0.5 > mat1=matrix(1:6,3,2) > mat1 [,1] [,2] [1,] 1 4 [2,] 2 5 [2,] 3 6 > var(mat1) [,1] [,2] [1,] 1 1 [2,] 1 1 |
Dość częstą czynnością jest wyliczanie różnych podsumowań związanych z macierzami. Są to różne obliczenia wykonywane osobno na każdym wierszu lub kolumnie. Do wykonywania podobnych obliczeń służy funkcja apply(). Jej składnia wygląda następująco:
apply(nazwa macierzy, liczba 1 lub 2, funkcja)
Wpisanie 1 w drugiej pozycji powoduje, że funkcja wykonywana będzie na wierszach. Wpisanie 2 w tym miejscu oznacza wykonywanie funkcji w kolumnach.
> mat=matrix(1:9,3,3) > mat [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > apply(mat, 1, sum) [1] 12 15 18 > apply(mat, 2, sum) [1] 6 15 24 > apply(mat, 2, function(x) x-mean(x)) #Od wartości odejmij średnią z kolumny [,1] [,2] [,3] [1,] -1 -1 -1 [2,] 0 0 0 [3,] 1 1 1 > apply(mat, 1, function(x) x-mean(x)) #Od wartości odejmij średnią z wiersza [,1] [,2] [,3] [1,] -3 -3 -3 [2,] 0 0 0 [3,] 3 3 3 > # Działanie wykonane dobrze, tylko wyniki zapisane kolumnami, nie wierszami. |
Poniższy przykład pokazuje działanie funkcji sort(), która porządkuje osobno wiersze albo kolumny.
> mat=cbind(c(1,3,2,0), c(5,7,6,8), c(4,3,6,5)) > mat [,1] [,2] [,3] [1,] 1 5 4 [2,] 3 7 3 [3,] 2 6 6 [4,] 0 8 5 > apply(mat, 2, sort) [,1] [,2] [,3] [1,] 0 5 3 [2,] 1 6 4 [3,] 2 7 5 [4,] 3 8 6 > apply(mat, 1, sort) [,1] [,2] [,3] [,4] [1,] 1 3 2 0 [2,] 4 3 6 5 [3,] 5 7 6 8 |
Najczęściej jednak istnieją powody by zsumować wyrazy w wierszach macierzy lub/i w jej komumnach. Można to robić za pomocą funkcji apply() z funkcją wewnetrznąsum(), ale to samo zrobią funkcje rowSums(), colSums() oraz addmargins().
> mat=cbind(c(1,3,2,0), c(5,7,6,8), c(4,3,6,5)) > mat [,1] [,2] [,3] [1,] 1 5 4 [2,] 3 7 3 [3,] 2 6 6 [4,] 0 8 5 > rowSums(mat)) [1] 10 13 14 13 > colSums(mat) [1] 6 26 18 > addmargins(mat) Sum 1 5 4 10 3 7 3 13 2 6 6 14 0 8 5 13 Sum 6 26 18 50 |
Na koniec pokażemy, jak znajdywać wartości ekstremalne w macierzy i określić, na przecięciu którego wiersza i kolumny one znajdują się.
> ciag=c(4.1, 3.4, 2.6, 2.8, 5.1, 4.0, 5.9, 2.5, 5.1, 3.1, 1.8, 2.4, 5.9, 3.2, 4.3, 2.7) > macierz=matrix(ciag,4,4) > macierz [,1] [,2] [,3] [,4] [1,] 4.1 5.1 5.1 5.9 [2,] 3.4 4.0 3.1 3.2 [3,] 2.6 5.9 1.8 4.3 [4,] 2.8 2.5 2.4 2.7 > max(macierz) [1] 5.9 > which.max(macierz) [1] 7 > wiersz = which.max(macierz) - 1) %% nrow(macierz) + 1 > kolumna = (which.max(macierz) - 1) %/% nrow(macierz) + 1 > wiersz [1] 3 > kolumna [1] 2 > min(macierz) [1] 1.8 > which.min(macierz) [1] 11 > wiersz = (which.min(macierz) - 1) %% nrow(macierz) + 1 > kolumna = (which.min(macierz) - 1) %/% nrow(macierz) + 1 > wiersz [1] 3 > kolumna [1] 3 |
Funkcje which.max(), which.min() pokazują miejsce pierwszego ekstremum w ciągu liczb, w którym ustawione są kolumny macierzy jedna za drugą. Zamiana tego wyniku na numer kolumny i wiersza wymaga wykonania odpowiednich działań arytmetycznych. Działanie a %% b wylicza resztę z dzielenia a przez b. By zamiast 0 otrzymać liczbę równą liczbie wierszy macierzy, zastosowano wyliczanie reszty z dzielenia od liczby o 1 mniejszej i dodawanie 1 do wyniku. Działanie %/% pokazuje ile razy b mieści się w a. Aby uzyskać właściwy wynik, również zastosowano odejmowanie 1 od dzielnej i dodawanie 1 do wyniku.
Wyznaczenie liczby wartości ekstremalnych można uzyskać za pomocą następujących działań:
> ciag=c(4.1, 3.4, 2.6, 2.8, 5.1, 4.0, 5.9, 2.5, 5.1, 3.1, 1.8, 2.4, 5.9, 3.2, 4.3, 2.7) > macierz=matrix(ciag,4,4) > macierz [,1] [,2] [,3] [,4] [1,] 4.1 5.1 5.1 5.9 [2,] 3.4 4.0 3.1 3.2 [3,] 2.6 5.9 1.8 4.3 [4,] 2.8 2.5 2.4 2.7 > macierz[macierz==max(macierz)] [1] 5.9 5.9 > length(macierz[macierz==max(macierz)]) [1] 2 > macierz[macierz==min(macierz)] [1] 1.8 > length(macierz[macierz==min(macierz)]) [1] 1 |
Gdy ekstremów funkcji jest więcej niż jeden, aby poznać ich położenie należy użyć funkcji which(ciąg logiczny) zamiast funkcji which.min() albo which.max().
> ciag=c(4.1, 3.4, 2.6, 2.8, 5.1, 4.0, 5.9, 2.5, 5.1, 3.1, 1.8, 2.4, 5.9, 3.2, 4.3, 2.7) > macierz=matrix(ciag,4,4) > macierz [,1] [,2] [,3] [,4] [1,] 4.1 5.1 5.1 5.9 [2,] 3.4 4.0 3.1 3.2 [3,] 2.6 5.9 1.8 4.3 [4,] 2.8 2.5 2.4 2.7 > macierz==max(macierz) [1] [,1] [,2] [,3] [,4] [1,] FALSE FALSE FALSE TRUE [2,] FALSE FALSE FALSE FALSE [3,] FALSE TRUE FALSE FALSE [4,] FALSE FALSE FALSE FALSE > which(macierz==max(macierz)) [1] 7 13 > wiersze=(which(macierz==max(macierz)) - 1) %% nrow(macierz) + 1 > wiersze [1] 3 1 > kolumny=(which(macierz==max(macierz))-1) %/% nrow(macierz) + 1 > kolumny [1] 2 4 |
Rachunek macierzowy
Rachunek macierzowy tylko pozornie nie jest potrzebny biologom. Na 100 prac biologicznych jedna stosuje macierze do opisu sposobu opracowania danych, do zapisania formuł, jakimi autor posługuje się wyliczając np. strukturę wiekową banku nasion gromadzących się w glebie leśnej, kondycję komórek nowotworowych, których zewnętrzne warstwy niszczone są lekiem itp. Są istotne w modelowaniu ekologicznych, teorii sztucznych inteligencji, metodach numerycznych oraz w statystyce, choć tu gotowe procedury skrzętnie ukrywają stosowanie rachunku macierzowego. Pewne jego elementy powinien jednak biolog znać, zwłaszcza, że żmudne obliczenia wykonywać będzie R, a nie on. Dodatkowym bodźcem do uzyskania umiejętności posługiwania się rachunkiem macierzowym, jest coraz powszechniejsze pojawianie się w pracach biologicznych specjalnych wykresów zwanych biplotami, w których pokazuje się rozrzut danych wielowymiarowych w postaci punktów i poszczególnych zmiennych w postaci wektorów ze strzałkami. Ich zrozumienie i wykonanie wymaga poznania podanych niżej definicji.
Rachunek macierzowy dotyczy tylko macierzy, w której komórkach są liczby. Jeżeli macierz A ma L wierszy i K kolumn, macierz B ma K wierszy i N kolumn to możemy te macierze pomnożyć. Macierz C=A·B będzie mieć L wierszy i N kolumn. Elementem tej macierzy w i-tym wierszu i j-tej kolumnie jest liczba Ci,j równa:
gdzie Ai,k jest elementem macierzy A z i-tego wiersza i k-tej kolumny a Bk,j jest elementem macierzy B i k-tego wiersza i j-tej kolumny. Taki iloczyn nie musi być przemienny. W R iloczyn macierzy wykonuje się za pomocą funkcji crossprod() albo za pomocą operatora “%*%”.
> A=matrix(1:10,2,5) > A [,1] [,2] [,3] [,4] [,5] [1,] 1 3 5 7 9 [2,] 2 4 6 8 10 > B=matrix(1:15,5,3) > B [,1] [,2] [,3] [1,] 1 6 11 [2,] 2 7 12 [3,] 3 8 13 [4,] 4 9 14 [5,] 5 10 15 > A%*%B [,1] [,2] [,3] [1,] 95 220 345 [2,] 110 260 410 > B%*%A Error in B %*% A : non-conformable arguments |
Prostym działaniem wykonywanym na macierzy jest jej transpozycja. Polega ona na zamianie macierzy [Ai,j] na macierz [Aj,i], czyli takim zapisaniem elementów macierzy aby jej kolumny stały się wierszami a wiersze kolumnami. W R taką operacje można wykonać za pomocą funkcji t(). Operacja ta działa także na wektorach, przy czym okazuje się, że pojedynczy wektor po transpozycji jest traktowany tak, jak macierz o n wierszach i 1 kolumnie.
> A=matrix(1:15,5,3) > A [,1] [,2] [,3] [1,] 1 6 11 [2,] 2 7 12 [3,] 3 8 13 [4,] 4 9 14 [5,] 5 10 15 > t(A) [,1] [,2] [,3] [,4] [,5] [1,] 1 2 3 4 5 [2,] 6 7 8 9 10 [3,] 11 12 13 14 15 > B=c(1,5,2,4,3) > t(B) [,1] [,2] [,3] [,4] [,5] [1,] 1 5 2 4 3 |
Macierze o takiej samej liczbie wierszy i kolumn można mnożyć używając operatora “*”, co opisano w poprzednim podrozdziale. Wynikiem takiego mnożenia nie jest jednak iloczyn macierzy, ale macierz złożona z iloczynów odpowiadających sobie wyrazów.
Macierze kwadratowe w biologii pojawiają się wszędzie tam, gdy sytuacja wymaga wyliczania n pierwiastków układu n równań liniowych. Taki układ równań liniowych zapisuje się często w postaci Ax=B, gdzie A jest macierzą liczbową złożoną z n wierszy i n kolumn, x jest wektorem niewiadomych (x1,…,xn), B jest wektorem liczbowych (B1,…,Bn). Liczby w macierzy A i wektorze B są dane. Pierwiastki te istnieją i są jednoznacznie wyznaczone, gdy wyznacznik macierzy A jest różny od 0. W szkole wyliczany był wyznacznik macierzy o 2 wierszach i 2 kolumnach. Istnieje uogólnienie tego pojęcia dla macierzy kwadratowych o n wierszach i n kolumnach. W R wyliczamy go za pomocą funkcji det().
> A [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > det(A) [1] 0 > A[1,1]=-1 > A[3,3]=-3 > A [,1] [,2] [,3] [1,] -1 4 7 [2,] 2 5 8 [3,] 3 6 -3 > det(A) [1] 162 |
Dla macierzy, która ma wyznacznik różny od 0 istnieje macierz odwrotna. Macierz odwrotna do macierzy A (oznaczana A-1) spełnia warunek: A*A-1=I, gdzie I jest macierzą, która wszędzie ma same zera, a na przekątnej jedynki. Do wyznaczania macierzy odwrotnej służy funkcja solve().
> A [,1] [,2] [,3] [1,] -1 4 7 [2,] 2 5 8 [3,] 3 6 -3 > odwA=solve(A) > odwA [,1] [,2] [,3] [1,]-0.38888889 0.33333333 -0.01851852 [2,] 0.18518519 -0.11111111 0.13580247 [3,]-0.01851852 0.11111111 -0.08024691 > A%*%odwA [,1] [,2] [,3] [1,] 1.000000e+00 5.551115e-17 -2.775558e-17 [2,] 5.551115e-17 1.000000e+00 0.000000e+00 [3,] 3.816392e-17 5.551115e-17 1.000000e+00 > C=matrix(1:9,3,3) > det(C) [1] 0 > solve(C) Error in solve.default(C) : Lapack routine dgesv: system is exactly singular: U[3,3] = 0 |
Rozwiązanie układu równań postaci:
-1x1 + 4x2 + 7x3 = -7
2x1 + 5x2 + 8x3 = 6
3x1 + 6x2 – 3x3 = -9
wymaga następujących operacji:
> A=matrixei(1:9, 3, 3); A[1,1]=-1; A[3,3]=-3 > B=c(-7, 6, -9) > solve(A)%*%B [,1] [1,] 4.888889 [2,] -3.185185 [3,] 1.518519 > # albo: > solve(A,B) [1] 4.888889 -3.185185 1.518519 |
Pierwiastki pokazanego wcześniej układu równań są równe: x1 = 4.888889, x2 = -3.185185, x3 = 1.518519.
Wykonując pomiary liczbowe k zmiennych dla wielu obiektów operujemy macierzą złożona z k kolumn i dane można traktować jako elementy przestrzeni k-wymiarowej. Tworzą one macierz o k-kolumnach i przeważnie (ale nie zawsze) większej liczbie wierszy (np. n). Większość operacji związanych z rachunkiem macierzowym dotyczy właśnie operacji matematycznych na takich macierzach. Dotyczy to także zależności zarówno statystycznej jak i liniowej poszczególnych zmiennych od siebie, co sprowadza się do analizy zależności poszczególnych kolumn macierzy danych od siebie. Na początek omówiona zostanie liniowa zależność.
Wektor liczb x jest liniowo niezależny od wektorów y1, y2…,yk jeżeli nie istnieją takie liczby (a1,…,ak), że x=a1y1+a2y2+…+akyk. Za symbolami x, y1, y2…,yk kryją się pewne ciągi n-elementowe, zatem mówimy o ciągu n liczb liniowo niezależnym od wierszy macierzy y=[yi,j]i=1..k, j=1..n. Liniową zależność można przedstawić jako istnienie jednokolumnowej macierzy α, że x=y*α. Natomiast liniowa niezależność oznacza, że dla dowolnych macierzy jednokolumnowych α zachodzi x≠y*α. Zysk z zapisu macierzy i wektorów w postaci jednoliterowych symboli jest duży. Strata polega na tym, że wymiary macierzy i liczba elementów w wektorze nie są widoczne – należy je domyślnie kontrolować.
Liniowa niezależność jest związana ściśle z wymiarem przestrzeni, w której można umieścić dane. k liniowo niezależnych wektorów złożonych z n liczb może istnieć tylko wtedy gdy k≤n. Dla k liniowo niezależnych wektorów n-wymiarowych tworzących wiersze w macierzy A, ogół wektorów postaci A*α tworzy przestrzeń kartezjańską k-wymiarową. Jeżeli n>k to kolumny tej macierzy muszą być od siebie zależne, a dokładnie to istnieje k-kolumn liniowo niezależnych, a pozostałe n-k można wyliczyć jako ich liniową kombinację. Z każdą macierzą związany jest wymiar przestrzeni liniowej, w jakiej można umieścić n-elementowe kolumny tej macierzy. Nazywany jest on rzędem macierzy (ang. rank of matrix).
Wyliczanie rzędu dużych macierzy jest dość kłopotliwe. Po prostu nie zawsze widoczna jest liniowa zależność pewnych ciągów od pozostałych. Komputer stosuje do tego celu kilka algorytmów, ale jego obliczenia obarczone są błędem wynikającym z wykonywania obliczeń z pewną dokładnością. Tymczasem definicja rzędu nie uwzględnia zjawiska prawie liniowej zależności, to znaczy że x≈A*α z dokładnością do 0.00000000000001. Jeżeli przyjmiemy, że taka prawie liniowa zależność jest liniową zależnością bo uniemożliwia wykonywanie pewnych operacji macierzowych za pomocą komputera – to możemy programem R posługiwać się przy wyliczaniu rzędu macierzy.
Rząd macierzy wyliczamy za pomocą funkcji rankMatrix(), która znajduje się w bibliotece Matrix, na ogół ładowanej przy instalowaniu R. Należy ją jednak wywołać w konsoli by korzystać z funkcji w niej zawartych.
> A=matrix(1:9,3,3) > A [,1] [,2] [,3] [1,] 1 4 7 [2,] 2 5 8 [3,] 3 6 9 > library(Matrix) > rankMatrix(A) [1] 2 attr(,"method") [1] "tolNorm2" attr(,"useGrad") [1] FALSE attr(,"tol") [1] 6.661338e-16 > rzadA=rankMatrix(A)[1] > rzadA [1] 2 |
Można zauważyć, że w macierzy A ostatni rząd (3,6,9) jest równy 2⋅(2,5,8)-1⋅(1,4,7), czyli kombinacji liniowej rzędów drugiego i pierwszego. Natomiast wektory (2,5,8) i (1,4,7) są liniowo niezależne. Wszystkie wektory postaci α⋅(2,5,8)+β⋅(1,4,7) tworzą płaszczyznę w przestrzeni trójwymiarowej, czyli przestrzeń dwuwymiarową. Stąd rząd macierzy A jest rzeczywiście równy 2.
Wynikiem funkcji rankMatrix() jest złożony obiekt – ciąg jednoelementowy z wyjaśnieniami. Ponieważ często do obliczeń potrzebny jest tylko rząd macierzy należy go wywołać jako rankMatrix( )[1].
Statystyczna zależność k zmiennych od siebie najczęściej liczona jest względem regresji liniowej y=a1x1+a2x2+…+akxk+b, co jest pewną hiperpłaszczyzną w przestrzeni k-wymiarowej. W przypadku liniowej zależności zmiennych x1, x2, …, xk od siebie ta hiperpłaszczyzna ma mniejszy wymiar i nie jest jednoznacznie określona. Dość często generuje to błąd w programach statystycznych. Stąd istnieje w biologii potrzeba wyliczania rzędu macierzy, jaką tworzą dane
Wektory i wartości własne (ang.: eingenvalues and eigenvectors) są integralną częścią pewnego sposobu opracowania danych zwanym analizą składowych głównych (principal component analysis PCA). Pojęcia te odgrywają też dużą rolę w fizyce (analizie drgań, fizyce kwantowej itp.) i być może są lub będą liczone w pewnych pracach biofizycznych. Postaram się zatem wyjaśnić, co one oznaczają.
Mówimy, że macierz A o n-wierszach i n kolumnach ma wartość własną λ (liczbę) i wektor własny x o n wyrazach, jeżeli Ax=λx. Po lewej stronie mnożymy macierze n×n i n×1 (tak traktowany przez R jest wektor), czego wynikiem jest jakiś wektor n-elementowy. Po prawej stronie mnożymy przez liczbę λ wektor x=(x1,x2,…,xn) co jest równe wektorowi (λx1,λx2,…,λxn). Do wyznaczania wektorów i wartości własnych macierzy służy w R funkcja eigen().
> A=matrix(1:9,3,3); A[1,1]=-1; A[3,3]=-3 > eigen(A) $values [1] 10.942898 -8.119652 -1.823246 # $vectors [,1] [,2] [,3] [1,] -0.5033257 -0.5305492 -0.8965518 [2,] -0.7491261 -0.3808798 0.4216953 [3,] -0.4306661 0.7572636 -0.1355284 # > lambda1=eigen(A)[[1]][1] > lambda2=eigen(A)[[1]][2] > lambda3=eigen(A)[[1]][3] > wek1=eigen(A)[[2]][,1] > wek2=eigen(A)[[2]][,2] > wek3=eigen(A)[[2]][,3] > as.vector(A%*%wek1) [1] -5.507842 -8.197611 -4.712735 > lambda1%*%wek1 [1] -5.507842 -8.197611 -4.712735 > as.vector(A%*%(2.7*wek2)) [1] 11.631263 8.350051 -16.601536 > lambda2%*%(2.7*wek2) [1] 11.631263 8.350051 -16.601536 > A%*%wek3-lambda3%*%wek3 [1] [1,] 2.220446e-16 [2,] -1.110223e-16 [3,] -2.498002e-16 |
Pokazywane przez R współrzędne wektorów własnych są przykładowe. Łatwo bowiem sprawdzić, że jeżeli w=(w1,w2,…,wn) jest wektorem własnym o wartości własnej równej λ to dla dowolnej liczby α również wektor u=αw=(αw1,αw2,…,αwn) jest wektorem własnym o tej samej wartości własnej. R wylicza te wektory własne, które znajdują się na sferze jednostkowej (czyli suma kwadratów ich współrzędnych jest równa 1). Pomnożenie ich współrzędnych przez dowolną stałą daje także wektor własny.
Kolejną rzeczą stosowana przy analizie danych jest wyliczanie tzw. wartości osobliwych macierzy i tworzenie jej rozkładu SVD (rozkładu według wartości osobliwych – Singular Value Decomposition). Dla danej macierzy A (nie koniecznie kwadratowej, o n wierszach i m kolumnach) rzędu r (tzn., że co najwyżej r rzędów w tej macierzy jest niezależnych) należy znaleźć takie macierze U (o n wierszach i r kolumnach) i V (o m wierszach i r kolumnach) oraz wartości liczbowe (tzw. wartości osobliwe) σ1, σ2, …,σmin(n,m), aby:
- t(U)*U = Ir
- V*t(V) = Ir
- S = macierz [si,j]i=1,…,n, j=1,…,m spełniała warunek si,i=σi dla i=1,2,…,min(n,m) oraz si,j=0 gdy i≠j
- U*S*V-1=A
gdzie t(U), t(V) oznaczają transpozycje macierzy U i V, Ir jest macierzą kwadratową r×r złożoną z samych zer i jedynek występujących tylko na jednej przekątnej (z lewego górnego rogu do prawego dolnego). Jest to macierz jednostkowa r-wymiarowa. Macierze o własnościach t(U)*U = Ir i V*t(V) = Ir nazywamy ortonormalnymi. Gdy któraś z macierzy U lub V jest kwadratowa, to jej transpozycja jest jednocześnie macierzą odwrotną. Wtedy taka macierz nazywana jest ortogonalną.
Biologom takie coś wydaje się kompletnie bez sensu. Dopiero przy tworzeniu wykresów typu biplot pojawia się sensowność wyliczania rozkładu svd danej macierzy, najczęściej wielokolumnowej macierzy danych. Pozwala on bowiem zamienić wielokolumnową macierz danych na macierz dwukolumnową, której zobrazowanie pozwala na wyciąganie wniosków o wzajemnych zależnościach między zmiennymi.
W R rozkład SVD macierzy uzyskujemy za pomocą funkcji svd().
> A=matrix(1:9, 3, 3); A[1,1]=-1; A[3,3]=-3 > svd(A) $d [1] 12.472399 7.371181 1.762089 $u [,1] [,2] [,3] [1,] 0.63433242 0.17395674 -0.7532340 [2,] 0.76771998 -0.02742333 0.6401984 [3,] 0.09071064 -0.98437138 -0.1509456 $v [,1] [,2] [,3] [1,] 0.09406686 -0.4316700 0.8971134 [2,] 0.55484061 -0.7254629 -0.4072536 [3,] 0.82662163 0.5360640 0.1712660 |
Funkcja svd() umieszcza wartości w liście, której pierwszym elementem jest wektor wartości osobliwych, drugim lewostronna macierz U, a prawym prawostronna macierz V. Można sprawdzić, że są spełnione wszystkie warunki, które powinien spełniać rozkład SVD.
> A=matrix(1:9, 3, 3); A[1,1]=-1; A[3,3]=-3 > svd(A)[[2]]->U > svd(A)[[3]]->V > S=matrix(rep(0,9),3,3) > S[1,1]=svd(A)[[1]][1] > S[2,2]=svd(A)[[1]][2] > S[3,3]=svd(A)[[1]][3] > U%*%t(U) [,1] [,2] [,3] [1,] 1.000000e+00 -1.698403e-16 2.456260e-16 [2,] -1.698403e-16 1.000000e+00 -2.144213e-16 [3,] 2.456260e-16 -2.144213e-16 1.000000e+00 > V%*%t(V) [,1] [,2] [,3] [1,] 1.000000e+00 -1.498910e-17 -7.337338e-17 [2,] -1.498910e-17 1.000000e+00 -1.594929e-16 [3,] -7.337338e-17 -1.594929e-16 1.000000e+00 > U%*%S%*%t(V) [,1] [,2] [,3] [1,] -1 4 7 [2,] 2 5 8 [3,] 3 6 -3 |