Transkrypt
PDF
Wprowadzenie do środowiska programistycznego R (na podst. http://math.illinoisstate.edu/dhkim/rstuff/rtutor.html) 1) R jako kalkulator > > > > > > > > > > 2 + 3 * 5 # zwróć uwage na kolejność wykonywania działań log (10) # logarytm natualny o podstawie e=2.718282 4^2 # 4 do potęgi drugiej 3/2 # dzielenie sqrt (16) # pierwiastek kwadratowy abs (3-7) # wartość bezwzględna wyrażenia 3-7 pi # liczba pi exp(2) # funkcja wykładnicza 15 %/% 4 # liczba całkowita z reszty dzielenia # Tworzenie komentarza wykonuje się poprzez wstawienie znaku '#' 2) Tworzenie obiektów Operatorem przypisania w R jest wyrażenie <- lub = Wyrażenie znajdujące się po prawej stronie operatora jest przypisane do wyrażenia znajdującego się po lewej stronie. Zapoznajmy się zatem z wybranymi funkcjami matematycznymi dostępnymi w R. Uwaga: W R wielkość znaków MA ZNACZENIE, tzn. wyrażenie abc i ABC, mogą być 2 różnymi obiektami o innej zawartości. > x=log(2.843432)*pi > x [1] 3.283001 > sqrt(x) [1] 1.811905 > floor(x) # największa liczba całkowita mniejsza niż x (zaokrąglanie w dół) [1] 3 > ceiling(x) # najmniejsza liczba całkowita większa niż x (zaokrąglanie w górę) [1] 4 3) Typy obiektów Wektor Podstawowym typem obiektu jest wektor, który tworzymy z wykorzystaniem funkcji c > x<-c(1,3,2,10,5) #tworzy wektor x o zdefiniowanych 5 komponentach > x [1] 1 3 2 10 5 > y<-1:5 #tworzy wektor liczb całkowitych w kolejności narastającej > y [1] 1 2 3 4 5 > y+2 #dodaje liczbę 2 do wszystkich elementów obiektu y [1] 3 4 5 6 7 > 2*y #mnoży x2 wszystkie elementy obiektu y [1] 2 4 6 8 10 > y^2 #podnosi każdy element obiektu y do potęgi 2-giej [1] 1 4 9 16 25 > 2^y #podnosi liczbę 2 do potęgi każdego z kolejnych elementów zbioru y [1] 2 4 8 16 32 > y #sam y nam się nie zmienia [1] 1 2 3 4 5 > y=y*2 > y #chyba, że użyjemy operatora przypisania [1] 2 4 6 8 10 Jeśli chcemy zawrzeć więcej niż 1 polecenie w 1 linii używamy do tego celu średnika: > x<-c(1,3,2,10,5); y<-1:5 Wygodnym uproszczeniem są operacje wykonywane bezpośrednio na obiektach: > x+y [1] 2 5 5 14 10 > x*y [1] 1 6 6 40 25 > x/y [1] 1.0000000 1.5000000 0.6666667 2.5000000 1.0000000 > x^y [1] 1 9 8 10000 3125 Podstawą pracy w R są funkcje gdzie najpierw podaje się nazwę funkcji, a następnie w nawiasie elementy jakie mają być przez funkcje wykonane: > sum(x) [1] 21 > cumsum(x) [1] 1 4 6 16 21 [1] 1 7 3 > max(x) [1] 10 > min(x) [1] 1 #suma wszystkich elementów of elements in x #skumulowana suma kolejnych elementów #maximum #minimum Sortowanie elementów z użyciem komendy sort() : > x [1] 1 3 2 10 5 > sort(x) # kolejność rosnąca [1] 1 2 3 5 10 wektora Funkcje mogą mieć domyślnie zadeklarowane parametry lub możemy je określać po przecinku: > sort(x, decreasing=T) # kolejność malejąca [1] 10 5 3 2 1 Ekstrakcja poszczególnych elementów wektora jest niezmiernie ważna w kontekście pracy z rzeczywistymi danymi: > x [1] 1 3 2 10 5 > length(x) # liczba elementów obiektu x [1] 5 > x[3] # 3-ci element obiektu x [1] 2 > x[3:5] # od 3-go do 5-go elementu obiektu x [1] 2 10 5 > x[-2] # wszystkie elementy x z wyjątkiem 2-giego [1] 1 2 10 5 > x[x>3] # wyświetla tylko te elementy które spełniają określoną zależność [1] 10 5 Kolejne przydatne funkcje to seq(), rep() i which(). Sprawdźmy zatem ich działanie: > seq(10) [1] 1 2 3 4 5 6 7 8 9 10 > seq(0,1,length=10) [1] 0.0000000 0.1111111 0.2222222 0.3333333 0.4444444 0.5555556 0.6666667 [8] 0.7777778 0.8888889 1.0000000 > seq(0,1,by=0.1) [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 > rep(1,3) [1] 1 1 1 > c(rep(1,3),rep(2,2),rep(-1,4)) [1] 1 1 1 2 2 -1 -1 -1 -1 > rep("Small",3) [1] "Small" "Small" "Small" > c(rep("Small",3),rep("Medium",4)) [1] "Small" "Small" "Small" "Medium" "Medium" "Medium" "Medium" > which(x>5 & x <7) # podaje numery indeksów spełniających warunek w nawiasie Macierze W najprostszej postaci (2-wymiarowej) macierze to po prostu tabele z danymi. Tworzenie macierzy można wykonywać np. poprzez złączenie kolumn lub rzędów o jednakowej długości. W zależności od tego w jaki sposób chcemy macierz utworzyć wykorzystujemy funkcje cbind(), (skrót od "column bind") lub rbind() (skrót od „row bind”): > x [1] 1 3 2 10 5 > y [1] 1 2 3 4 5 > m1<-cbind(x,y);m1 x y [1,] 1 1 [2,] 3 2 [3,] 2 3 [4,] 10 4 [5,] 5 5 > t(m1) # transpozycja macierzy m1 [,1] [,2] [,3] [,4] [,5] x 1 3 2 10 5 y 1 2 3 4 5 > m1<-t(cbind(x,y)) # operacje można także zagnieżdżać > dim(m1) # podaje wymiary macierzy [1] 2 5 > m1<-rbind(x,y) # rbind() jest funkcją dla łączenia po wierszach. Wynik powinien być taki sam jak dla komendy: t(cbind()). Oczywiście można macierz utworzyć również z wykorzystaniem funkcji 'matrix()': > m2<-matrix(c(1,3,2,5,-1,2,2,3,9),nrow=3);m2 [,1] [,2] [,3] [1,] 1 5 2 [2,] 3 -1 3 [3,] 2 2 9 Zwróć uwagę, że poszczególne elementy są użyte do wypełnienia w pierwszej kolejności 1-szej kolumny, potem 2-giej, itd. Jeśli chcemy użyć danych do wypełnienia po rzędach, musimy komputer o tym poinformować za pomocą opcji byrow=T: > m2<-matrix(c(1,3,2,5,-1,2,2,3,9),ncol=3,byrow=T);m2 [,1] [,2] [,3] [1,] 1 3 2 [2,] 5 -1 2 [3,] 2 3 9 Wyciąganie poszczególnych elementów z macierzy wymaga zadeklarowania jej wszystkich wymiarów: > m2 [,1] [,2] [,3] [1,] 1 3 2 [2,] 5 -1 2 [3,] 2 3 9 > m2[2,3] #element macierzy m2 w 2-gim rzędzie i 3-ciej kolumnie [1] 2 > m2[2,] #cały 2-gi rząd [1] 5 -1 2 > m2[,3] #cała 3-cia kolumna [1] 2 2 9 > m2[-1,] #cała macierz m2 bez pierwszego rzędu [,1] [,2] [,3] [1,] 5 -1 2 [2,] 2 3 9 > m2[,-1] #i bez pierwszej kolumny [,1] [,2] [1,] 3 2 [2,] -1 2 [3,] 3 9 # stwórz nową macierz o dowolnej nazwie bez pierwszej kolumny i pierwszego rzędu Operacje arytmetyczne na macierzach wykonuje się analogicznie do operacji na wektorach: > m1<-matrix(1:4, ncol=2); m2<-matrix(c(10,20,30,40),ncol=2) > 2*m1 # iloczyn skalarny [,1] [,2] [1,] 2 6 [2,] 4 8 > m1+m2 # dodawanie macierzy [,1] [,2] [1,] 11 33 [2,] 22 44 > m1*m2 # mnożenie analogicznych elementów [,1] [,2] [1,] 10 90 [2,] 40 160 Zwróc uwagę, że formuła: m1*m2 NIE JEST mnożeniem macierzy w sensie matematycznym. Do tego służy funkcja %*% : > m1 %*% m2 [,1] [,2] [1,] 70 150 [2,] 100 220 Ramka danych Ramka danych jest ostatnim typem danych, który muszą Państwo poznać przed rozpoczęciem prawdziwej pracy w środowisku R. Ramka danych jest zwykle macierzą składającą się z kolumn, ale może zawierać różne typy danych (np. dane w formie liczbowej, tekstowej, itd.). Nie będziemy się zatrzymywać na kwestii tworzenia ramek danych, tylko wykorzystamy domyślnie wgrane dane o nazwie 'cars' data(cars) names(cars) # wyświetlenie nazw kolumny Jeśli chcemy wyświetlić tylko pierwszą kolumnę możemy zrobić wywołanie analogiczne jak dla macierzy [] lub użyć symbolu '$' cars$speed Mocną stroną R jest tworzenie wykresów wysokiej jakości, które z powodzeniem mogą być wykorzystane przy publikacjach i opracowaniach. Spróbujmy zatem zastososowania poniższych komend: [1] "speed" "dist" hist(cars$dist) # tworzy histogram # zapisz histogram w postaci obiektu 'a' i wyświetl jego zawartość plot(cars, xlab = "Speed (mph)", ylab = "Stopping distance (ft)", las = 1) lines(lowess(cars$speed, cars$dist, f = 2/3, iter = 3), col = "red") title(main = "cars data") plot(cars, xlab = "Speed (mph)", ylab = "Stopping distance (ft)", las = 1, log = "xy") title(main = "cars data (logarithmic scales)") lines(lowess(cars$speed, cars$dist, f = 2/3, iter = 3), col = "red") summary(fm1 <- lm(log(dist) ~ log(speed), data = cars)) # Możemy także spróbować zrobić prostą wizualizację 3d dla modelu DEM data(volcano) z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) ## Don't draw the grid lines : border = NA persp(x, y, z, theta = 135, phi = 30, col = "green3", scale = FALSE, ltheta = -120, shade = 0.75, border = NA, box = FALSE) Programowanie w R Dotychczas nasza nauka nie wykraczała zbytnio poza możliwości, które możemy osiągnać w dowolnym arkuszu kalkulacyjnym. Prawdziwa moc zaklęta w językach programowania polega na zastosowaniu instrukcji sterujących, pętli oraz funkcji programistycznych, które pozwalają na automatyzację wykonywanych operacji. Instrukcje sterujące/warunkowe: #Instrukcja warunkowa 'if': > if (warunek){ + instrukcja1 + } > else{ + instrukcja2 + } można także zastosować instrukcję warunkową 'if' bez opcji 'else', np.: >x=2 > if(x==2){ print("Faktycznie, x=2") } > y=4 > if(x==3 & y==4){ print("Faktycznie, x=3 i y=4") } else{ print("x jest różny od 3, y jest różny od 4") } Zadanie: Napisz instrukcję warunkową „if-else” sprawdzających wybrane dowolnie 3 poniższe wyrażenia logiczne (dla dowolnie zdefiniowanych liczb): x == y "x is equal to y" x != y "x is not equal to y" x > y "x is greater than y" x < y "x is less than y" x <= y "x is less than or equal to y" x >= y "x is greater than or equal to y" Drugą instrukcją sterującą, podobną do 'if' jest instrukcja 'ifelse': # Instrukcja 'ifelse' (odpowiednik excelowego 'jeżeli', ale możemy go tworzyć dla obiektów dowolnie długich, a nie dla jednej komórki) > x = 1:10 > ifelse(x<5 | x>8, x, 0) PĘTLE: 1. FOR Najpopularniejsza pętla w językach programowanie to tzw. pętla 'for'. Wszystko co znajduje się pomiędzy znakami '{}' jest wykonywane dla każdej zdefiniowanej wartości dowolnego parametru , taką ilość razy jaka jest długość prawej strony wyrażenia: # Pętla for: > for (k in 1:5){ + print(k) +} Najlepiej jednak pokazać użyteczność na przykładzie (np. posługując się zbiorem danych z reanalizy temperatury powierzchni morza wg Reynoldsa (2007): load("sst.Rdata") # wczytujemy przykładowe dane for (dzien in (1:10)) { jpeg(filename=paste(czas[dzien],"jpg",sep=".")) image(lon,lat,sst[,,dzien],main=czas[dzien],xlab="lon",ylab="lat") box() dev.off() } 2. WHILE W modelowaniu często nie znamy dokładnego rozwiązania wielu układów równań różniczkowych. Często nie mają one analitycznego rozwiązania. Stąd też wiele metod wykorzystuje tzw. metody iteracyjne, gdzie obliczenia wykonywane są aż do uzyskania pewnej satysfakcjonującej nas wielkości minimalnego błędu. Tego typu zależność będziemy wykorzystywać w jednym z najprostszych modeli bilansu energetycznego Ziemi. Spróbujmy zatem wykorzystać inną właściwość pętli 'while', która wykonuje się tak długo dopóki zadeklarowany warunek nie zostanie spełniony. Wyobraźmy sobie, że mamy dużą ilość plików, które mają analogiczny ciąg serii danych (rok, miesiąc, dzień, godzina) i chcemy je połączyć w jedną tabelę: setwd(„C:\modelowanie\pliki ”) # ustawiamy katalog gdzie przechowujemy te pliki: plik=dir(pattern=".txt") # pobieramy nazwy plików, które znajdują się w katalogu dl=length(plik) # sprawdzamy ile jest plików w tym katalogu wynik=NULL i=1 # tworzymy pusty obiekt na wyniki while(i<=dl) { dane=read.table(plik[i], header=T) wynik=cbind(wynik,dane$ff) i=i+1 } colnames(wynik)=plik wynik=cbind(dane[,1:4],wynik) write.table(wynik, file="wynik.csv", sep=";", row.names=F) FUNKCJE Ostatnią rzeczą, którą każdy początkujący programista musi poznać są funkcje. Wszystkie polecenia, po których do tej pory wywoływaliśmy () są w rzeczywistości właśnie funkcjami, przyjmującej pewne parametry. Jeśli wywołamy jakieś polecenie będące funkcją bez nawiasów, wówczas wyświetli nam się jej kod źródłowy. > log Ogólna postać funkcji wygląda następująco: nazwafunkcji = function(argument1, argument2, ...) { wyrażenia zawarte w funkcji } # koniec funkcji następnie wywołujemy funkcję wpisując jej nazwę i argumenty. Sprawdźmy jak to działa na konkretnym przykładzie: funkcja = function(r,x) { r*x*(1-x) } i przetestujmy jej działania na wartościach r=2, x=5 : funkcja(2,5) Jeśli korzystamy z jakiegoś schematu postępowania bardzo często warto zawrzeć je właśnie w postaci funkcji.