Wektory i macierze dla zaawansowanych

Poznaliśmy już wektory i macierze i podstawowe operacje na nich, pora podnieść nieco poprzeczkę i nauczyć się bardziej zaawansowanych, a przy tym znacznie ciekawszych funkcji.

Kilka pożytecznych funkcji, które najlepiej poznać po prostu sprawdzając, jak działają:

> ceny = c(2.80, 4.60, 2.70, 8.40)
> length(ceny) # dlugosc
[1] 4
> sum(ceny)     # suma
[1] 18.5
> mean(ceny)    # srednia
[1] 4.625
> max(ceny)     # chyba nie trzeba tlumaczyc...
[1] 8.4
> min(ceny)
[1] 2.7
> names(ceny)   # sprawdzamy czy elementy w naszym wektorze maja nazwy
NULL
> # nie maja? no to je dodamy
> names(ceny) = c("chleb", "czekolada", "sok", "maslo orzechowe")
> ceny
          chleb       czekolada             sok maslo orzechowe
            2.8             4.6             2.7             8.4
>
> ceny["czekolada"]     # teraz mozemy dostac sie do elementu po jego nazwie, nie tylko numerze!
czekolada
      4.6
> 2.8 %in% ceny         # sprawdzamy czy wartosc 2.8 jest w wektorze
[1] TRUE
> "czekolada" %in% names(ceny)  # a teraz czy wartosc "czekolada" jest w wektorze nazw wektora ceny
[1] TRUE
> "makaron" %in% names(ceny)
[1] FALSE
> ceny[ ceny > 3 ]              # wyswietlimy tylko te elementy wektora, ktore sa wieksze od 3
      czekolada maslo orzechowe
            4.6             8.4

Ostatnie polecenie może na pierwszy rzut oka wyglądać mało intuicyjnie. Wpiszmy najpierw samo ceny > 3 i zobaczmy, co wyjdzie:

> ceny > 3
          chleb       czekolada             sok maslo orzechowe
          FALSE            TRUE           FALSE            TRUE

No tak, wektor TRUE / FALSE. Z tego wynika, że jeśli wektor wartości logicznych wpiszemy jako indeksy wektora, dostaniemy wektor z elementami odpowiadającymi wartościom TRUE. Na przykład:

> ( wektor = 1:5 )
[1] 1 2 3 4 5
> wektor[ c(TRUE, TRUE, FALSE, FALSE, TRUE) ]
[1] 1 2 5

Podobne rzeczy można robić oczywiście z macierzami:

> ( macierz = matrix(1:9, ncol = 3) )
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> dim(macierz)  # dimensions, czyli wymiary
[1] 3 3
> colnames(macierz) = c("a", "b", "c")
> rownames(macierz) = c("I", "II", "III")
> macierz
    a b c
I   1 4 7
II  2 5 8
III 3 6 9
> macierz["I",]
a b c
1 4 7
> macierz["II","c"]
[1] 8
> macierz[-1,"c"]       # bez pierwszego wiersza, tylko kolumna "c"
 II III
  8   9
> macierz[ macierz %% 2 == 1 ]  # wszystkie wartosci, dla ktorych spelnione jest, ze reszta z dzielenia to 2
[1] 1 3 5 7 9
> sum(macierz)
[1] 45

Jeśli nie tylko przeczytałeś/aś już wszystkie powyższe polecenia, ale też przepisałeś/aś je u siebie do R-a, przetestowałeś/aś i sądzisz, że rozumiesz już ich działanie, to możemy zanurkować jeszcze głębiej, poznawać kolejne ciekawe funkcje:

> which( c(TRUE, FALSE, TRUE, FALSE, FALSE) )   # na ktorych indeksach jest TRUE
[1] 1 3
> which( c(1,2,3) )                             # to nie zadziala, musza byc true / false
Error in which(c(1, 2, 3)) : argument to 'which' methods/html/is.html">is not logical
> which( 1:10 %% 3 == 0 )                       # no to zrobmy true / false - sprawdzmy, gdzie sa w wektorze 1:10 liczby podzielne przez 3
[1] 3 6 9
> length( which( 1:100 %% 11 == 0 ) )           # ile jest liczb podzielnych przez 11 od 1 do 100?
[1] 9
> wektor = c(4,3,0,5,11,2)
> sort(wektor)          # zwroc wektor posortowany (oczywiscie zmienna wektor pozostaje nietknieta)
[1]  0  2  3  4  5 11
> order(wektor)         # zwroc kolejnosc wektora, tj. na jakim miejscu bylyby poszczegolne elementy, gdyby byl posortowany
[1] 3 6 2 1 4 5
> wektor[ c(2,4,6,1,3,5) ]      # podajemy wektor indeksow - tu podalismy wszystkie, ale w dziwnej kolejnosci, wiec namieszalismy kolejnosc w wektorze
[1]  3  5  2  4  0 11
> wektor[ order(wektor) ]       # troche na okolo sposob na sortowanie wektora...
[1]  0  2  3  4  5 11
> inny_wektor = c("a","b","c","d","e","f")
> inny_wektor[ order(wektor) ]  # sortujemy inny_wektor wg kolejnosci w wektorze wektor
[1] "c" "f" "b" "a" "d" "e"
> inny_wektor[ order(wektor) ][ wektor != 4 ]   # i wywalamy wartosci z tych pozycji, na ktorych w wektorze wektor mamy liczbe 4
[1] "f" "b" "a" "d" "e"

Jeżeli pojęłaś/pojąłeś dokładnie wszystko, co dzieje się w powyższym fragmencie kodu, jesteś gotowa/y poznać jedną z najpożyteczniejszych funkcji R-a: apply. Jest to funkcja działająca na macierzach, która wykonuje jakąś żądaną przez nas operację na wszystkich wierszach / kolumnach danej macierzy. Przykład użycia:

     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6
> apply(macierz, 1, sum)
[1]  9 12
> apply(macierz, 2, sum)
[1]  3  7 11

Pierwszym argumentem jest macierz, na której chcemy coś policzyć. Drugi argument wynosi 1, jeśli chcemy zrobić coś na wierszach, albo 2 jeśli na kolumnach (można zapamiętać w ten sposób, że podając indeksy wierszy i kolumn zawsze pierwsze są wiersze, aczkolwiek można też nie pamiętać i skorzystać z helpa wpisując ?apply). Trzeci mówi, jaką funkcję chcemy zastosować. Wynikiem jest wektor: w pierwszym przypadku, dostaliśmy wektor dwuelementowy, bo operację wykonywaliśmy na wierszach, których było dwa: R zsumował pierwszy wiersz, wyszło mu 9, zsumował drugi, wyszło mu 12; zwrócił więc wektor c(9, 12). W drugim przypadku działaliśmy na kolumnach i dostaliśmy wektor sum kolejnych kolumn.

Oczywiście jest to ledwie garstka funkcji, które są dostępne w R-ze. Ciekawskim polecam poczytanie o innych funkcjach i przetestowanie ich działania, np. sample, rank, rev, diag czy outer, oraz sięgnięcie do rozmaitych zewnętrznych źródeł.