Część funkcji poznanych wcześniej przy obsłudze wektorów można zastosować także do macierzy, przy czym w przypadku which.min() oraz which.max() konieczne jest użycie dodatkowo funkcji arrayInd() do określenia indeksów macierzy - w przeciwnym wypadku otrzymamy tylko indeks "wektorowy".
# Przykład 3.1
A <- matrix(1:16, 4, 4)
A## [,1] [,2] [,3] [,4]
## [1,] 1 5 9 13
## [2,] 2 6 10 14
## [3,] 3 7 11 15
## [4,] 4 8 12 16
sum(A)## [1] 136
mean(A)## [1] 8.5
sd(A)## [1] 4.760952
min(A)## [1] 1
max(A)## [1] 16
which.min(A)## [1] 1
which.max(A)## [1] 16
arrayInd(which.min(A), dim(A))## [,1] [,2]
## [1,] 1 1
arrayInd(which.max(A), dim(A))## [,1] [,2]
## [1,] 4 4
Aby wyznaczyć brzegowe wartości dla macierzy (np. sumę, średnią etc) wykorzystuje się funkcje apply(macierz,liczba,funkcja), przy czym liczba określa, czy odnosimy się do wiersza (1) czy kolumny (2).
# Przykład 3.2
apply(A, 1, sum)## [1] 28 32 36 40
apply(A, 2, sum)## [1] 10 26 42 58
apply(A, 1, mean)## [1] 7 8 9 10
apply(A, 2, sd)## [1] 1.290994 1.290994 1.290994 1.290994
Zamiast wbudowanych funkcji można także wykorzystac własne funkcje
# Przykład 3.3
# Wlasna funkcja
f <- function(x) {
sum(x^2)
}
apply(A, 1, f)## [1] 276 336 404 480
apply(A, 2, f)## [1] 30 174 446 846
Jak już zostało wcześniej wspomniane, w R należy unikać stosowania pętli. Paradygmat jest następujący: wszędzie, gdzie się da, należy wykorzystywać wektory (lub listy, macierze, ramki danych) i na tych strukturach dokonywać określonych operacji, dostając na wyjściu znów wektor etc. W najprostszym przypadku oznacza to po prostu użycie znanej funkcji (np. sin()) do wszystkich elementów wektora:
# Przykład 3.4
x <- 10
sin(x)## [1] -0.5440211
Powyższy przykład można również zapisac za pomocą funkcji sapply, która jako argumenty przyjmuje wektor oraz funkcje, która zostanie zastosowana element po elemencie:
# Przykład 3.5
x <- 10
sapply(x, sin)## [1] -0.5440211
Oczywiście, w tym konkretnym przypadku wygodniej jest użyć opcji z Przykładu 3.4. Gdy jednak sami chcemy skonstruowac funkcje, musimy uciec się do sapply, w przeciwnym wypadku R będzie chciał wykonać naszą funkcję tylko dla pierwszego elementu .
# Przykład 3.6a
# Własna funkcja
g <- function(x) {
y <- sum(1:x)
if(y > 2 * x) return(x)
else return(0)
}
# Glowny kod
x <- 1:10
# Bezpośrednie użycie g do wektora
g(x)## Warning in 1:x: numerical expression has 10 elements: only the first used
## Warning in if (y > 2 * x) return(x) else return(0): the condition has
## length > 1 and only the first element will be used
## [1] 0
# Użycie sapply
sapply(x, g)## [1] 0 0 0 4 5 6 7 8 9 10
Jeszcze lepiej jest użyć funkcji sapply wewnątrz swojej własnej funkcji
# Przykład 3.6b
# Wlasna funkcja
g <- function(x) {
y <- sapply(x, function(k) sum(1:k))
ifelse(y > 2 * x, x, 0)
}
# Glowny kod
x <- 1:10
# Bezposrednie użycie g do wektora
g(x)## [1] 0 0 0 4 5 6 7 8 9 10
Podobnie jak w innych językach skryptowych istnieje możliwość tworzenia funkcji anonimowych. Są to najczęściej krótkie wyrażenia, nie tylko arytmetyczne, bez nazwy (stąd anonimowe), które istnieją ulotnie - po wykonaniu operacji zostają usunięte z pamięci.
# Przykład 3.7
a <- 1:10
sapply(a, function(x) x^2 - 2)## [1] -1 2 7 14 23 34 47 62 79 98
Za pomocą funkcji anonimowych oraz zagnieżdżonych funkcji sapply można tworzyc alternatywę dla podwójnych pętli.
# Przykład 3.8
a <- 1:10
sapply(a, function(x) {sapply(rev(a), function(y) x * y)})## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
## [1,] 10 20 30 40 50 60 70 80 90 100
## [2,] 9 18 27 36 45 54 63 72 81 90
## [3,] 8 16 24 32 40 48 56 64 72 80
## [4,] 7 14 21 28 35 42 49 56 63 70
## [5,] 6 12 18 24 30 36 42 48 54 60
## [6,] 5 10 15 20 25 30 35 40 45 50
## [7,] 4 8 12 16 20 24 28 32 36 40
## [8,] 3 6 9 12 15 18 21 24 27 30
## [9,] 2 4 6 8 10 12 14 16 18 20
## [10,] 1 2 3 4 5 6 7 8 9 10
Standardowa funkcja wykorzystywana do tworzenia wykresów jest plot(x,y), gdzie x i y sa odpowiednio wektorami liczb.
# Przykład 3.9
x <- 1:10
plot(x, x^2)Funkcja plot() ma pokaźny zestaw różnych opcji, przy czym najczęściej wykorzystywane to xlab="..." (tytuł osi X), ylab="..." (tytuł osi Y), main="..." (tytuł wykresu), col="..." (kolor punktów), pch=... (kształt punktów), cex="..." (rozmiar punktów), font=... (typ czcionki osi: 1 - normalna, 2 - pogrubiona, 3 - kursywa, 4 - pogrubiona kursywa). W przypadku nazw osi można wykorzystywać funkcje expression(), która koduje wyrażenia matematyczne i litery greckie (np. ^ to indeks gorny, [..] - indeks dolny, itd.).
# Przykład 3.10
x <- 1:10
plot(x, x^2, xlab = "x", ylab = expression(f(xi)==x^2), col = "red", pch = 19, font = 2, font.lab = 4, main = "Wykres funkcji f(x)", font.main = 3, cex = 2)W przypadku potrzeby zapisania wykresu do pliku należy skorzystać z jednej z komend png(), jpeg() czy tiff(), a następnie zamknąć strumień komendą dev.off().
# Przykład 3.11
png("fig2.png")
plot(x, x^2, xlab = "x", ylab = expression(f(xi)==x^2), col = "red", pch = 19, font = 2, font.lab = 4, main = "Wykres funkcji f(x)", font.main = 3, cex = 2)
dev.off()## png
## 2
Do umieszczenia legendy na wykresie służy funkcja legend(), której najważniejszymi argumentami są:
x - współrzędna lewej krawędzi legendy na wykresie lub jedno z predediniowanych słów-kluczy: top,bottom,left,right,center,topleft,topright,bottomleft,bottomright,y - współrzędna górnej krawędzi legendy (domyślnie NULL, używa się jej w parze ze współrzędną lewej krawędzi legendy),legend - wektor nazw poszczególnych elementów legendy,pch - wektor z numerami symboli wyświetlających się przy nazwach poszczególnych elementów legendy,col - wektor z kolorami symboli (obramowania),pt.bg - wektor z kolorami teł symboli.# Przykład 3.12
x <- 1:10
plot(x, x^2, xlab = "x", ylab = expression(f(x)), col = "red", bg="red", pch = 21, cex = 2)
points(x, x^1.5, col="blue", bg="blue", pch=22, cex=2)
legend("topleft", legend=c(expression(x^1.5),expression(x^2)), pch = c(22,19), col = c("blue","red"), pt.bg=c("blue","red"))Najprostszą metodą tworzenia histogramu (w formie tekstowej) jest wykorzystanie funkcji tabulate(). Efektem jej działania jest zliczenie wartości całkowitych zawartych w wektorze. W przypadku liczb rzeczywistych dokonywane jest zaokrąglenie w dół.
# Przykład 3.13
y <- c(0,0,1,2,3,1,2,3,4)
tabulate(y)## [1] 2 2 2 1
y <- c(0,0,1.1,1.9,2.1,2,3)
tabulate(y)## [1] 2 2 1
W przypadku histogramu 2D można posłuzyć się funkcją table(), która stworzy dwuwymiarową tablicę współwystępowania wartości.
# Przykład 3.14
df <- data.frame(x=c(1,1,2,2,3,4,5), y=c(2,2,3,1,5,5,5))
df## x y
## 1 1 2
## 2 1 2
## 3 2 3
## 4 2 1
## 5 3 5
## 6 4 5
## 7 5 5
table(df)## y
## x 1 2 3 5
## 1 0 2 0 0
## 2 1 0 1 0
## 3 0 0 0 1
## 4 0 0 0 1
## 5 0 0 0 1
Jednak klasyczna funkcja odpowiedzialna za tworzenie histogramów jest hist(). Samo jej wywołanie daje efekt narysowania histogramu o zadanej liczbie przedziałów (binów).
# Przykład 3.15
x <- c(1,1,1,2,2,4,10)
hist(x)W pewnym sensie nawet ważniejszą rzeczą od samego wykresu jest zawartość zmiennej, do której zostanie zapisany jego wynik. Otrzymamy z niej informacje nie tylko o liczbie zliczeń (counts), ale także o granicach binów (breaks), ich środkach (mids) jak również funkcji gęstosci (density).
# Przykład 3.16
x <- c(1,1,1,2,2,4,10)
h <- hist(x)h## $breaks
## [1] 0 2 4 6 8 10
##
## $counts
## [1] 5 1 0 0 1
##
## $density
## [1] 0.35714286 0.07142857 0.00000000 0.00000000 0.07142857
##
## $mids
## [1] 1 3 5 7 9
##
## $xname
## [1] "x"
##
## $equidist
## [1] TRUE
##
## attr(,"class")
## [1] "histogram"
Za pomocą funkcji sample(x) można w pakiecie R uzyskać permutację oryginalnego zbioru (wektora x). W przypadku podania konkretnej liczby próbek, mniejszej niż rozmiar x elementy zostaną wylosowane bez zwracania. Wreszcie, podanie opcji replace=TRUE umożliwi losowanie ze zwracaniem. Dodatkowo, podanie wektora prob daje możliwość sterowania prawdopodobieństwem wylosowania konkretnych elementów wektora x. Funkcja nie ogranicza się jedynie do typów liczbowych.
# Przykład 3.17
sample(1:3, 2)## [1] 3 1
sample(1:10, 2)## [1] 5 6
sample(1:10)## [1] 8 4 6 2 5 7 10 3 1 9
sample(1:10, 4)## [1] 10 4 9 2
sample(1:10, 20, replace=TRUE)## [1] 8 10 1 3 5 10 9 4 8 6 7 4 8 3 3 1 1 8 2 9
sample(1:3, 10, replace=TRUE, prob=c(0.1,0.8,0.1))## [1] 2 2 2 2 3 2 2 2 2 2
sample(letters[1:3], 10, replace=TRUE)## [1] "b" "b" "c" "a" "b" "c" "b" "b" "b" "b"
sample(c(0.1, 0.2, 0.3), 10, replace=TRUE)## [1] 0.3 0.1 0.2 0.1 0.3 0.3 0.3 0.2 0.2 0.3
W pakiecie R jest zaimplementowany cały zestaw standardowych rozkładów prawdopodobieństw (rozkład Gaussa, dwumianowy etc), do których odwołujemy się w ten sam sposob r|p|d|qnazwa(), gdzie w miejsce nazwa należy wstawić nazwę odpowiedniego rozkładu prawdopodobieństwa (np. norm, unif, exp, binom), a pierwsza litera oznacza typ funkcji:
r - losowanie z rozkładu (np. runif(5) - losowanie pięciu liczb z rozkładu jednostajnego),
p - dystrybuantę (np. pnorm(2, 0, 1.5) - wartość dystrybuanty dla rozkładu normalnego o średniej 0 i odchyleniu 1.5 w punkcie 2),
d - gęstość prawdopodobieństwa (np. dexp(2, 0.1) - gęstość prawdopodobieństwa dla rozkładu wykładniczego o parameterze 0.1 w punkcie 2),
q - kwantyl (np. qnorm(0.95, 0, 1) zwróci kwantyl rzędu 0.95 z rozkładu normalnego o średniej 0 i odchyleniu standardowym 1).
# Przykład 3.18
x <- seq(-2, 2, .1)
plot(x, dnorm(x, 0, 0.5), ylim = c(0,1.5), pch = 19)
points(x, dnorm(x, 0, 1), pch = 19, col = "blue")
points(x, dnorm(x, 0, 0.3), pch = 19, col = "green", t = "o")
lines(x, pnorm(x, 0, 0.3), col = "red", lwd = 2)# Przykład 3.19
runif(10)## [1] 0.6607871 0.7717536 0.7353429 0.5211421 0.3531406 0.9384612 0.9312509
## [8] 0.6434158 0.3916183 0.7073876
runif(10, 5, 10)## [1] 8.269966 6.724866 5.963732 7.468810 8.479985 6.939653 7.321587
## [8] 8.478122 6.719646 9.895461
Wylosuj \(n\) liczb z rozkładu normalnego o średniej \(m\) i odchyleniu standardowym \(s\) (\(n\),\(m\),\(s\) powinny być zmiennymi których wartość będzie można zmieniać w skrypcie). Następnie wykonaj histrogram z tych danych i umieść na wykresie empiryczną gęstość prawdopodobieństwa w postaci punktów (tę gęstość można wyciągnąć z obiektu histogram. Dodaj drugą serię do wykresu (czerwona linia), która będzie przedstawiać teoretyczną gęstość prawdopodobieństwa. Podpisz osie i dodaj legendę tak jak na rysunku poniżej.