Uvod - Srce | Sveučilišni računski centar Sveučilišta ...



Osnove programiranja u R-uS760615954254500Ovu ina?icu priru?nika izradio je autorski tim Srca u sastavu:Autori: dr. sc. Damir Pintar i dr. sc. Mihaela Vrani?Recenzentica: mr. sc. Melita Per?ec Tadi?Urednica: Sabina RakoLektorica: Mia Ko?ulSveu?ili?te u ZagrebuSveu?ili?ni ra?unski centarJosipa Marohni?a 5, 10000 Zagrebedu@srce.hrISBN 978-953-8172-45-8 (meki uvez)ISBN 978-953-8172-46-5 (PDF)Verzija priru?nika: 20200205Ovo djelo dano je na kori?tenje pod licencom Creative Commons Imenovanje-Nekomercijalno-Dijeli pod istim uvjetima 4.0 me?unarodna. Licenca je dostupna na stranici: \o "1-3" \h \z \u1.Uvod PAGEREF _Toc31795111 \h 11.1.Osnovne informacije PAGEREF _Toc31795112 \h 11.2.Osnovno o jeziku R PAGEREF _Toc31795113 \h 21.2.1.R – programsko okru?enje za statisti?ke metode, vizualizaciju, eksploratornu i dubinsku analizu podataka PAGEREF _Toc31795114 \h 21.2.2.Na?ini u?enja R-a PAGEREF _Toc31795115 \h 21.2.3.Pregled sadr?aja te?aja PAGEREF _Toc31795116 \h 32.Osnovni tipovi podataka i podatkovne strukture PAGEREF _Toc31795117 \h 42.1.Osnovni tipovi podataka PAGEREF _Toc31795118 \h 42.1.1.Pregled osnovnih tipova PAGEREF _Toc31795119 \h 42.1.2.Pojam varijable PAGEREF _Toc31795120 \h 42.1.3.Provjera tipa podatka PAGEREF _Toc31795121 \h 52.2.Slo?ene podatkovne strukture PAGEREF _Toc31795122 \h 62.2.1.Vektor PAGEREF _Toc31795123 \h 62.2.2.Operator [ PAGEREF _Toc31795124 \h 72.2.3.Matrice i polja PAGEREF _Toc31795125 \h 82.2.4.Liste PAGEREF _Toc31795126 \h 102.2.5.Podatkovni okviri (Data frames) PAGEREF _Toc31795127 \h 113.Vektorizacija i indeksni vektori PAGEREF _Toc31795128 \h 143.1.Principi vektorizacije i recikliranja PAGEREF _Toc31795129 \h 143.1.1.“Sve je vektor” PAGEREF _Toc31795130 \h 143.1.2.Matrica kao vektor PAGEREF _Toc31795131 \h 143.1.3.Lista kao vektor PAGEREF _Toc31795132 \h 153.1.4.Podatkovni okvir kao vektor PAGEREF _Toc31795133 \h 163.1.5.Vektorizirane operacije i princip recikliranja PAGEREF _Toc31795134 \h 173.2.Indeksni vektori PAGEREF _Toc31795135 \h 193.2.1.Definicija indeksnoga vektora PAGEREF _Toc31795136 \h 193.2.2.Lokacijsko indeksiranje PAGEREF _Toc31795137 \h 203.2.3.Uvjetno indeksiranje PAGEREF _Toc31795138 \h 223.2.4.Imensko indeksiranje PAGEREF _Toc31795139 \h 233.2.5.Indeksni vektori i matrice PAGEREF _Toc31795140 \h 243.2.6.Indeksni vektori i podatkovni okviri PAGEREF _Toc31795141 \h 243.3.Dodatni zadaci za vje?bu PAGEREF _Toc31795142 \h 264.R i programske paradigme PAGEREF _Toc31795143 \h 274.1.?to su programske paradigme? PAGEREF _Toc31795144 \h 274.1.1.Op?enito o programskim paradigmama PAGEREF _Toc31795145 \h 274.1.2.Imperativna programska paradigma PAGEREF _Toc31795146 \h 274.1.3.Objektna programska paradigma PAGEREF _Toc31795147 \h 274.1.4.Funkcijska programska paradigma PAGEREF _Toc31795148 \h 274.2.Programski jezici i programske paradigme PAGEREF _Toc31795149 \h 284.2.1.Odabir jezika = odabir paradigme? PAGEREF _Toc31795150 \h 284.2.2.R i programske paradigme PAGEREF _Toc31795151 \h 285.Upravljanje programskim tokom PAGEREF _Toc31795152 \h 295.1.Uvjetno izvo?enje naredbi PAGEREF _Toc31795153 \h 295.1.1.Naredba if - else PAGEREF _Toc31795154 \h 295.1.2.Naredba ifelse PAGEREF _Toc31795155 \h 295.2.Programske petlje PAGEREF _Toc31795156 \h 305.2.1.R i programske petlje PAGEREF _Toc31795157 \h 305.2.2.Petlja repeat PAGEREF _Toc31795158 \h 305.2.3.Petlja while PAGEREF _Toc31795159 \h 315.2.4.Petlja for PAGEREF _Toc31795160 \h 315.2.5.Kori?tenje programskih petlji u jeziku R PAGEREF _Toc31795161 \h 326.Funkcije u jeziku R PAGEREF _Toc31795162 \h 336.1.Ugra?ene funkcije PAGEREF _Toc31795163 \h 336.1.1.Paketi i staza pretrage PAGEREF _Toc31795164 \h 336.1.2.Dohvat pomo?i PAGEREF _Toc31795165 \h 346.1.3.Klasi?ne, primitivne i interne funkcije PAGEREF _Toc31795166 \h 356.2.Korisni?ki definirane funkcije PAGEREF _Toc31795167 \h 376.2.1.Sintaksa pisanja funkcije PAGEREF _Toc31795168 \h 376.2.2.Princip kopiranja-kod-izmjene (engl. copy-on-change) PAGEREF _Toc31795169 \h 396.2.3.Anonimne funkcije PAGEREF _Toc31795170 \h 417.Objekti u jeziku R PAGEREF _Toc31795171 \h 427.1.Razli?iti objektni modeli jezika R PAGEREF _Toc31795172 \h 427.1.1.Pregled objektnoga modela S3 PAGEREF _Toc31795173 \h 427.1.2.Generi?ke funkcije PAGEREF _Toc31795174 \h 447.2.Stvaranje vlastitih konstruktorskih i generi?kih funkcija PAGEREF _Toc31795175 \h 457.2.1.Konstruktorske funkcije PAGEREF _Toc31795176 \h 457.2.2.Vlastite generi?ke funkcije PAGEREF _Toc31795177 \h 467.3.Dodatni zadaci za vje?bu PAGEREF _Toc31795178 \h 478.Deklarativne programske petlje PAGEREF _Toc31795179 \h 498.1.Porodica funkcija apply PAGEREF _Toc31795180 \h 498.1.1.Op?enito o porodici funkcija apply PAGEREF _Toc31795181 \h 498.1.2.Funkcija apply PAGEREF _Toc31795182 \h 508.1.3.Funkcija lapply PAGEREF _Toc31795183 \h 528.1.4.Funkcija sapply PAGEREF _Toc31795184 \h 548.1.5.Ostale funkcije iz porodice apply PAGEREF _Toc31795185 \h 568.2.Alternativa funkcijama iz porodice apply PAGEREF _Toc31795186 \h 568.2.1.Paket purrr PAGEREF _Toc31795187 \h 568.2.2.Paket plyr PAGEREF _Toc31795188 \h 579.U?inkovito programiranje i upravljanje podatkovnim skupovima PAGEREF _Toc31795189 \h 589.1.Operator cjevovoda PAGEREF _Toc31795190 \h 589.1.1.Kori?tenje operatora cjevovoda PAGEREF _Toc31795191 \h 589.1.2.Operator cjevovoda i drugi operatori PAGEREF _Toc31795192 \h 609.2.U?inkovito upravljanje podatkovnim skupovima PAGEREF _Toc31795193 \h 619.2.1.Paket dplyr PAGEREF _Toc31795194 \h 619.2.2.Odabir redaka PAGEREF _Toc31795195 \h 649.2.3.Odabir stupaca PAGEREF _Toc31795196 \h 659.2.4.Agregacija i grupiranje PAGEREF _Toc31795197 \h 6710.Zaklju?ak PAGEREF _Toc31795198 \h 7010.1.Dodatni zadaci za vje?bu PAGEREF _Toc31795199 \h 72UvodOsnovne informacijeU te?aju Osnove programiranja u R-u (S760) obra?uje se jezik R s programerskog stajali?ta. Polazniku se pru?a uvid u osnovne elemente jezika R uz obrazlo?enje njihovih specifi?nosti u odnosu na druge programske jezike. Posebna pa?nja posve?ena je principima vektorizacije i recikliranja, te razli?itim na?inima kori?tenja indeksnih vektora za u?inkovito upravljanje skupovima podataka. Tako?er se polaznike upoznaje s funkcionalnom orijentirano??u jezika R i njezinim u?inkovitim kori?tenjem u pisanju vlastitoga programskog k?da. Obra?uju se razli?iti tipovi funkcija, na?ini stvaranja vlastitih funkcija te daju savjeti o tome kako izbje?i klasi?ne zamke kod pisanja programskoga k?da u R-u. Kona?no, polazniku se daje kratki osvrt na neke od popularnijih dodatnih paketa jezika R koji omogu?uju pisanje ?istog, jednostavnog i preglednog programskog k?da.Te?aj je namijenjen studentima, djelatnicima visokih u?ili?ta i javnih instituta, zaposlenicima tvrtki i institucija te ostalim zainteresiranima.Za poha?anje ovoga te?aja potrebno je poznavanje osnova rada na ra?unalu i operacijskom sustavu MS Windows te poznavanje osnova rada na Internetu. Minimalno iskustvo u programiranju je prednost.U ovom su priru?niku naredbe pisane proporcionalnim slovima (na primjer, naredba install.packages()).Sintaksa naredbi pisana je proporcionalnim slovima te komentarima za dijelove koje program ne izvodi: >library(help = "base") #pomo? za paket base.Gradivo je uglavnom obra?eno kroz niz primjera i vje?bi. Rje?enja vje?bi i rezultati izvo?enja programskih naredbi dani su u interaktivnim prozorima (HTML ina?ica) ili na kraju priru?nika (PDF ina?ica).Ovaj priru?nik predvi?a kori?tenje elektroni?kih radnih bilje?nica koje uz njega ?ine nedjeljivu cjelinu.Osnovno o jeziku RR – programsko okru?enje za statisti?ke metode, vizualizaciju, eksploratornu i dubinsku analizu podatakaU dana?nje doba postoji vrlo bogata ponuda razli?itih programskih jezika. Za razliku od jezika koju su ciljano dizajnirani kao “jezici op?enite namjene”, kao ?to su Java, C++ ili Python, postoje i jezici ?iji je dizajn usredoto?en na to?no odre?enu svrhu. Jezik R primjer je ovakvoga jezika – iako sadr?i sve nu?ne elemente prema kojima bismo ga mogli tako?er uvrstiti u skup jezika op?e namjene, njegova primarna uloga jest podr?ka za eksploratornu, statisti?ku i dubinsku analizu podatkovnih skupova, uglavnom na interaktivni na?in izvo?enjem naredbi uz pomo? programske konzole.Za jezik R ?esto se ka?e da su ga “dizajnirali statisti?ari za statisti?are”. Ako pojam “statisti?ar” zamijenimo ?irim pojmom “podatkovnog analiti?ara” i uzmemo u obzir domensku orijentiranost jezika onda ovu izjavu mo?emo interpretirati u pozitivnom smislu, da su dizajneri jezika R ljudi koji razumiju potrebe analiti?ara i koji su jezik oblikovali upravo kako bi istima rad u?inili ?to lak?im i u?inkovitijim. No, izjavu je lako interpretirati i u smislu da ovo nije jezik smi?ljen “od programera za programere”, tj. da u?enjem jezika R moramo biti spremni na ru?enje odre?enih konvencija i predrasuda te prihva?anje ?injenice da “R-ovski” pristup programiranju nije nu?no u skladu s pristupom kojim bismo se koristili u nekom “klasi?nijem” programskom jeziku. R je jezik koji primarno ?eli omogu?iti korisniku/analiti?aru postizanje rezultata na lak, brz i fleksibilan na?in. Dizajn osnovnih tipova podataka, programskih struktura i funkcija odra?ava ovu filozofiju. Postoje jasni razlozi za?to se jezik R nametnuo kao de facto standard u podru?ju podatkovne znanosti te za?to je toliko dobro prihva?en i od strane korisnika ?ija struka nije primarno programerska. No, za u?inkovito svladavanje R-a vrlo je bitno odabrati u?inkovit na?in u?enja ovoga jezika.Na?ini u?enja R-aPosebnosti jezika R mogu uzrokovati pote?ko?e kod po?etnika koji se priklanjaju dvama – podjednako pogre?nim pristupima u?enju ovoga jezika. Prvi je da se R-u pristupa kao jeziku op?e namjene te da ga se poku?ava nau?iti “klasi?nom” metodologijom u?enja programskih jezika, upoznavaju?i njegove elemente, programske strukture, principe pisanja progresivno slo?enijih programa i sl. Ovakav na?in u?enja R-a nije nemogu? jer R sadr?i sve nu?ne elemente jezika op?e namjene te ga je i mogu?e koristiti za primjene koje nisu usko povezane s podatkovnom znanosti. Problem nastaje ako se tijekom u?enja sustavno zanemaruje orijentiranost R-a prema analizi podataka. Razdru?ivanjem elemenata R-a kao programskoga jezika i njegove svrhe nai?i ?emo na niz prividnih nelogi?nosti i nekonvencionalnih elemenata koji su te?ko obja?njivi ako ne razmi?ljamo u kontekstu upotrebe istih u okvirima podatkovne analize, kada oni naj?e??e postaju logi?ni i jasni. Na primjer, ve?ina programskih jezika za prvi indeks elemenata nekoga skupa koristi broj 0, tj. prosje?an programer prirodno o prvom elementu razmi?lja kao o “nultom” usprkos pote?ko?ama koje ovo potencijalno uzrokuje. R u potpunosti zaobilazi ovu konvenciju i po?inje enumeraciju ?lanova nekoga skupa s 1. Za?to? Zato ?to je analiti?aru puno prirodnije i prakti?nije razmi?ljati o “prvom retku tablice” nego “nultom” te je u potpunosti rastere?en potrebe “mentalnog posmaka za 1”, toliko prirodne u programerskom svijetu.Drugi pogre?an na?in u?enja jezika R, kojem naj?e??e te?e ljudi bez programerskog iskustva, jest onaj koji koristi dijametralno suprotni pristup, a to je u?enje samo onih elemenata jezika R orijentiranih neposrednoj svrsi njegovoga kori?tenja. Ta svrha mo?e biti, na primjer, u?itavanje skupa podataka iz datoteke, crtanje neke vizualizacije ili izrada linearnoga prediktivnog modela. Zanemarivanjem programskih elemenata i internoga na?ina funkcioniranja jezika R isti se tako svodi na niz naredbi koje korisnik u?i napamet (ili zapisuje na “?alabahter”) i koji onda predstavlja jedini i isklju?ivi na?in kori?tenja ovoga jezika. Ovo prakti?ki reducira R na “aplikaciju bez su?elja” koja time postaje zbunjuju?a i manje atraktivna alternativa nekom grafi?kom analiti?kom alatu. Usprkos domenskoj orijentiranosti, jezik R je i dalje programski jezik i iskori?tavanje njegovoga punog potencijala zahtjeva svladavanje vje?tine programiranja, kao i razumijevanje svih njegovih elemenata, a ne samo ograni?ene kolekcije “korisnih” funkcija.Ideja ovoga te?aja jest prvenstveno na?i kompromis izme?u ova dva “ekstremna” pristupa u?enja R-a te pokazati kako programerski pristup u?enju uz prihva?anje domenske orijentiranosti jezika mo?e uvelike olak?ati svladavanje R-a te dugoro?no omogu?iti lak?i i u?inkovitiji rad uz pisanje jasnoga i preglednoga programskog k?da. Posebna pa?nja posvetit ?e se specifi?nostima jezika te ?e se neke njegove neobi?nije strane demistificirati i razjasniti u kontekstu kori?tenja istih u konkretnim primjerima i zadacima. Kona?no, dio te?aja posvetit ?e se i tome kako izbje?i klasi?ne po?etni?ke gre?ke i zablude koje toliko ?esto stvaraju krivu percepciju u ovom programskom jeziku.Pregled sadr?aja te?ajaPrvi dan posvetit ?emo osnovnim elementima jezika R – tipovima podataka i podatkovnim strukturama. Posebno ?emo se usredoto?iti na fundamentalne elemente R-a, principe vektorizacije i recikliranja te dizajna indeksnih vektora, koji su klju?ni za kvalitetno upoznavanje s jezikom i njegovo u?inkovito kori?tenje.Drugi dan bit ?e uglavnom usmjeren prema funkcijama kako onim ugra?enim ili dostupnim kroz raznorazne dodatne pakete tako i onima koje korisnik mo?e samostalno definirati. Bit ?e re?eno i nekoliko rije?i o paradigmama programskih jezika, osobito funkcionalnom programiranju, koje predstavlja bitan segment u?inkovitoga rada s jezikom R. Obradit ?e se i elementi kontrole programskoga toka te razjasniti za?to pojedini od njih (osobito programske petlje) nisu toliko prisutni ni po?eljni u jeziku R koliko u drugim programskim jezicima.Kona?no, tre?i dan ?emo se usredoto?iti na najpopularnije funkcije i dodatne pakete posebno dizajnirane za to da korisniku olak?aju i ubrzaju kori?tenje i razumijevanje jezika R. Jedan od bitnih aspekata ovoga jezika jest i vrlo aktivna R zajednica koja svojim doprinosima unapre?uje iskustvo rada s jezikom svim njegovim korisnicima. Kao rezultat ovoga nastao je niz paketa koji doslovno redefiniraju na?in kori?tenja R-a i koje veliki dio R zajednice smatra neizostavnim, obaveznim dijelom jezika.Krenimo sada od po?etka i pogledajmo osnovne elemente jezika – elementarne tipove podataka, varijable i temeljne podatkovne strukture.Osnovni tipovi podataka i podatkovne struktureOsnovni tipovi podatakaOsnovni (elementarni ili atomarni) tipovi podataka nekoga programskog jezika predstavljaju temeljne vrste informacije kojima neki jezik mo?e upravljati. Ovi tipovi su danas uglavnom standardizirani i svode se na na?in reprezentacije podataka logi?koga, numeri?koga ili znakovnoga tipa.Pregled osnovnih tipovaR poznaje ?est osnovnih tipova podataka:tipizvorni naziv tipaprimjerilogi?kilogicalTRUE, FALSE ili T, Fcjelobrojniinteger2L, 5L, 123456789Lrealnidouble4, 6, 3.14, 2e5kompleksnicomplex5 + 2i, 7 + 1iznakovnicharacter"A", "B", "Pero", "ABCDEFGHijklmnoPQRSTUVwyz"bajtovnirawas.raw(2), charToRaw("1")Cjelobrojni i realni tip podatka zajedno se svrstavaju u takozvani “numeri?ki” tip podatka (engl. numeric). Razlika izme?u njih jest u tome ?to cjelobrojni pohranjuje cijele brojeve s potpunom precizno??u, ali ima ograni?eniji opseg i nema mogu?nost pohrane brojeva koji sadr?e decimale. Realni tip sadr?i odre?enu nepreciznost koja je rezultat ?injenice da postoji beskona?an broj realnih brojeva, ali kona?an broj bitova u registru, onome u koji pohranjujemo realni broj. U velikoj ve?ini slu?ajeva u radu s R-om o ovome uop?e ne moramo brinuti – ako to eksplicitno ne zatra?imo (slovo L!), R ?e numeri?ku informaciju pohraniti u realnom tipu, a nepreciznost ?e nam smetati samo ako se koristimo brojevima s vi?e od 16 znamenaka, ?to je rijedak slu?aj.Dakle, za prakti?ne svrhe uglavnom su nam zanimljivi samo logi?ki, znakovni i realni tip podatka (koji ?emo zbog jednostavnosti zvati “numeri?ki”). Cjelobrojni, kompleksni i “sirovi” (bajtovni) tip mo?emo zanemariti, osim ako smo suo?eni s vrlo specifi?nom situacijom gdje su isti potrebni.Pojam varijablePodatke pohranjujemo u imenovane spremnike zvane “varijable”. R je takozvani “slabo tipizirani” jezik (engl. weakly typed), ?to zna?i da varijable mo?emo slobodno definirati, a da ne navedemo unaprijed koji tip podatka pohranjuju, a istu varijablu mo?emo vrlo lako “preusmjeriti” da ozna?ava neki novi tip podatka.Primjer 1: Inicijalizacija varijabli razli?itih tipova# inicijaliziramo varijable a, b i c na sljede?i na?ina <- 5b <- TRUEc <- 14Lc <- "Pero"# funkcija `cat` - "sirovi" ispis, samo "izbacuje" sadr?aj parametara na zasloncat(a, b, c)## 5 TRUE PeroU primjeru smo inicijalizirali tri varijable, a, b i c. Vidimo da tipove podataka nismo morali navoditi, ve? je R automatski dodijelio tip varijabli ovisno o tipu podatka koji smo joj pridru?ili. Isto tako, mo?emo vidjeti da smo varijablu c prvo inicijalizirali na cjelobrojni tip, da bi joj potom pridru?ili znakovni tip. Ovim vidimo da je varijabla zapravo samo svojevrsni “pokaziva?” na informaciju u radnoj memoriji. Cjelobrojni podatak 14L vi?e nije dohvatljiv i predstavlja “sme?e” – R ima posebnu dretvu zvanu “sakuplja? sme?a” koja periodi?ki provjerava postoji li ovakva nedohvatljiva informacija i ako da, onda istu trajno bri?e ozna?avaju?i taj dio memorije kao slobodan.(NAPOMENA: jedan od ?e??ih problema u radu s R-om jest pojava nedostatka radne memorije, koja se mo?e dogoditi kod rada s velikim podatkovnim skupovima, a koja rezultira usporavanjem izvo?enja programa ili njegovim ru?enjem. ?esto je uzrok ovoga neiskustvo analiti?ara/programera, ?iji programski k?d stvara previ?e “kopija” podatkovnoga skupa koje se jednokratno koriste i odmah ?ine zalihosnima, ali koje sakuplja? sme?a ne stigne na vrijeme osloboditi. Tijekom ovoga te?aja nau?it ?emo kako izbje?i ovu pojavu.)Provjera tipa podatkaTip podatka (tj. varijable) mo?emo provjeriti uz pomo? funkcija typeof ili class. Poku?ajmo upotrijebiti ove funkcije nad varijablama a, b i c koje smo inicijalizirali u prethodnom primjeru.Vje?ba 1: Funkcije typeof i class# primijenite funkciju `typeof` redom na varijable a, b i c# primijenite funkciju `class` redom na varijable a, b i cRazlika izme?u typeof i class mo?da nije o?ita. Funkcija typeof odgovara na pitanje “Kako je ovaj podatak pohranjen u memoriji?”, dok nam funkcija class otkriva odgovor na pitanje “?to ovaj podatak predstavlja?” (to?nije: “Koje je klase ovaj objekt?”). U praksi ?emo gotovo uvijek koristiti funkciju class, jer je – kao ?to ?emo kasnije nau?iti – ve?ina kompleksnijih objekata u R-u zapravo pohranjena kao liste, tako da nam tip podatka koji vra?a typeof ne?e biti previ?e koristan.U gornjem primjeru, varijable smo inicijalizirali s jednostavnim, elementarnim vrijednostima. U nastavku ?emo se upoznati sa slo?enijim podatkovnim strukturama koje predstavljaju temeljni dio jezika R.Slo?ene podatkovne struktureKao ?to ?emo vidjeti u nastavku, jedan od ?e??ih uzoraka koji susre?emo u R-u jest ?injenica da radimo vi?e stvari odjednom. Ovo je nu?an nusprodukt ?injenice da je R dizajniran za potrebe analize velikih podatkovnih skupova – analiti?ar se ?e??e orijentira na obradu podatkovnoga skupa u cijelosti nego ?to se usredoto?uje na jedan podatak unutar skupa. U skladu s time, umjesto da inicijaliziramo varijable u koje pohranjujemo jedan podatak, puno ?e??e ?emo upravljati varijablama koje pohranjuju kolekciju ili skup podataka. Ovisno o tipu i strukturi podataka koje pohranjujemo, R nudi ?etiri temeljne slo?ene podatkovne strukture: vektor, matricu, listu i podatkovni okvir.VektorVektor je jednodimenzionalna ure?ena kolekcija elemenata istoga tipa. Novi vektor (koji ima vi?e od jednog elementa) stvaramo uz pomo? funkcije c (od engl. combine).Primjer 2: Inicijalizacija vektora# numeri?ki vektorm <- c(1, 2, 3, 4, 5) # logi?ki vektorv <- c(T, F, T)# znakovni vektorimena <- c("Ivo", "Pero", "Ana")# kori?tenje samog imena varijable pokrenut ?e tzv. `autoprint`# isti rezultat postigli bismo i eksplicitnim pozivom funkcije `print`mvimena## [1] 1 2 3 4 5## [1] TRUE FALSE TRUE## [1] "Ivo" "Pero" "Ana"Ako stvaramo novi vektor s elementima razli?itih tipova podataka, R ?e sve elemente automatski pretvoriti u “najja?i” tip, ?to ?e na kraju postati i tip samoga vektora (termin “ja?i” tip u ovom kontekstu ozna?ava mogu?nost tipa da pohrani svu informaciju “pohranjenu u slabiji tip”, a u op?enitom slu?aju pretvorba ide u smjeru logi?ki -> numeri?ki -> znakovni tip).Vje?ba 2: Stvaranje vektora# stvorite novi vektor x s ?etiri proizvoljna elementa sljede?ih tipova: # logi?ki, realni, znakovni i cjelobrojni# ispi?ite na zaslon sadr?aj vektora i njegovu klasuFunkcijom c mo?emo tako?er i vi?e vektora spojiti u jedan:Primjer 3: Spajanje vektora# inicijaliziramo vektore a, b i ca <- c(1, 2, 3)b <- c(4, 5) # uo?ite – varijablu smijemo nazvati c usprkos tome ?to postoji funkcija c()c <- c(6, 7, 8) d <- c(a, b, c) # d je sada c(1, 2, 3, 4, 5, 6, 7, 8)d## [1] 1 2 3 4 5 6 7 8Pored funkcije c, R nudi i dodatne pogodne na?ine stvaranja novih vektora:: – operator “raspona” (engl. range), pri ?emu dajemo raspon od gornje do donje granice, obje uklju?iveseq – funkcija sekvence (engl. sequence), radi sli?no operatoru raspona, ali s dodatnim mogu?nostimarep – funkcija repliciranja (engl. replicate), ponavlja zadane elemente zadani broj puta.Primjer 4: Stvaranje vektora – pomo?ne funkcije i operatori1:5rep(c(1, 2, 3), times = 3)rep(c(1, 2, 3), each = 3)seq(1, 5, by = 0.5)## [1] 1 2 3 4 5## [1] 1 2 3 1 2 3 1 2 3## [1] 1 1 1 2 2 2 3 3 3## [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0Operator [Elementima vektora pristupamo preko indeksnog operatora [, uz pomo? kojega mo?emo i mijenjati elemente vektora:Primjer 5: Pristup elementima vektora# zadan je vektor aa <- c(2, 4, 6)a[1] # ispisuje vrijednost 2a[2] <- 5 # element na 2. mjestu postaje 5a[5] <- 7 # na 5. mjesto dodaje se 7, a "rupa" se popunjava s NAa## [1] 2## [1] 2 5 6 NA 7Uo?ite jednu pomalo neuobi?ajenu ?injenicu – prvi element vektora u R-u ima indeks 1, a ne 0! Ovo je bitna razlika u odnosu na indeksiranje elemenata u drugim programskim jezicima. Razlog ove specifi?nosti je jednostavan – R se primarno smatra jezikom za analizu podataka, osobito u tabli?nom obliku, a u praksi je puno lak?e brojati retke ili stupce redoslijedom kojim se pojavljuju u podatkovnom skupu nego raditi “posmak za 1”.Rekli smo da je vektor “jednodimenzionalna” podatkovna struktura – ako gledamo vektor od n numeri?kih elemenata, on zapravo predstavlja pravac u n-dimenzionalnom prostoru. R nudi i podatkovne strukture za pohranu podataka u dvije, ali i vi?e dimenzija. Ove strukture zovu se matrice i polja.Matrice i poljaMatrice i polja su, jednostavno re?eno, vi?edimenzionalni vektori. Matrica (engl. matrix) je tako vektor s dvije dimenzije, tj. vektor koji elemente smje?ta u “retke” i “stupce”. Polje (engl. array) je vektor s tri ili vi?e dimenzija. Dok se matrice relativno ?esto koriste u praksi, polja su ipak ne?to vi?e ograni?ena na posebne scenarije. Zbog ove ?injenice, u ovom poglavlju uglavnom ?emo se baviti matricama, iako se prikazani koncepti vrlo lako poop?uju na polja.Postoji nekoliko na?ina stvaranja nove matrice:uz pomo? funkcije matrix kojoj proslje?ujemo jednodimenzionalni vektor i ?eljeni broj redaka i stupaca kroz parametre nrow i ncol“ru?nim” postavljanjem dimenzija jednodimenzionalnoga vektora uz pomo? funkcije dim i pridru?ivanja dvoelementnoga numeri?kog vektora s dimenzijama matrice“lijepljenjem” jednodimenzionalnih vektora koji predstavljaju retke ili stupce nove matrice uz pomo? funkcija rbind (engl. row bind) i cbind (engl. column bind).Vje?ba 3: Funkcija matrix# zadan je vektor xx <- 1:12# uz pomo? funkcije `matrix` i vektora x stvorite matricu s 3 retka i 4 stupca# ispi?ite rezultat na zaslon# ponovite postupak, ali pozivu funkcije dodajte parametar `byrow = T`# ispi?ite rezultat na zaslon i usporedite s prethodnim rezultatomVje?ba 4: Funkcije rbind i cbind# zadani su vektori a, b i ca <- 1:4b <- 5:8c <- c(0,0)# stvorite matricu m u kojoj ?e vektori a i b biti stupci# dodajte novi redak na vrh matrice m s elementima vektora c# ispi?ite matricu mElementima matrice tako?er pristupamo preko indeksnog operatora [. Razlika je samo u tome ?to ?emo kod indeksiranja matri?nih elemenata (uglavnom) koristiti dvodimenzionalnu referencu – indeks retka i indeks stupca, odvojene zarezom. Ako ?elimo cijeli redak ili cijeli stupac, jednostavno ispustimo indeks te dimenzije (npr. m[2,] zna?i “drugi redak”).Vje?ba 5: Indeksiranje matri?nih elemenata# zadana je matrica mm <- matrix(1:12, nrow = 3, ncol = 4, byrow = T)# ispi?ite:# element u 2. retku, 3. stupcu# cijeli 3. redak# cijeli 4. stupacPolja (engl. array) su zapravo vi?edimenzionalno pro?irenje koncepta matrice. U praksi ih relativno rijetko susre?emo osim u specifi?nim slu?ajevima gdje ciljano radimo s vi?edimenzionalnim strukturama, na primjer modeliranje neke trodimenzionalne podatkovne strukture ili rje?avanje vi?edimenzionalnih problema iz linearne algebre. Zbog ove ?injenice, ovdje ih ne?emo posebno obra?ivati, no ako se pojavi potreba za njihovim kori?tenjem, dovoljno se prisjetiti da se njima upravlja analogno matricama (npr. indeksiranje svake dimenzije zasebno, odvojeno zarezom).ListeLista je element programskoga jezika R koji se koristi kao “univerzalni spremnik” bilo kakvih podataka. Za razliku od vektora (tj. od pojma vektora kakvog smo ga inicijalno definirali), lista mo?e sadr?avati razli?ite tipove podataka ili, ?e??e, skupove razli?itih tipova podataka.Listu stvaramo uz pomo? funkcije list kojoj dodajemo niz parova naziva elemenata i njihovih sadr?aja. Ovi elementi mogu biti bilo ?to, pa ?ak i druge liste.Primjer 6: Funkcija listmojaLista <- list(a = 1, b = 2:100, c = list(x = 1, y = 2))Poku?ajmo stvoriti vlastitu listu u sljede?oj vje?bi.Vje?ba 6: Stvaranje liste# stvorite novu listu naziva `svastara` koja ?e imati sljede?e elemente# element naziva `brojevi` s cijelim brojevima od 1 do 3# element naziva `slova` sa slovima "A" i "B"# bezimeni element s logi?kim vektorom `c(T,F)`# element naziva `imena` s imenima "Ivo" i "Ana"# ispi?ite listu `svastara`Uo?ite da lista zadr?ava poredak elemenata – element bez imena prikazan je indeksom 3.Funkcija str (engl. structure) omogu?uje nam uvid u svojstva i sadr?aj liste bez ispisivanja cijele liste.Vje?ba 7: Struktura liste# ispi?ite strukturu liste `svastara`Elementima liste uglavnom pristupamo na dva na?ina:uz pomo? operatora [[, tj. operatora “dvostruke uglate zagrade”uz pomo? operatora $ (tzv. “string” operator).Vje?ba 8: Operator [[# ispi?ite prvi element liste svastara kori?tenjem operatora [[# provjerite njegovu klasuNavedeni operator naj?e??e koristimo kako bismo dohvatili odabrani element liste koji definiramo brojem ili (ako ima ime) nazivom elementa. Kod ovakvog dohvata moramo koristiti kombinaciju simbola lista[["ime_elementa"]] koja je pone?to nespretna za tipkanje. Zbog toga R nudi alternativni na?in pristupa elementima liste prema nazivu kori?tenjem operatora $, tj. lista$ime_elementa.Vje?ba 9: Operator $# ispi?ite element naziva `slova` liste svastara# kori?tenjem operatora [[# ispi?ite isti element kori?tenjem operatora $Za kraj, nau?imo dodati element u listu. Ovo je najjednostavnije u?initi kori?tenjem ve? spomenutog operatora $, kao na primjer, lista$noviElement <- noviElement. Element bri?emo tako da mu dodijelimo vrijednost NULL.Vje?ba 10: Dodavanje i brisanje elemenata liste# listi `svastara` dodajte element `parniBrojevi` koji sadr?i# sve parne brojeve od 1 do 100# obri?ite tre?i element liste# ispi?ite listu `svastara`Podatkovni okviri (Data frames)Podatkovni okvir predstavlja vjerojatno najpopularniju i naj?e??e kori?tenu podatkovnu strukturu jezika R, ?to proizlazi iz ?injenice da se radi o objektu koji reprezentira podatkovni skup koji namjeravamo analizirati. Drugim rije?ima, podatkovni okvir je objekt sli?ne funkcije kao tablica u Microsoft Excelu ili relacijskoj bazi podataka. Gotovo svaka “sesija” u R-u svodi se na manipuliranje podatkovnim okvirima – no, dok u Excelu tablicom upravljamo uz pomo? grafi?koga su?elja, a u bazi uz pomo? upitnoga jezika SQL, u R-u podatkovni okvirima upravljamo gotovo isklju?ivo programski.Uzmimo za primjer sljede?u tablicu:pbrnazivMjestaprosjPlacaKnbrojStanovnikaprirez10000Zagreb6359.007900171851000Rijeka5418.001283841521000Split5170.001671211031000Osijek4892.00841041320000Dubrovnik5348.002843410Ovdje se radi o podatkovnom skupu koji sadr?ava odre?ene (ne nu?no a?urne) parametre vezane za gradove u Republici Hrvatskoj.Podatkovni okvir naj?e??e stvaramo na jedan od dva na?ina:programski, uz eksplicitno navo?enje sadr?aja?itanjem iz vanjske datoteke uz pomo? funkcija read.table / read.csv / read.csv2.U nastavku ?emo isprobati kori?tenje obaju na?ina.Vje?ba 11: Programsko stvaranje podatkovnog okvira#zadani su sljede?i vektoripbr = c(10000, 51000, 21000, 31000, 2000)nazivMjesta = c("Zagreb", "Rijeka", "Split", "Osijek", "Dubrovnik")prosjPlacaKn = c(6359., 5418., 5170., 4892., 5348.)brojStanovnika = c(790017, 128384, 167121, 84104, 28434)prirez = c(18, 15, 10, 13, 10)# uz pomo? funkcije `data.frame` i gornjih vektora stvorite podatkovni okvir `mjesto`# koristite istu sintaksu kao kod stvaranja liste# elemente liste nazovite imenima varijabli# ispi?ite podatkovni okvir `mjesto`Naziv CSV zna?i “comma separated values”, tj. “podaci odvojeni zarezom”. Prvi redak datoteke obi?no sadr?i nazive stupaca. Ovako oblikovane podatke lako ?itamo uz pomo? funkcije read.csv kojoj dajemo sljede?e parametre:stazu do CSV datotekeparametar stringsAsFactors = FALSE.Potonji parametar bitan je za spre?avanje takozvanoga “faktoriziranja”, tj. kategoriziranja znakovnih stupaca, ?to je postupak koji je bolje obaviti “ru?no” (nakon u?itavanja u podatkovni okvir) kako bismo izbjegli eventualne gre?ke.NAPOMENA: Problem CSV datoteka jest taj ?to one koriste zarez kao razdvojnik (engl. delimiter) elemenata zapisa, ?to predstavlja problem na govornim podru?jima koje kao standard, umjesto decimalne to?ke, koriste upravo “decimalni zarez”. Zbog ove ?injenice postoji i “alternativni” CSV standard koji kao razdvojnik koristi “to?ku-zarez”. Budu?i da smo stanovnici takvoga govornog podru?ja, velike su ?anse da ?emo se susresti s takvom “alternativnom” CSV datotekom; u tom slu?aju bismo umjesto funkcije read.csv trebali koristiti funkciju read.csv2, ili read.table koja je op?enitija funkcija za ?itanje podataka iz datoteke i omogu?uje fino pode?avanje niza parametara (zapravo su read.csv i read.csv2 izvedenice funkcije read.table).Za sljede?u vje?bu bit ?e potrebno u radnoj mapi stvoriti CSV datoteku sljede?ega sadr?aja:pbr,nazivMjesta,prosjPlacaKn,brojStanovnika,prirez10000,Zagreb,6359.00,790017,18 51000,Rijeka,5418.00,128384,1521000,Split,5170.00,167121,1031000,Osijek,4892.00,84104,13 20000,Dubrovnik,5348.00,28434,10Vje?ba 12: ?itanje podataka iz CSV datoteke# u?itajte podatke iz datoteke `mjesto.csv` # podatke spremite u podatkovni okvir `mjesto2` # ispi?ite podatkovni okvir `mjesto2` Jedna od zgodnih stvari kod podatkovnih okvira jest ta ?to se oni pona?aju i kao matrice (dvodimenzionalno indeksiranje) i kao liste. Ovo proizlazi iz ?injenice da su podatkovni okviri zapravo ni?ta drugo nego liste, samo s ograni?enjem da svi elementi moraju imati istu duljinu. Ovo ograni?enje zapravo diktira “tabli?nu” strukturu podatkovnog okvira, ?to nam daje opciju da isti vizualiziramo kao dvodimenzionalnu tablicu te da s njom upravljamo kroz koncepte “redaka” i “stupaca”.Upravljanje podatkovnim okvirima predstavlja temelj rada s jezikom R i najva?niju stepenicu za njegovo jednostavnije i u?inkovito kori?tenje. Zbog toga je vrlo va?no ulo?iti trud i vrijeme za svladavanje nekih osnovnih principa koji ?e rad s podatkovnim okvirima (ali i ostalim podatkovnim strukturama) u?initi ?to transparentnijim i razumljivijim, bez pojave “neobi?noga” pona?anja i “neo?ekivanih” rezultata. Konkretno, to su principi vektorizacije i recikliranja te konstrukcije indeksnih vektora, a koje ?emo nau?iti u nastavku.Vektorizacija i indeksni vektoriPrincipi vektorizacije i recikliranja“Sve je vektor”U prethodnom dijelu upoznali smo osnovne tipove podataka jezika R te slo?ene podatkovne strukture. Poku?ajmo sada odgovoriti koja je od varijabli u sljede?em primjeru “vektor”.Primjer 7: Vektoria <- 4b <- "Ivana"c <- c(1, 2, 3, 4, 5)d <- list(a = 1:10, b = LETTERS, c = c(T,F)) # ?to je LETTERS? Ispi?imo to!e <- matrix(1:9, 3, 3)Poku?ajte prvo intuicijom odgovoriti na ovo pitanje, a potom provjerite ispravnost pretpostavke uz pomo? funkcije is.vector.Do?li smo do jednog vrlo va?noga, i mo?da pone?to neo?ekivanoga zaklju?ka – sve gornje varijable su vektori, osim varijable e (iako je i ona zapravo vektor, usprkos tomu ?to ju funkcija is.vector ne priznaje kao takvu, ?to je zapravo rezultat ?injenice da ta funkcija ne provjerava da li je ne?to vektor, ve? ima li dodatne atribute pored names, tako da ju zapravo ne bismo ni trebali koristiti).Dakle, ?ak i broj 4 te niz znakova "Ivana" nisu ni?ta drugo nego jedno?lane “kolekcije” elemenata. ?to ovo konkretno zna?i? Postoji jedan ?esto spominjani princip jezika R, koji glasi “sve je vektor”. Iako ovo ba? nije doslovno to?na izjava, ona otkriva jednu vrlo va?nu ?injenicu, a to je da je ve?ina varijabli kojima ?emo se koristiti u jeziku R zapravo vektor, ?to zna?i da ?e imati sli?no pona?anje i koristiti sli?ne obrasce upravljanja!Matrica kao vektorIako smo rekli da funkcija is.vector ne?e prepoznati matricu kao vektor, to ne mijenja ?injenicu da matrica nije ni?ta drugo nego jednodimenzionalni vektor s dodanim atributom dim koji programeru omogu?uje da ga koristi kao dvodimenzionalnu strukturu. Drugim rije?ima, dvodimenzionalna struktura matrice je samo prividna, ona je tu strogo zbog prakti?nosti i lak?ega kori?tenja jezika R za potrebe matri?nih izra?una. Ovo je zapravo uobi?ajena pojava u programskim jezicima – vi?edimenzionalne strukture se zapravo “raspli?u” kako bi se uop?e mogle pohraniti u jednodimenzionalnu memoriju ra?unala, a vi?edimenzionalno indeksiranje se uz pomo? poznate dimenzionalnosti “ispod haube” prera?unava u jednodimenzionalni indeks.U ovo se mo?emo uvjeriti u sljede?oj vje?bi.Vje?ba 13: Matrica kao vektor# zadana je matrica mm <- matrix(1:12, nrow = 3, ncol = 4)# ispi?ite matricu m# ispi?ite 2. element u 4. stupcu# ispi?ite 11. element (jednodimenzionalno indeksiranje!)Za?to nam je ovo korisno? Poznavanje interne strukture podataka nam mo?e olak?ati rad s istima – ako znamo da je matrica zapravo pohranjena “po stupcima” onda mo?emo i razumjeti za?to mo?e do?i do izrazitih usporavanja u radu s velikim matricama ako podatke obra?ujemo “po retcima”. Isto tako, kao ?to ?emo vidjeti u nastavku, podatkovni okviri se u izvjesnoj mjeri pona?aju kao matrice tako da i za njih vrijedi princip “virtualne dimenzionalnosti” – to ?to mi kao programeri vidimo podatke organizirane u retke, to ne zna?i da su oni zapravo bliski jedni drugima na mjestu gdje su pohranjeni.Ovo sve naravno ne zna?i da u radu s matricama (i podatkovnim okvirima) ne bismo trebali koristiti pogodnosti koje nam donosi prividna dvodimenzionalnost, ve? samo da bismo istu morali imati u vidu u trenucima kada do?e do eventualnih problema ili uspijemo prona?i zgodan na?in kako jednodimenzionalnu prirodu iskoristiti za lak?e upravljanje takvim podacima.Lista kao vektorOpravdano je postaviti pitanje – ?to je s listom? Kod same definicije liste rekli smo da ona “sadr?ava razli?ite skupove podataka”, ?to se naizgled kosi s definicijom vektora kao “jednodimenzionalne ure?ene kolekcije elemenata istoga tipa”. Obja?njenje je zapravo jednostavno – definicija nije naru?ena zato ?to lista u biti sadr?ava “niz jednoelementnih listi”. Svaki element liste je lista, ?to obja?njava ?injenicu za?to kod indeksiranja liste ne koristimo operator [ ve? [[. Budu?i da je svaki element liste opet lista, jednostruki operator bi nam vratio listu, i kod dohva?anja prvog elementa te liste opet bismo dobili listu, i tako u nedogled. Operator [[ (a tako i operator $ koji je zapravo izveden iz prethodno navedenog) zapravo zna?i “dohvati i otpakiraj” element liste.Isprobajmo ovo uz pomo? idu?e vje?be:Vje?ba 14: Lista kao vektor# zadana je lista `svastara`svastara <- list(brojevi = c(1,2,3), slova = c("A", "B"), c(T,F), imena = c("Ivo", "Ana"))# provjerite klasu drugog elementa liste `svastara`# koristite operator [# provjerite klasu drugog elementa liste `svastara`# koristite operator [[Opet, za?to nam je uop?e bitno znati da je lista zapravo vektor? Zato ?to to zna?i da u su?tini nema bitne razlike izme?u upravljanja vektorom i upravljanja listom; i vektor i lista se pona?aju jednako s gledi?ta “kolekcije elemenata” te ako razumijemo kako upravljati vektorom koji sadr?i, na primjer, jednostavne numeri?ke vrijednosti, onda iste principe mo?emo koristiti za upravljanje listama, iako su njezini elementi ?esto slo?enije strukture od “obi?nih” brojeva.Podatkovni okvir kao vektorVe? smo spomenuli da je podatkovni okvir zapravo lista, samo s elementima jednake duljine. To zna?i da je sve spomenuto za percepciju liste kao vektora primjenjivo i na podatkovni okvir, pa ?ak i rasprava o operatorima [, [[ i $ – iako ne smijemo zaboraviti ?injenicu da R omogu?uje dvodimenzionalno indeksiranje podatkovnih okvira tako da kod njih ipak ne?emo koristiti operator [[ ve? operator [ sa zarezom za razdvajanje dimenzija (?to je kod “obi?nih” lista besmisleno i neprimjenjivo).Poka?imo ovo u idu?oj vje?bi.Vje?ba 15: Podatkovni okvir kao vektor# # u?itajte podatke iz datoteke `mjesto.csv` # podatke spremite u okvir `mjesto`# ispi?ite drugi stupac (nazivMjesta) na sljede?e na?ine:# koristite operator [ i jednodimenzionalno indeksiranje# koristite operator [ i dvodimenzionalno indeksiranje# koristite operator [[ # koristite operator $ Ako ste pa?ljivo prou?ili rje?enje, mogli ste uo?iti jasnu poveznicu izme?u liste i podatkovnih okvira – operator [ uz jednodimenzionalno indeksiranje vratio nam je (jednostup?ani) podatkovni okvir, dok su svi ostali na?ini “otpakirali” informaciju i pretvorili je u obi?an znakovni vektor. Ova ?injenica nam se nekad mo?e pokazati korisnom, pogotovo ako pi?emo funkcije koje obra?uju podatkovne okvire i ?elimo da nam rezultat operacije bude okvir, a ne vektor.NAPOMENA: Razlog za?to kod operatora [ i dvodimenzionalnog indeksiranja nismo dobili podatkovni okvir ve? vektor zapravo nije “otpakiravanje” elemenata liste (to operator [ ni ne radi!), ve? ?injenica da jezik R ?esto “pojednostavljuje” rezultat. Ukoliko to ne ?elimo, mo?emo kod indeksiranja dodati parametar drop = FALSE, npr. mjesto[, 2, drop = FALSE].Mo?emo ponovo postaviti pitanje – za?to nam je bitno razumjeti internu strukturu podatkovnog okvira? Ako znamo da je okvir zapravo lista, to zna?i da se funkcije za obradu listi mogu bez problema primijeniti na podatkovne okvire (s time da moramo voditi ra?una o tome da su “elementi liste” zapravo stupci okvira). Isto tako, znaju?i da je lista zapravo vektor, opet se vra?amo na ?injenicu da funkcije za obradu vektora element po element postaju direktno primjenjive na liste, a time i na okvire. Kona?no, ve? spomenuta ?injenica kod matrica vrijedi i za okvire – obrada po stupcima je puno u?inkovitija od obrade po redcima, budu?i da se podatkovni okvir interno “raspli?e” po stupcima.Prihva?anjem principa “sve je vektor” ve? smo u?inili bitan pomak u razumijevanju principa vektorizacije i kako ga primijeniti u jeziku R. U?inimo sad korak dalje.Vektorizirane operacije i princip recikliranjaPojam vektorizacije ili bolje re?eno vektoriziranih operacija i funkcija jednostavno zna?i da se operacije rade nad vi?e elemenata odjednom. Ovo je temeljni princip kako R obra?uje podatke i klju?na prepreka za razumijevanje ovoga jezika. Budu?i da je u R-u “sve vektor”, to zna?i da su operacije koje radimo nad na?im varijablama prirodno vektorizirane, ili – jednostavnim jezikom re?eno – R-ov uobi?ajeni na?in rada jest da radi nad cijelim skupom odjednom, umjesto sa svakim elementom posebno.Dakle, ako zadamo R-u da radi neku operaciju ili funkciju nad nekim vektorom vrijednosti, R ?e funkciju ili operaciju izvesti nad svakim elementom posebno i vratiti rezultantni vektor kao rezultat. Isto tako, ako provodimo binarnu operaciju nad dva vektora, ona ?e se provesti nad “uparenim” ili “poravnatim” elementima obaju vektora (pretpostavimo za sada da su vektori jednake duljine).Vje?ba 16: Princip vektorizacije# zadani su vektori x, a i bx <- seq(-5, 5, 1)a <- 1:3b <- 4:6# pozovite funkciju `abs` za ra?unanje apsolutne vrijednosti# nad vektorom x i ispi?ite rezultat# zbrojite vektore a i b uz pomo? operatora +# i ispi?ite rezultat# pomno?ite vektore a i b uz pomo? operatora *# i ispi?ite rezultatPa?ljivo razmotrite rezultate prethodnoga zadatka. Ako je potrebno, skicirajte vektore a i b na papiru s vertikalno poslaganim elementima i uo?ite kako radi paralelno “uparivanje” elemenata. Primijetite da ovdje ne govorimo o “vektorskim operacijama” u strogom matemati?kom smislu, ve? o poravnavanju elemenata dvaju nizova i provo?enja jednostavnih operacija nad svakim od tih parova. Ovo je pogotovo o?ito u zadnjem primjeru gdje nema nikakvoga “mno?enja vektora” kako ga uobi?ajeno interpretiramo u linearnoj algebri (“skalarni produkt”), ve? se provodi jednostavno mno?enje paralelnih elemenata dvaju vektora.?to ako vektori nisu jednake duljine? R u ovom slu?aju koristi princip recikliranja.Princip recikliranja navodi da se kod nejednake duljine vektora kra?i vektor “reciklira” onoliko puta koliko je potrebno da se dostigne duljina duljega vektora. Naj?e??i scenarij kori?tenja ovoga principa su operacije u kojima je s jedne strane vektor s vi?e elemenata, a s druge strane jednoelementni vektor koji se onda reciklira za svaki element “velikoga” vektora. Ono ?to bismo trebali izbjegavati jest scenarij recikliranja gdje duljina “velikoga” vektora nije vi?ekratnik duljine “maloga” – R ?e i dalje reciklirati kra?i vektor, samo ?e ga na kraju morati “odrezati” ?to ?e rezultirati odgovaraju?im upozorenjem.Vje?ba 17: Princip recikliranja# zadani su vektori a, b i ca <- 1:4b <- c(1, 2)c <- rep(5, 3)# udvostru?ite elemente vektora a i ispi?ite rezultat# podijelite vektor a vektorom b i ispi?ite rezultat# pomno?ite vektore a i c i ispi?ite rezultatOvdje mo?emo razjasniti razliku izme?u “skalarnih” i “vektorskih” logi?kih operatora u jeziku R. Podsjetimo se, za razliku od drugih programskih jezika, R nudi dvije ina?ice logi?kih operatora “i” i “ili”:skalarni: && i ||vektorski: & i |Razlika je u sljede?em:Skalarni logi?ki operatori namijenjeni su kori?tenju s jednoelementnim vektorima, vra?aju jedinstvenu vrijednosti TRUE ili FALSE te su pogodni za kori?tenje raznim u uvjetnim izrazima.Vektorski logi?ki operatori koriste standardne R-ove principe vektorizacije i recikliranja, tj. namijenjeni su radu s logi?kim vektorima i kao rezultat daju logi?ki vektor.Vje?ba 18: Skalarni i vektorski logi?ki operatori# zadani su vektori a i ba <- c(T, F, F)b <- c(T, T, F)# primijenite skalarnu i vektorsku ina?icu logi?kog operatora "ili"# nad vektorima a i b i ispi?ite rezultatVidimo da ?e skalarna ina?ica “iskoristiti” samo prvi par elemenata logi?kih vektora. Ovo zna?i da ju u teoriji mo?emo koristiti u uvjetnim izrazima, iako za to nema opravdanoga smisla, a R ?e se u tom slu?aju oglasiti upozorenjem kako bi nam obratio pa?nju na ?injenicu da vjerojatno koristimo “krivi” operator.Sljede?i primjer s usporednim operatorima ?e mo?da inicijalno izgledati trivijalan, no potrebno je obratiti posebnu pa?nju na rezultate koje ?emo dobiti jer ?e oni imati vrlo va?nu primjenu u nastavku lekcije. Dakle, pogledajmo ?to se doga?a kod vektorizacije usporednih operatora.Vje?ba 19: Vektorizacija usporednih operatora# zadani su vektori x i yx <- 1:5y <- seq(-10, 10, 5)#ispi?ite x i y#ispi?ite rezultat naredbe x > y i objasnite rezultat#ispi?ite rezultat naredbe x < 3 i objasnite rezultatDakle, vektoriziranom primjenom usporednih operatora nad vektorima (ili kombinacijama vektora i “skalara”) kao rezultat dobivamo logi?ke vektore. Interpretacija ovih rezultata je klju?na – ona zapravo odgovara na pitanje “na kojim je indeksima zadovoljen uvjet zadan ovim izrazom?” Drugim rije?ima, dobiveni rezultati zapravo predstavljaju predlo?ak koji opisuje kako filtrirati elemente prema zadanom principu. Ovo je osnovni temelj takozvanoga logi?kog indeksiranja, ?to je jedna od metoda indeksiranja koje ?emo upoznati u nastavku.Indeksni vektoriDefinicija indeksnoga vektoraDo sada smo usvojili dva vrlo va?na principa za razumijevanje jezika R:“sve je vektor”“sve operacije su vektorizirane”.Jedan od razloga inicijalno strme krivulje u?enja ovoga jezika jest i taj da su programeri ?esto naviknuti na intenzivno kori?tenje programskih petlji te pojedina?nu obradu elemenata kolekcija tako da im princip vektoriziranih operacija ?esto predstavlja dramati?an pomak paradigme. No, ukoliko se ova problematika sagleda sa suprotne strane, mo?e se uo?iti da se zapravo radi o bitnom pojednostavljenju sintakse – umjesto da u programu obja?njavamo “kako” ne?to u?initi, mi mu samo govorimo “?to” ?elimo i pu?tamo ra?unalo da se brine o niskorazinskim stvarima kao ?to je “?etanje po kolekciji”.Dakle, jezik R jednostavno voli raditi “vi?e stvari odjednom”. No ovo ne zna?i da smo u praksi ograni?eni na pristup “sve ili ni?ta”, tj. da moramo uvijek sve podatke nekoga skupa obra?ivati istodobno. Jezik R nam omogu?uje da to?no specificiramo nad kojim elementima skupa ?elimo raditi, ali bez napu?tanja principa “sve odjednom” – u tome nam poma?u takozvani indeksni vektori.Indeksni vektor nije ni?ta drugo nego obi?an, elementaran vektor koji predstavlja svojevrsnu specifikaciju elemenata (indekasa) s kojima ?elimo raditi, bilo da ih ?elimo dohvatiti ili izmijeniti. Postoje tri osnovna na?ina indeksiranja (i pripadaju?ih indeksnih vektora):lokacijsko indeksiranje (engl. integer- or location-based indexing), numeri?ki indeksni vektoruvjetno indeksiranje (engl. conditional or boolean-based indexing), logi?ki indeksni vektorimensko indeksiranje (engl. label-based indexing), znakovni indeksni vektor.Koje ?emo indeksiranje odabrati ovisi o tome ?elimo li elementima pristupati ovisno o njihovoj lokaciji, imenu ili prema zadanom uvjetu, a svaki tip indeksiranja u su?tini se svodi na kori?tenje navedenoga tipa vektora kao parametra za operator indeksiranja [.Upoznajmo detaljno svaki od tipova indeksiranja. U vje?bama koje slijede uglavnom ?emo indeksirati jednostavne vektore, no principi koje upoznamo direktno su primjenjivi i na ostale slo?ene strukture (matrice, liste, podatkovne okvire), s obzirom na ?injenice koje smo dosad nau?ili.Lokacijsko indeksiranjeLokacijsko indeksiranje je poop?enje ve? upoznatoga principa indeksiranja gdje navodimo redni broj elementa koji nas zanima. Ako ?elimo vi?e elemenata, jednostavno navedemo njihove indekse “zapakirane” u numeri?ki vektor.Poku?ajte rije?iti sljede?i zadatak kori?tenjem odgovaraju?ih numeri?kih vektora kao parametara indeksiranja.Vje?ba 20: Lokacijsko indeksiranje# zadan je vektor xx <- 1:10# ispi?ite prvi element vektora x# ispi?ite prva tri elementa vektora x# ispi?ite prvi, peti i sedmi element vektora xDakle, lokacijski indeksni vektor nije ni?ta drugo nego obi?an numeri?ki vektor koji koristimo zajedno s indeksnim operatorom da bismo odredili koje elemente nekoga drugog vektora ?elimo “zadr?ati”.Pogledajmo jo? neke zna?ajke lokacijskih indeksnih vektora:Vje?ba 21: Lokacijsko indeksiranje (2)# zadan je vektor xx <- 1:10# odgovorite na sljede?a pitanja uz pomo? prikladnog primjera# ?to vra?a indeks 0? # ?to vra?a negativni indeks? # ?to vra?a indeks izvan granica duljine vektora?# ?to vra?a negativni indeks izvan granica duljine vektora?Indeksiranje se ne koristi samo za dohva?anje elemenata. Kombinacijom operatora indeksiranja i operatora pridru?ivanja mo?emo mijenjati elemente vektora (i to tako?er po principu “vi?e elemenata odjednom”):Vje?ba 22: Lokacijsko indeksiranje i pridru?ivanje# zadan je vektor aa <- 1:10# postavite sve elemente vektora a od drugog do osmog mjesta na nulu # ispi?ite vektor a# nakon toga izvr?ite sljede?e naredbe:b <- 1:20b[2 * 1:5] <- 0# razmislite o tome kako izgleda vektor b nakon gornje naredbe# ispi?ite vektor b i objasnite rezultatUvjetno indeksiranjeAko smo pa?ljivo razmotrili rezultate dobivene kod primjera s vektoriziranim usporednim operatorima, onda smo mogli vrlo dobro naslutiti kako radi uvjetno indeksiranje. Princip je jednostavan – za indeksni vektor postavljamo logi?ki vektor iste duljine kao i vektor ?ije elemente ?elimo dohvatiti. Elementi logi?koga vektora odre?uju koje elemente zadr?avamo (pozicije na kojima se nalazi vrijednost TRUE) a koje odbacujemo (pozicije na kojima se nalazi vrijednost FALSE).Vje?ba 23: Uvjetno indeksiranje# zadan je vektor xx <- 1:10# napravite logi?ki vektor y duljine 10 s proizvoljnom kombinacijom# vrijednosti TRUE i FALSE# indeksirajte vektor x vektorom y, ispi?ite i objasnite rezultat# ispi?ite sve elemente vektora x manje ili jednake 5# kao logi?ki indeksni vektor upotrijebite odgovaraju?i izraz# koji koristi usporedni operatorNaredba x[x <= 5], naoko jednostavna, zapravo je jedan od klju?nih principa odabira elemenata u jeziku R. Kombinacija indeksnog operatora i uvjetnog izraza predstavlja sa?et ali vrlo mo?an mehanizam rezanja vektora prema odabranom kriteriju.Isprobajmo ovaj princip na jo? nekoliko primjera.Vje?ba 24: Uvjetno indeksiranje (2)# zadani su vektor y i `studenti`y <- seq(1, 100, 7)studenti <- c("Ivo", "Petra", "Marijana", "Ana", "Tomislav", "Tin")# ispi?ite sve parne, a potom sve neparne elemente vektora y# ispi?ite sve elemente vektora `studenti` koji predstavljaju imena od 3 slova# (napomena: za prebrojavanje slova znakovnog niza u R-u koristimo funkciju `nchar`)Ukoliko koncept uvjetnog indeksiranja uz pomo? uvjetnih izraza i dalje nije jasan, jedna od stvari koje mogu pomo?i jest skiciranje “me?urezultata” – jednostavno na papir ispi?ite rezultat izraza unutar uglatih zagrada indeksnog operatora i potom razmislite kako taj rezultat utje?e na kona?no rje?enje.Preostao nam je jo? samo zadnji tip indeksiranja koji radi na principu dohva?anja elemenata vektora ovisno o njihovu imenu.Imensko indeksiranjeImensko indeksiranje radi na principu eksplicitnog imenovanja elemenata koje ?elimo “zadr?ati”. Da bismo mogli koristiti ovakav tip indeksiranja, moramo zadovoljiti nu?an preduvjet – elementi vektora moraju imati definirana “imena”.Vektori koje smo do sada koristili nisu imali imenovane elemente. Svaki element imao je svoju predefiniranu poziciju unutar vektora te svoju vrijednost, ali nije imao nikakav poseban dodatni identifikator. Programski jezik R dopu?ta pridavanje imena elementima vektora na vrlo jednostavan na?in – kori?tenjem funkcije names, operatora pridru?ivanja te znakovnoga vektora s odabranim imenima. Moramo voditi ra?una o tome da vektor imena bude jednake duljine kao originalni vektor!Vje?ba 25: Imensko indeksiranje# zadan je vektor `visine` s postavljenim imenima elemenatavisine <- c(165, 173, 185, 174, 190)names(visine) <- c("Marica", "Pero", "Josip", "Ivana", "Stipe")# ispi?ite vektor `visine`# ispi?ite koliko su visoki Pero i IvanaVidimo da se imensko indeksiranje o?ekivano svodi na proslje?ivanje odgovaraju?ega znakovnog vektora kao parametra indeksiranja.(NAPOMENA: Pa?ljiviji ?itatelj uo?it ?e jednu neobi?nu ?injenicu u gornjem programskom kodu – poziv funkcije se koristi kao lvalue (objekt koji nastavlja postojati i nakon obavljanja jedne operacije, za razliku od rvalue koji ne egzistira nakon naredbe u kojoj je kori?ten)! Odgovor na pitanje za?to je ovakva pohrana mogu?a zahtijeva malo vi?e znanja o internom funkcioniranju jezika R, a za sada je dovoljno re?i da se ovdje zapravo radi o pozivu funkcije pravog imena names<- koji se “skriva” iza puno intuitivnije i lako razumljive sintakse).Ako iz nekog razloga po?elimo obrisati imena elemenata vektora, jednostavno pozivu funkcije names proslijedimo NULL.names(visine) <- NULLIndeksni vektori i matricePoku?ajmo sada primijeniti nau?eno i na slo?enije podatkovne strukture.Vje?ba 26: Indeksni vektori i matrice# zadana je matrica m` s postavljenim imenima stupacam <- matrix(1:30, 6, 5, T)colnames(m) <- c("a", "b", "c", "d", "e")# ispi?ite sve elemente matrice m od drugog do ?etvrtog retka# te od tre?eg do petog stupca# sve elemente u stupcu naziva "c" postavite na nulu# a potom ispi?ite prva dva retka matrice `m`# ispi?ite samo stupac "d"# ispi?ite opet stupac "d", ali kod indeksiranja dodajte parametar `drop = FALSE`# parametar odvojite zarezom (kao da se radi o "tre?oj" dimenziji indeksiranja)Indeksni vektori i podatkovni okviriSljede?a vje?ba koristi podatkovni okvir mjesto koji smo ve? koristili u prethodnim primjerima i vje?bama.Vje?ba 27: Indeksni vektori i podatkovni okviri# ispi?ite tablicu `mjesto` (za referencu)# ispi?ite prva tri retka, drugi i peti stupac# ispi?ite stupac "prirez"# ispi?ite po?tanske brojeve i nazive svih mjesta koja # imaju prirez ve?i od 12 % i broj stanovnika ve?i od 100.000Rje?avanjem ovoga zadatka mogli smo uo?iti uobi?ajeni obrazac “rezanja” podatkovnog okvira – logi?ki indeksni vektor za retke, znakovni (ili numeri?ki) za stupce. Poznavatelji SQL-a ?e uo?it ?e sli?nost izme?u te naredbe i SQL upita:SELECT pbr, nazivMjestaFROM mjestoWHERE mjesto.prirez > 12 AND mjesto.brojStanovnika > 100000Odabir stupaca i redaka nije te?ak ako se dobro koristimo znanjem o indeksnim vektorima, no kao ?to se vidi u zadnjem primjeru, sintaksa ?esto nije previ?e ?itljiva (u usporedbi s npr. SQL-ovom sintaksom koja obavlja isti posao). Zbog toga postoje razli?ita pro?irenja R-a koja ovaj posao uvelike olak?avaju, a koja ?emo detaljno obraditi u jednoj od budu?ih lekcija koja ?e se baviti upravljanjem podatkovnim skupovima.?to ako NE ?elimo odre?ene elemente u rezultatu, na primjer, ?elimo sve stupce OSIM stupaca nazivMjesta i prirez? Sjetimo se da negativni numeri?ki indeks zna?i “izbaci element”. No, kako nam ovo koristi ako stupac identificiramo znakovnim indeksnim vektorom? Jedna od opcija jest da provjerimo koji su po redu ti stupci i onda se koristimo numeri?kim indeksnim vektorom, no recimo da trebamo generi?ko rje?enje koje ?e raditi neovisno o polo?aju stupaca. Ovdje nam u pomo? nam sti?e funkcija which koja pretvara logi?ki vektor u numeri?ki. Procedura je sljede?a:dohvatimo vektor imena stupaca (funkcija names)stvorimo logi?ki indeksni vektor koji ozna?ava koja imena se nalaze u odabranom skupu imena (operator %in%)uz pomo? funkcije which pretvorimo ovaj logi?ki indeksni vektor u numeri?kiiskoristimo taj numeri?ki vektor uz operator - s ciljem izbacivanja odabranih stupaca.Primjer 8: Izbacivanje stupaca po imenumjesto[, -which(names(mjesto) %in% c("nazivMjesta", "prirez"))]## pbr prosjPlacaKn brojStanovnika## 1 10000 6359 790017## 2 51000 5418 128384## 3 21000 5170 167121## 4 31000 4892 84104## 5 20000 5348 28434Mo?emo uo?iti nekoliko problema sa zadnjim primjerom. Prvo, procedura je relativno slo?ena, pogotovo za po?etnika. Drugo, postoji izvjesna vjerojatnost jedne relativno nezgodne pogre?ke – ako ni jedan stupac ne odgovara onima navedenim u skupu imena, umjesto da dobijemo sve stupce, mi ne?emo dobiti ni jedan (rezultat ?e biti “prazan” numeri?ki vektor, na koji operator - ne djeluje, tako da mi zapravo doslovno tra?imo “nijedan” stupac). Ovo sve pokazuje da se R-ova sintaksa za upravljanje podatkovnim okvirima u odre?enim slu?ajevima mo?e pokazati relativno nezgrapnom i nepotrebno kompleksnom. Upravo zbog toga R zajednica nudi niz paketa koji umnogome olak?avaju rad s podatkovnim okvirima te omogu?uju pisanje jasnijega, preglednijega programskog k?da s puno manjom vjerojatnosti pogre?ke. Vjerojatno najpopularniji takav paket jest dplyr, o kojem ?e biti ne?to vi?e rije?i u jednoj od nastupaju?ih lekcija.Dodatni zadaci za vje?buStvorite sljede?e vektore:(11, 12, 13…, 99)(0, 0, 0, 0… , 0) (100 nula)(0, 0.1, 0.2…, 1.0).Kolika je suma svih brojeva od 101 do 1001, presko?imo li sve brojeve djeljive s 10? Koristite se funkcijom sum.Stvorite matricu 3 × 3 s brojevima izvo?enjem sljede?ih naredbi (funkciju sample ?emo pobli?e upoznati u jednoj od sljede?ih lekcija):# stvaramo matricu 3 × 3 nasumi?no odabranih elemenata iz skupa od 1 do 100set.seed(1234)m <- matrix(c(sample(1:100, 9, T)), nrow = 3, ncol = 3, byrow = T)Izra?unajte inverznu matricu uz pomo? funkcije solve. Provjerite daje li umno?ak originalne i inverzne matrice jedini?nu matricu (za mno?enje matrica koristite se operatorom %*%).Inicijalizirajte ponovo listu svastara kori?tenu u lekciji. Napravite sljede?e:ispi?ite klasu drugog elementa listeispi?ite element na tre?em mjestu elementa liste naziva slovaprovjerite duljinu elementa naziva imena te na zadnje mjesto dodajte ime "Pero"provjerite nalazi li se broj 4 u prvom elementu listena zadnje mjesto liste dodajte novu listu s tri vektora a, b i c koji svi sadr?e elemente (1,2,3).U?itajte podatkovni okvir mtcars (naredba data(mtcars)). Napravite sljede?e:ispi?ite sve parne retke i stupce s tri ili vi?e slova u nazivustupac mpg pokazuje potro?nju u obliku “milja po galonu goriva”. Dodajte stupac l100km koji ?e sadr?avati potro?nju u litrama na 100 km. Koristite se formulom litara na 100km = 378.5 / milja po galonuizbri?ite sve retke gdje je broj cilindara (stupac cyl) jednak broju 4.R i programske paradigme?to su programske paradigme?Op?enito o programskim paradigmamaPojam “programske paradigme” predstavlja na?in na koji programski jezik ili programer dizajnira, tj. oblikuje svoje programe. Postoji niz programskih paradigmi kod kojih ima dosta preklapanja, a programski jezici ?esto podr?avaju vi?e istih tako da se pitanje “odabira” programske paradigme ?esto svodi na preuzimanje odre?enih na?ela i smjernica koje odgovaraju kako cilju koji programer ?eli posti?i tako i svojstvima odabranoga programskog jezika.U kontekstu ovoga te?aja bavit ?emo se programskim paradigmama, osobito u kontekstu boljega razumijevanja jezika R. Zbog toga ne?emo raditi iscrpan pregled postoje?ih paradigmi kao ni ulaziti u detalje oko svake, ve? ?emo odabrati tri naj?e??e spominjane paradigme koje direktno utje?u na pristup u?enju jezika R: imperativna, objektna i funkcijska paradigma.Imperativna programska paradigmaImperativna programska paradigma predstavlja uobi?ajen pogled na programiranje kao pisanje naredbi koje mogu na odre?eni na?in utjecati na stanje programa. Program je u ovom slu?aju zapravo zapis nekog algoritma u odabranom programskom jeziku, a ?ije slijedno izvo?enje dovodi do tra?enog cilja. Program ima definirani tok od po?etka do kraja, a naredbama kontrole toka utje?emo na uvjetno ili ponavljano izvo?enje nekih njegovih segmenata (tzv. if-else naredbe i programske petlje).Objektna programska paradigmaObjektna programska paradigma temelji se na stvaranju i upravljanju takozvanim “objektima”, tj. programskim strukturama koje enkapsuliraju podatke (tzv. “atributi”) i metode (funkcije koje obavljaju neki posao, ?esto vezan za atribute). Programiranje se svodi na dizajn ovakvih objekata ?ije metode omogu?uju me?usobnu komunikaciju, a ?ije izvo?enje ?esto dovodi do promjene internih stanja objekata. Objektno programiranje uvodi pojmove kao ?to su “klase i instance” (predlo?ci objekata te sami objekti), naslje?ivanje (izvo?enje novih objekata pro?irenjem predlo?aka postoje?ih), polimorfizam (jedinstveno su?elje nad razli?itim objektima) i sl.Funkcijska programska paradigmaOsnovni princip funkcijske programske paradigme jest da je fokus na poslu koji se obavlja, ne na objektima nad kojima se obavlja posao. Drugim rije?ima, ako se objektno orijentirano programiranje usredoto?uje na “imenice”, funkcijsko se usredoto?uje na “glagole”. Programiranje se svodi na stvaranje i provo?enje funkcija, a izbjegava se bilo kakvo “pam?enje stanja”. Poziv funkcije s istim ulazima uvijek mora rezultirati identi?nim izlazima. Ovakav na?in programiranja stavlja visoku va?nost na reproducibilnost i predvidljivost rezultata programskoga k?da, ?ine?i razumijevanje i kori?tenje razvijenih programa jednostavnijim. Tako?er, jedna od karakteristika funkcijske programske paradigme jest ta da se funkcije tretiraju kao “gra?ani prvoga reda” – one nisu ne?to “zamotano” u objekte, one su samostalne, imaju svoju referencu, mogu se slati u druge funkcije kao parametri ili vra?ati kao rezultat funkcije. Funkcijska programska paradigma ?esto se smatra malo te?om za u?enje od imperativne i (donekle) objektne, ali neupitna je njezina u?inkovitost kod odre?enih skupina problema.Programski jezici i programske paradigmeOdabir jezika = odabir paradigme?Ve? smo rekli da programski jezici ?esto podr?avaju vi?e programskih paradigmi te omogu?avaju programerima prilagodbu na paradigmu koja najvi?e odgovara njihovim osobnim preferencama ili cilju koji ?ele obaviti. Usprkos tomu, odre?eni jezici “naginju” odre?enoj paradigmi, tako se npr. C++ i Java ?esto smatraju “primarno” objektnim jezicima, Erlang i Haskell funkcionalnima itd. Postoje jezici, kao na primjer Python, za koje je te?ko jasno klasificirati naginju li odre?enoj paradigmi ili ne.R i programske paradigmeKod programskog jezika R dosta je te?ko re?i radi li se o “univerzalnom” jeziku (s gledi?ta paradigmi) ili ga se mo?e svrstati u jezike koji su sna?no naklonjeni odre?enoj paradigmi.Neupitno je da je R domenski orijentirani jezik, tj. da je njegova primarna funkcija analiza podataka. R uredno podr?ava sve elemente imperativnih jezika – u R-u mo?emo pisati naredbe koje mijenjaju stanje programa, a koje je reprezentirano kroz varijable. Isto tako, gledaju?i na?in na koji je R dizajniran, uo?ava se da on sadr?ava jasno definirane elemente objektne programske paradigme – entiteti kojima upravljamo programiraju?i u R-u su objekti, a R podr?ava sve nu?ne objektno-orijentirane principe kao ?to su enkapsulacija, polimorfizam i naslje?ivanje. No, u?enjem R-a lako ?emo spoznati da R radi s objektima na dosta neobi?an na?in, zaobilaze?i neke ustaljene konvencije prisutne u drugim jezicima, te da pisanje R programskoga k?da vrlo ?esto naginje funkcionalnom programiranju – funkcije su “punokrvni” objekti, prirodno je slati ih kao parametre ili primati kao rezultat drugih funkcija, a usredoto?enost na “radnju”, tj. “posao” koji moramo izvesti vrlo je sukladno procesu analize podataka gdje se na?e programiranje zapravo svodi na razvoj metode koja ?e “obraditi” podatke na odre?eni na?in i koja bi za isti ulazni skup morala uvijek davati iste rezultate.Zaklju?ak koji se name?e je sljede?i – kod u?enja R-a treba nau?iti i njegove imperativne i objektne elemente, ali R ne bismo trebali tretirati kao “univerzalni” programski jezik jer je cilj koji njegovim kori?tenjem ?elimo posti?i u jasnom i o?itom skladu s funkcijskom programskom paradigmom. Shodno tome, iako poznavanje detalja oko funkcijske programske paradigme nije klju?no za svladavanje R-a, prihva?anje R-a kao funkcionalnoga jezika te ulaganje truda u svladavanje barem nekih principa ove paradigme mo?e se vi?estruko isplatiti.U nastavku ?emo se baviti elementima jezika R koji odgovaraju razli?itim paradigmama. Nau?it ?emo naredbe kontrole toka tipi?ne za imperativni pristup, spominjat ?emo i objekte, ali fokus ?e ipak biti na funkcijama: kako R “vidi” funkcije, kakve tipove funkcija podr?ava R, kako pisati vlastite funkcije te kako ih koristiti kao “prvoklasne” objekte.Upravljanje programskim tokomUvjetno izvo?enje naredbiNaredba if - elseAko program gledamo kao niz naredbi, onda nam uvjetno izvo?enje omogu?uje da se odre?ene naredbe izvedu samo ako su ispunjeni odre?eni preduvjeti (ili samo ako nisu ispunjeni). Ovo je u gotovo svakom programskom jeziku poznato kao klasi?ni if - else konstrukt, a izgleda ovako:if (izraz) {blok} else {blok}gdje se pod izraz misli na logi?ki izraz s jednoelementnim logi?kim rezultatom.Uvjetno izvo?enje ne koristimo ?esto u interaktivnom radu, ali je vrlo bitno ako razvijamo vlastite programske funkcije ili skripte. Kori?tenje if - else konstrukta je samo po sebi jasno i trivijalno, no moramo pripaziti da ne u?inimo jednu pomalo te?ko uo?ljivu gre?ku. Poku?ajmo tu gre?ku uo?iti i ispraviti u sklopu sljede?ega zadatka.Vje?ba 28: Naredba if-else# izvr?ite sljede?u naredbu uvjetnog izvo?enjaif (2 > 1) print("Uspjeh!")# preina?ite sljede?e naredbe tako da ne rezultiraju gre?komif (1 > 2) print("Uspjeh!")else print("Nuspjeh!")Dakle, potencijalni problem mo?e nam stvarati else dio naredbe ako ga stavimo u novi red nakon ?to je naredba if formalno “zavr?ila” s gledi?ta interpretera. Nakon prvog retka interpreter ?e do?i do vrijednosti FALSE, ispis ne?e biti izvr?en te ?e interpreter nastaviti s ‘novom’ naredbom koja to u ovom slu?aju nije pa ?e javiti gre?ku. Postavljanjem naredbe u blok koji ne zatvaramo u istom retku dajemo interpreteru na znanje da “ima jo?”, tako da onda uredno mo?emo ubaciti i ?eljeni else dio.Naredba ifelseNa ovom mjestu nije lo?e nau?iti i funkciju ifelse koja predstavlja svojevrsnu “vektoriziranu” ina?icu naredbe if - else. Ona, strogo gledaju?i, nema veze s uvjetnim izvo?enjem naredbi, ali je vrlo korisna u radu s programskim okvirima kada ?elimo dodati stupac – binarnu “zastavicu” koja opisuje je li neki uvjet ispunjen ili ne.Rad ove funkcije najlak?e mo?emo prikazati uz pomo? primjera.Primjer 9: Funkcija ifelsea <- 1:3b <- c(0, 2, 4)x <- ifelse(a < b, 2, 5)x## [1] 5 5 2Programske petljeR i programske petljeU programskom jeziku R imamo tri tipa petlji:repeat – beskona?na petljawhile – petlja s provjerom uvjeta na po?etkufor – iteratorska petlja (“petlja s poznatim brojem ponavljanja”).Petlja repeatPetlja repeat je najjednostavnija petlja. Ona ima sljede?u sintaksu:repeat {blok}Ovdje se radi o “beskona?noj” petlji gdje se nakon zavr?etka bloka on ponovo izvr?ava i tako unedogled. Jedini na?in izlaska iz ovakve petlje jest kori?tenje naredbe break. Pored ove naredbe imamo i naredbu next koja ?e presko?iti ostatak bloka, ali ne?e iza?i iz petlje ve? ?e nastaviti izvr?avati blok od po?etka.Pogledajmo kako radi ova petlja u sljede?oj vje?bi.Vje?ba 29: Petlja repeat# prije izvr?avanja sljede?eg bloka odgovorite na pitanja:# - ho?e li se petlja izvr?avati beskona?no?# - ?to ?e se ispisati na zaslonu?i <- 1repeat { i <- i + 1 if (i %% 2 == 0) next print(i) if (i > 10) break}## [1] 3## [1] 5## [1] 7## [1] 9## [1] 11?esto unaprijed znamo uvjet izlaska iz petlje te bismo ga htjeli staviti na jasno vidljivo mjesto tako da nije “skriven” u tijelu petlje. Za to nam poma?e takozvana while petlja.Petlja whilePetlja while predstavlja “naj?i??i” oblik programske petlje ?ija sintaksa doslovno glasi “dok je uvjet ispunjen, ponavljaj navedeni k?d”:while (uvjet) {blok}Vje?ba 30: Petlja while# dodajte uvjet petlje tako da se ona izvr?i# to?no 7 putai <- 1while() { print(i) i <- i+1}Kod ove petlje moramo paziti da se u odre?enoj iteraciji moraju stvoriti uvjeti za izlaz, ina?e ona tako?er postaje “beskona?na” petlja. Usprkos tomu ?to imamo jasno definiran na?in izlaska iz petlje, mi i u ovoj petlji mo?emo slobodno koristiti klju?ne rije?i next i break, koje imaju istu funkciju kao i kod petlje repeat.Petlja forPetlja for ili “iteratorska petlja” obi?no slu?i za “?etanje” po nekoj podatkovnoj strukturi (naj?e??e vektoru), uzimaju?i element po element i ne?to rade?i s njim. Ona koristi klju?nu rije? for, ime nove (iteratorske) varijable, klju?nu rije? in te vektor ?ije se vrijednosti uzimaju jedna po jedna i koriste unutar petlje (uo?ite da navedeni in nije isto ?to i operator %in% koji provjerava nalazi li se neki element u nekom skupu!). Sintaksa ove petlje je sljede?a:for (i in v) {radi ne?to s i}Uo?imo da ovdje varijabla i nije “broja?” – u svakoj iteraciji petlje ona postaje vrijednost elementa do kojeg smo do?li. Ako ba? ?elimo iterirati po indeksima, a ne po samim elementima, onda mo?emo koristiti konstrukt for (i in 1:length(a)).Vje?ba 31: Petlja fora <- seq(-10, 10, 4)# ispi?ite elemente vektora `a` jedan po jedan # uz pomo? petlje `for`# pristupajte elementima direktno# ponovite isto, ali iterirajte po indeksimaUo?ite da je drugi na?in bolji ako ?elite mijenjati elemente vektora ili imati informaciju na kojem se mjestu unutar originalnoga vektora trenuta?no nalazite.Kori?tenje programskih petlji u jeziku RSada kad smo nau?ili sintaksu petlji va?no je naglasiti jednu ?injenicu – u programskom jeziku R u pravilu se ne preporu?uje kori?tenje programskih petlji. Iako ovo inicijalno mo?da djeluje neobi?no s obzirom na sveprisutnost petlji u drugim programskim jezicima, razlog je jednostavan – R je jezik dizajniran upravo na na?in da naredbe jezika rade po principu “vi?e stvari odjednom”. Ve? smo vidjeli da principi vektorizacije i recikliranja u?inkovito obavljaju poslove koji bi u drugim programskim jezicima zahtijevali petlju, a u poglavljima koja slijede vidjet ?emo da R nudi i mnoge druge konstrukte koji nude po?eljniju alternativu od eksplicitnog kori?tenja programskih petlji.Recimo, sljede?i primjer je sintaksno potpuno ispravan:# primjer nepotrebnoga kori?tenja petljea <- 1:5b <- 6:10c <- numeric()for (i in 1:length(a)) c[i] <- a[i] + b[i]ali vjerojatno radi sporije i puno je ne?itljiviji od:# R-ovska sintaksaa <- 1:5b <- 6:10c <- a + bSve navedeno, naravno, ne zna?i da petlje u R-u ne smijemo koristiti ve? samo to da bi njihovo kori?tenje trebalo biti popra?eno dodatnim razmatranjem stvarne potrebitosti petlje na tom mjestu te postojanja alternativne sintakse (ili funkcije!) koja isti posao obavlja deklarativno (i potencijalno br?e jer su mnoge rutine R-a implementirane u jeziku C). Rano prihva?anje “R-ovskoga” na?ina razmi?ljanja rezultirat ?e dugoro?nim pozitivnim efektima koji ?e se o?itovati kompaktnijim, ?i??im i ?esto u?inkovitijim programskim k?dom.Funkcije u jeziku RUgra?ene funkcijePaketi i staza pretragePod pojmom “ugra?enih funkcija” nekoga programskog jezika ?esto mislimo na funkcije koje su nam odmah dostupne nakon instalacije odabrane distribucije toga jezika. Kod programskoga jezika R vrlo brzo se upoznajemo s takvim funkcijama u?e?i osnovnu sintaksu jezika te neke njegove temeljne koncepte. Tako smo do sada zasigurno ve? upoznali razne numeri?ke funkcije (log, abs, sqrt, round i sl.), funkcije za stvaranje vektora (rep, seq i sl.), funkcije za rad s paketima (install.packages, library i sl.) i tako dalje. Operatori kao ?to su +, *, :, <- i sl. su tako?er zapravo samo funkcije, izvedene na na?in da omogu?uju kori?tenje specifi?ne “operatorske” sintakse.Sve ove funkcije logi?ki su organizirane u zasebne kolekcije zvane “paketi”. Novi paket u?itavamo uz pomo? naredbe library(ime_paketa), a R okolina automatski pri pokretanju u?itava predefiniranu kolekciju korisnih paketa. Potpuna sintaksa za zvanje funkcije iz nekog paketa jest ime_paketa::ime_funkcije(parametri).Uzmimo za primjer paket stats koji sadr?i bogati skup funkcija vezanih za statisti?ke obrade – ovaj ?e paket ve? biti u?itan ?im pokrenemo distribuciju jezika R. Odaberimo iz ovog paketa jednu od vrlo ?esto kori?tenih funkcija zvanu rnorm. Ona vra?a numeri?ki vektor ?eljene duljine ?iji su elementi nasumi?no odabrani iz normalne distribucije s aritmeti?kom sredinom 0 i standardnom devijacijom 1 (ove vrijednosti mo?emo i promijeniti uz pomo? parametara mean i sd).Pozovimo ovu funkciju u sljede?oj vje?bi.Vje?ba 32: Poziv funkcije iz odabranog paketa# stvorite vektor x koji ?e imati 10 slu?ajnih elemenata# izvu?enih iz standardne normalne distribucije# koristite puni naziv funkcije `rnorm` iz paketa `stats`# zaokru?ite elemente vektora x na dvije decimale# koristite puni naziv funkcije `round` iz paketa `base`# ispi?ite vektor xIako je ovo sintaksno ispravan na?in pozivanja funkcije, R nam omogu?uje da izuzmemo nazive paketa i jednostavno navedemo samo naziv funkcije.Vje?ba 33: Poziv funkcije bez imena paketa# stvorite vektor y po istom principu kao i vektor x# obavite sve u jednom retku# koristite nazive funkcija bez naziva paketa# ispi?ite yKako je R znao koju funkciju pozvati ako se one nalaze u razli?itim paketima? Odgovor na to daje nam koncept “staze pretrage”. Naime, R u?itava pakete odre?enim slijedom koji se zapisuje u spomenutu stazu pretrage (engl. search path) pri ?emu se paket koji je zadnje u?itan postavlja na drugo mjesto u stazi, odmah iza radne, tj. “globalne” okoline (koja je uvijek na prvom mjestu). Kada pozivamo neku funkciju (ili referenciramo neku varijablu), a ista nije prisutna u radnoj okolini, R ?e se “pro?etati” stazom pretrage i slijedno tra?iti tu varijablu ili funkciju u paketima koji se nalaze u njoj. Pretragu ?e zavr?iti ?im na?e prvo “poklapanje”.Stazu pretrage mo?emo i sami vidjeti uz pomo? funkcije search.Vje?ba 34: Staza pretrage# ispi?ite stazu pretrage uz pomo? funkcije `search` (bez parametara) # u?itajte novi paket uz pomo? funkcije `library` (npr. paket `dplyr`)# (ako paket nije instaliran, morate ga prvo dohvatiti uz pomo? funkcije `install.packages`)# ispi?ite ponovo stazu pretrageUo?ite dvije bitne stvari. Prvo, globalna okolina uvijek ostaje na prvom mjestu, tako da nijedan novou?itani paket ne mo?e “pregaziti” varijable i funkcije radne okoline. Drugo, kod u?itavanja novoga paketa mo?emo dobiti upozorenje da su sada neki objekti “maskirani”. Ovo se doga?a kada novi paket sadr?i objekte s imenima koja ve? postoje u stazi pretrage. Ovo ne zna?i da su maskirani objekti sada nedostupni, ve? samo da njima sada moramo pristupati preko punog imena (ime_paketa::ime_funkcije). Zbog ovoga moramo biti pa?ljivi kod izrade vlastitih programskih skripti ili izvje?taja, te uvijek koristiti puno ime ako se bojimo da ?e zbog naknadnog u?itavanja nekog paketa neki dio programskoga k?da po?eti raditi neispravno jer ?e se unutar njega pozivati “kriva” funkcija.Dohvat pomo?iKada koristimo programski jezik R, ?e??e se oslanjamo na ve? postoje?e funkcije ili na funkcije iz dodatnih paketa koje je netko drugi stvorio i dao na uporabu R zajednici. Zbog toga je vrlo va?no znati kako prona?i informaciju o tome postoji li ve?, za neki zadatak koji ?elimo izvr?iti, stvorena funkcija te, ako da, na koji ju na?in pozvati.Da bismo rije?ili prvi problem, utvr?ivanje postoji li ve? neka funkcija i, ako postoji, prona?i gdje se nalazi, potrebno je koristiti dostupnu dokumentaciju, podsjetnike ili internetske tra?ilice. Alat RStudio nudi odli?ne podsjetnike za razne aspekte i razine kori?tenja jezika R, a koji se vrlo lako mogu prona?i upisuju?i “RStudio Cheat Sheets” u internetsku tra?ilicu. Isto tako, vrlo ?esto odgovor na pitanje o tome postoji li neka funkcija mo?emo dobiti postavljanjem jasno sro?enoga pitanja u tra?ilicu na engleskom jeziku, na primjer, “What is a function for adding vector elements in R?”.Jednom kada znamo koju funkciju odabrati, te po potrebi instaliramo paket u kojem se ona nalazi, idu?i korak jest pregled dokumentacije o navedenoj funkciji. Za to postoji funkcija help, iako je ?esto lak?e staviti znak ? i ime funkcije, na primjer, ?rnorm.Primjer 10: Tra?enje pomo?i# isprobajte nazive i nekih drugih funkcija?rnormPozivanje pomo?i za neku funkciju ?esto daje informacije i o nekim srodnim funkcijama, a na dnu dokumentacije ?esto se daju i primjeri kori?tenja. Ako ?elimo, primjere mo?emo i odmah zatra?iti uz pomo? funkcije examples.Iako dokumentacija funkcije ?esto mo?e djelovati pomalo ne?itljivo ili ?ak zastra?uju?e, potrebno se naviknuti na ovakav pristup tra?enja pomo?i jer je to najbr?i i naju?inkovitiji na?in za pisanje kvalitetnoga, ciljno orijentiranoga programskog k?da. ?esto nije lo?e ni uz pomo? internetske tra?ilice potra?iti dodatne primjere kori?tenja tra?ene funkcije, ako ih se mo?e prona?i, jer programeri ?esto nailaze na sli?ne probleme te je mogu?e da obja?njenje ili rje?enje problema s nekom funkcijom ve? postoji te je lako dostupno uz postavljanje pravog upita u internetsku tra?ilicu.Klasi?ne, primitivne i interne funkcijeR je jezik otvorenoga k?da, u ?to se vrlo lako mo?e uvjeriti uz pomo? jednostavnog eksperimenta. Poku?ajmo pozvati funkciju sd (za tra?enje standardne devijacije elemenata vektora), ali na na?in da napi?emo samo ime funkcije, bez zagrada i parametara.Primjer 11: Ispis funkcije sdsd## function (x, na.rm = FALSE) ## sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), ## na.rm = na.rm))## <bytecode: 0x0000000015f99d58>## <environment: namespace:stats>Mo?emo uo?iti da nam R uredno daje ispis programskoga k?da ove funkcije. To?nije, vidimo programski k?d, memorijsku adresu na kojoj je funkcija pohranjena (ako se radi o unaprijed prevedenoj funkciji, ?to je ?esto slu?aj s ugra?enim funkcijama) te paket u kojem se funkcija nalazi. Uvid u izvorni k?d mo?e nam pomo?i kod eventualnih problema s kori?tenjem funkcije, ako nam ?itanje dokumentacije nije ve? pomoglo, a imamo i opciju kopiranja k?da i stvaranje vlastite ina?ice funkcije ako ?elimo.Mo?emo zatra?iti i samo parametre, tijelo ili okolinu funkcije uz pomo? funkcija formals, body i environment.Primjer 12: Ispis detalja o funkciji sd# ulazni parametri funkcije (lista!)formals(sd)# tijelo funkcijebody(sd)# okolina funkcije (radna okolina ili paket)environment(sd)## $x## ## ## $na.rm## [1] FALSE## ## sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), ## na.rm = na.rm))## <environment: namespace:stats>Kod nekih funkcija ne?emo uspjeti dobiti ispis, na primjer, kod funkcije sum za sumiranje elemenata vektora.Primjer 13: Ispis funkcije sumsum## function (..., na.rm = FALSE) .Primitive("sum")Ovakve “primitivne” funkcije nalazimo samo u osnovnom (base) paketu. One formalno i nisu “prave” R funkcije – ovdje se radi o funkcijama koje su implementirane na niskoj razini (naj?e??e u jeziku C) koje su zbog toga i vrlo u?inkovite. Zbog specifi?nost ovakvih funkcija dizajneri jezika R ih u pravilu izbjegavaju tako da se nove primitivne funkcije implementiraju samo ako za to postoje dovoljno jaki razlozi.Pored primitivnih funkcija imamo i takozvane “interne” funkcije, koje ?emo prepoznati po ispisu .Internal umjesto .Primitive. Ovdje se tako?er radi o niskorazinskim funkcijama koje nisu “prave” R funkcije iako imaju neka dodatna svojstva koje primitivne nemaju, tj. kod njihovoga pozivanja logika izvo?enja se provodi sli?nije “pravim” R funkcijama.U praksi nema neke konkretne potrebe za u?enjem detalja o primitivnim i internim funkcijama – time se bavi programerski tim koji dizajnira jezik R, a prosje?nim korisnicima je dovoljna informacija da se logika ovakvih funkcija odvija na niskoj razini, vrlo u?inkovito, ali da nemamo jednostavan uvid u njihovo funkcioniranje pored onoga ?to nudi dokumentacija (?to je ?esto i dovoljno, jer je svrha ovih funkcija ?esto o?igledna).Kona?no, za neke funkcije mo?emo dobiti prili?no zbunjuju?i ispis, npr. za funkciju mean:Primjer 14: Ispis funkcije meanmean## function (x, ...) ## UseMethod("mean")## <bytecode: 0x0000000013f40e30>## <environment: namespace:base>Vidimo da smo umjesto tijela funkcije dobili poziv funkcije neobi?nog imena UseMethod. Ovakav ispis ?emo zapravo ?esto susretati ako poku?amo pogledati kako izgledaju neke popularne ugra?ene funkcije, kao na primjer, print, plot ili summary. Razlog tomu je ?to su ovo zapravo takozvane “generi?ke” funkcije koje su direktno povezane s na?inom na koji R realizira svoj objektni model. Vi?e o njima nau?it ?emo u idu?oj lekciji.Korisni?ki definirane funkcijeVe? smo rekli da standardni na?in kori?tenja programskoga jezika R uglavnom uklju?uje primjenu postoje?ih funkcija, bilo da se radi o funkcijama iz paketa isporu?enih s R distribucijom ili onih naknadno dohva?enih iz CRAN repozitorija. No, tijekom rada u R-u ?esto se pojavljuje potreba za programiranjem vlastite funkcije, bilo da se radi o jednokratnoj, “anonimnoj” funkciji ili implementaciji nekoga slo?enijeg algoritma ili procesa koji planiramo naknadno koristiti u budu?im programima. Shodno tome, svladavanje jezika R neizbje?no uklju?uje i u?enje pisanja vlastite, korisni?ki definirane funkcije.Sintaksa pisanja funkcijeU op?enitom slu?aju, definicija nove funkcije izgleda ovako:ime_funkcije <- function(ulazni argumenti) { tijelo funkcije}Uo?imo da kod definicije funkcije koristimo operator <-. Ovo nije slu?ajno – definicija funkcije nije ni?ta drugo nego stvaranje objekta klase function koji onda pridru?ujemo odre?enoj varijabli; ime varijable zapravo je “naziv” funkcije.Funkcija prima nula ili vi?e ulaznih parametara (argumenata). Za razliku od programskih jezika kao ?to su C++ ili Java, u R-u ne definiramo eksplicitno njihove tipove – ulazni argumenti imaju samo ime te opcionalno nazivnu vrijednost.Cilj funkcije je vratiti rezultat u pozivaju?u funkciju ili program. Funkcija formalno mo?e vratiti samo jednu vrijednost, ?to nije nu?no restrikcija ako ?elimo vratiti vi?e vrijednosti, jednostavno taj skup vrijednosti uokvirimo u vektor, listu ili objekt. Klju?na rije? return je opcionalna – funkcija vra?a rezultat zadnjeg izraza u funkciji pa je ?esto dovoljno navesti samo varijablu koja predstavlja povratnu vrijednost kao zadnji red funkcije.Funkcija je, dakle, jednostavno komad programskoga k?da koji na osnovi ulaznih argumenata i programske logike vra?a neki rezultat. Ako ?elimo pove?ati robusnost funkcije na na?in da ?emo odbiti izvo?enje posla ako nisu zadovoljeni odre?eni uvjeti, unutar tijela funkcije mo?emo koristiti funkciju stopifnot(<logi?ki izraz>). Ova funkcija izra?unava zadani logi?ki izraz i prekida uokviruju?u funkciju ako navedeni uvjet nije istinit.Vje?ba 35: Prva korisni?ki definirana funkcija# napi?ite funkciju `veci` koja prima dva numeri?ka vektora iste duljine # i vra?a vektor koji sadr?i ve?i od dva elementa na istim mjestima# ako jedan ili oba vektora nisu numeri?ki ili nisu iste duljine, # funkcija mora izbaciti gre?ku# u funkciji nemojte koristiti petlje## NAPUTAK: sjetimo se funkcije `ifelse`!# pozovite funkciju `veci` nad kombinacijama vektora# c(T, F, T) i c(1, 2, 3)# c(1, 2, 3, 4) i c(5, 6, 7)# c(1, 2, 3) i c(0, 4, 2)# (preporuka – drugi dio zadatka isprobati direktno u konzoli!)Kod poziva funkcije mo?emo, ali ne moramo, navesti imena parametara, a R dozvoljava mije?anje imenovanih i neimenovanih parametara (iako to nije ne?to ?to bismo trebali ?esto koristiti u praksi). Kada R bude povezivao poslane vrijednosti s formalnim parametrima, imenovani parametri imat ?e prioritet te ?e se prvi razrije?iti, a potom ?e se redom razrje?ivati neimenovani parametri.U ovo se mo?emo uvjeriti u sljede?oj vje?bi. Ova vje?ba usput demonstrira i kori?tenje jedne vrlo korisne funkcije – paste, koja konkatenira znakovne nizove uz automatsko dodavanje razmaka (za spajanje bez razmaka postoji alternativna funkcija paste0).Vje?ba 36: Parametri funkcijeispisiABC <- function(a, b, c) { print(paste("A:", a, "B:", b, "C:", c)) }# razmislite – ?to ispisuje sljede?i poziv funkcije? ispisiABC(1, a = 2, 3)U praksi bismo se trebali dr?ati konvencije da prvo koristimo neimenovane parametre, a potom imenovane. Uobi?ajeno je da postavljamo samo one imenovane parametre ?ija nam nazivna vrijednost ne odgovara, pri ?emu strogi raspored nije bitan (iako ?e pra?enje rasporeda zadanoga potpisom funkcije pove?ati ?itljivost na?ega k?da).Ako ?elimo napisati funkciju koja prima proizvoljan broj argumenata, koristimo se elementom ..., tj. troto?kom. Primjer ovakve funkcije jest gore prikazana ugra?ena funkcija paste koja mo?e primiti proizvoljan broj znakovnih nizova. Ako koristimo troto?ku u na?oj funkciji, u potpisu je u pravilu stavljamo na kraj liste argumenata, a unutar same funkcije ju potom jednostavno pretvorimo u listu te pristupamo njezinim parametrima na na?in koji nam odgovara.Vje?ba 37: Funkcija s proizvoljnim brojem parametaraispisiParametre <- function(...) { parametri <- list(...) for (p in parametri) print(p)}# pozovite gornju funkciju s proizvoljnim parametrimaPrincip kopiranja-kod-izmjene (engl. copy-on-change)Jedno od ?e??ih pitanja koje se postavlja kod u?enja novih programskih jezika jest rade li funkcije na na?in “poziva preko vrijednosti” (engl. call-by-value) ili “poziva preko reference” (engl. call-by-reference). Razlika se svodi na sposobnost funkcije da mijenja vrijednosti varijabli koje su poslane na mjestu formalnih argumenata funkcije; kod call-by-value principa u funkciju se ?alju samo “vrijednosti” parametara, tj. “kopije” originalnih argumenata. S druge strane, kod call-by-reference principa funkcija prima “reference” originalnih varijabli, tj. pona?a se kao da su originalne varijable proslije?ene funkciji i sve izmjene nad njima odraziti ?e se u pozivaju?em programu.Jezik R koristi hibridni princip poznat po nazivom “kopiranje kod izmjene” (engl. copy-on-modify). Kod ovog principa u funkciju se proslje?uju reference argumenata, ?to nam omogu?uje da prenosimo i “velike” varijable bez straha da ?e do?i do nepotrebnog kopiranja. No ovo vrijedi samo ako funkcija ne mijenja vrijednost dobivenih varijabli – u trenutku kada funkcija poku?a provesti bilo kakvu izmjenu, provodi se kopiranje varijable i funkcija dalje nastavlja rad na kopiji. Zbog ovoga se ka?e da R kao takav ne podr?ava call-by-reference (usputno – jedan razlog uvo?enja objekata tipa “reference classes”, tj. RC objekata u jezik R upravo je uvo?enje ovoga principa).Pogledajmo ?to se doga?a kada naivno poku?amo izmijeniti varijablu iz pozivaju?e okoline.Primjer 15: Poku?aj izmjene varijable iz pozivaju?e okolinef <- function(x) { x <- x + 1}x <- 5f(x)print(x)## [1] 5Ako zaista ?elimo da funkcija mijenja varijablu iz pozivaju?e (npr. globalne) okoline, to mo?emo izvesti kori?tenjem operatora <<-. Ovo je takozvani “operator dodjele vanjskom opsegu” (engl. scoping assignment operator), a njegova funkcija jest da izmjeni varijablu zadanog imena koja se nalazi “negdje na stazi pretrage”. R ide slijedno po stazi pretrage i mijenja prvu pojavu navedene varijable. Ako varijabla toga naziva ne postoji nigdje u stazi pretrage, R ?e stvoriti novu varijablu u prvoj okolini iznad okoline funkcije.Primjer 16: Operator <<-# operator `<<-`f <- function(x) { x <- 6 x <<- 7}x <- 5f()x## [1] 7Budu?i da ovaj operator utje?e na varijable izvan svoje okoline, treba biti oprezan s njegovim kori?tenjem.Anonimne funkcijeAko definiramo funkciju, a ne pridru?imo istu nekoj varijabli, onda smo stvorili takozvanu. “anonimnu funkciju”.Primjer 17: Anonimna funkcijafunction(x) x * x Uo?imo da ovime nismo uveli nikakav novi koncept jer je svaka funkcija inicijalno “anonimna”. Ako se vratimo na sintaksu definicije funkcije, vidimo da je ona zapravo kombinacija stvaranja anonimne funkcije i pridjeljivanja iste nekoj varijabli uz operator pridru?ivanja. Naravno, ostavljanje funkcije anonimnom, kao ?to smo izveli u gornjem primjeru, nema previ?e smisla, isto kao ?to nema smisla definirati neki vektor ili listu bez pridjeljivanja reference na taj objekt – u tom slu?aju stvoreni objekt nije ni na koji na?in iskoristiv jer nema nijedne poveznice prema njemu te ?e ga R vrlo brzo obrisati u sklopu rutine “?i??enja sme?a”.Mo?emo se zapitati kako onda izgleda scenarij gdje je kori?tenje anonimne funkcije smisleno i korisno? Eksplicitne anonimne funkcije koristimo kada nam ba? treba “jednokratna” funkcija, recimo kao argument neke druge funkcije. Primjere ovoga vidjet ?emo u kasnijim poglavljima.Objekti u jeziku RRazli?iti objektni modeli jezika RKako bismo objasnili ?to su zapravo generi?ke funkcije, moramo se vratiti na pri?u o programskim paradigmama i ?injenici da je R dizajniran kao objektno orijentirani jezik, zajedno s mehanizmima koje objektno orijentirana paradigma nala?e – enkapsulacija (zdru?ivanje razli?itih varijabli u zajedni?ku cjelinu), polimorfizam (uporaba iste funkcije nad razli?itim objektima rezultirat ?e razli?itim operacijama ovisno o prirodi objekta) i naslje?ivanje (izvo?enje novih objekata iz postoje?ih na na?in da ih pro?irujemo dodatnim elementima).R je svoj inicijalni na?in modeliranja objekata preuzeo iz jezika S te su stoga takvi objekti poznati kao “S3 objekti” (prema ina?ici jezika S iz koje su izvorno preuzeti). Ovaj na?in, koji ?emo upoznati u nastavku, zapravo je vrlo nekonvencionalan, ali i jednostavan za kori?tenje. Upravo ova nekonvencionalnost i jednostavnost zasmetala je R programerima koji te?e slo?enijem, profinjenijem i robusnijem objektnom modelu, tako da ubrzo nastaju tipovi objekata koji vi?e odgovaraju na?inu na koji drugi jezici upravljaju objektima. Novi objektni modeli dobivaju svoje poklonike, ali ne uspijevaju istisnuti osnovni, S3 model, koji ne gubi na popularnosti.Sve ovo dovelo je do toga da danas formalno imamo ?ak tri tipa objekata u programskom jeziku R (tj. ?etiri, ako brojimo i bazi?ne objekte):osnovni objekti (engl. base classes) – osnovni, “bazi?ni” elementi jezika R (funkcije, vektori, podatkovni okviri)S3 objekti – objektni model preuzet iz jezika S (ina?ica 3)S4 objekti – formalniji i rigorozniji na?in stvaranja objekata koji se pribli?ava standardnim objektno-orijentiranim mehanizmima iz drugih jezikaRC objekti (engl. reference classes) – najnoviji na?in stvaranja objekata (uveden u ina?ici R 2.12) koji u potpunosti replicira “klasi?ne” objektno-orijentirane principe utemeljene na razmjeni poruka.Postojanje triju razli?itih modela definiranja objekata (mo?emo zanemariti osnovni jer njega formalno ne mo?emo “pro?irivati” novim objektima) mo?e djelovati demotiviraju?e – je li potrebno nau?iti sva tri modela? Kako ih razlikovati? Koji odabrati? No, usprkos ?injenici da se pri?a o objektnoj prirodi jezika R tijekom njegova razvoja (nepotrebno) zakomplicirala, dobra vijest je da je za ve?inu potreba sasvim dovoljno nau?iti na koji na?in radi model S3. Veliki broj popularnih R paketa koristi isklju?ivo S3 klase i mogu?e je raditi dugo vremena u jeziku R bez potrebe za u?enjem S4 ili RC modela. Zbog ove ?injenice, u nastavku ?emo se usredoto?iti isklju?ivo na S3 klase, dok ?emo bavljenje drugim objektnim modelima ostaviti kao opcionalni izazov za zahtjevnije korisnike.Pregled objektnoga modela S3Kao ?to je ve? re?eno, S3 objekti zapravo su preneseni iz programskog jezika S i predstavljaju relativno primitivno poimanje koncepta “objekta”, barem ?to se ti?e o?ekivanja glede standardnih na?ina stvaranja objekata i pripadaju?ih metoda. S3 objekt je zapravo obi?na lista kojoj smo definirali atribut klase, imena class .Primjer 18: Stvaranje novoga S3 objekta# stvaramo novi objekt klase `osoba`pero <- list(oib = "12345678", prezime = "Peric", tezina = 78)class(pero) <- "Osoba"I to je to! Uo?ite da nemamo formalno definiranoga “predlo?ka” klase koji onda instanciramo u objekt kao ?to je ustaljena praksa u drugim programskim jezicima. Kod S3 objekata jednostavno stvaramo listu i onda deklariramo da je ta lista objekt odre?ene klase, iako je struktura te klase zapravo samo implicirana izgledom objekta (i ne mora uop?e odgovarati strukturi nekog drugog objekta koji se deklarirao kao pripadaju?i istoj klasi).Naravno, ovako le?eran na?in konstrukcije objekata ipak nije preporu?ljiv te se zbog toga savjetuje da klase ne oblikujemo “ru?no”, ve? da to radimo uz pomo? posebne konstruktorske funkcije ?iji ?e parametri zapravo definirati izgled objekta (ovo ?emo nau?iti u lekciji o stvaranju vlastitih funkcija).Mo?emo se pitati ?to se doga?a s naslje?ivanjem ako se klase definiraju na ovako trivijalan na?in?R omogu?uje naslje?ivanje, ali tako?er na vrlo neformalan i relativno trivijalan na?in, i svodi se na to da umjesto navo?enja samo jednoga “naziva” klase uz pomo? atributa class, mi stvorimo znakovni vektor gdje ?e prvi element biti naziv klase, a ostali elementi ?e biti klase roditelji, poredani prema “va?nosti”. Na primjer, ako smo stvorili novi objekt mate klase Zaposlenik nad kojim bismo htjeli koristiti iste implementacije odre?enih generi?kih funkcija razvijenih za potrebe objekata klase Osoba, onda je dovoljno izvesti sljede?e:Primjer 19: Naslje?ivanje S3 objektamate <- list(oib = "12345678", prezime = "Peric", tezina = 78, godZaposlenja = 2001)class(mate) <- c("Zaposlenik", "Osoba")Primijetimo da smo ovdje sav posao oko naslje?ivanja atributa obavili “ru?no”, tj. trebali smo se sami pobrinuti da mate ima atribute klase Osoba koje ?e generi?ka funkcija koju pozivamo koristiti.Ponovimo kratko dosada?nje zaklju?ke o S3 objektima:S3 objekti funkcioniraju na jednostavan, neformalan na?in – to su jednostavno liste s postavljenom proizvoljnom vrijednosti class atributapuno toga ostavljeno je na odgovornosti programerajednostavni su za uporabu ako su jednostavni i objektni modeli koje dizajniramo, ali nisu pogodni za kompleksnije objektne modele zbog te?kog odr?avanja modela i velike mogu?nosti pogre?aka.Generi?ke funkcijeGledaju?i gore definirani na?in dizajna objekta, opravdano je postaviti i dodatno pitanje – a gdje su metode? Kao ?to znamo, standardni objektno-orijentirani principi pretpostavljaju enkapsulaciju atributa ali i metoda u okvir objekta. Upravo tu le?i osnovna razlika izme?u S3 objekta i “standardnih” objekata iz drugih programskih jezika – kod S3 objekata metode se definiraju izvan objekta u obliku takozvanih generi?kih funkcija.Za?to je tomu tako? Ideja je sljede?a – u radu s objektima korisnik (programer, analiti?ar) ?esto poziva iste funkcije (npr. “ispis”, “crtanje”, “sa?eti opis”) nad objektima razli?itoga tipa. Funkcija istog imena ali razli?ite implementacije, ovisno o objektu nad kojim radi, zove se generi?ka funkcija. Tako, recimo, funkcija print uvijek rezultira nekakvim ispisom, ali kako ?e ispis izgledati zapravo ovisi o objektu kojeg ispisujemo.Ovaj na?in dizajna objekata mo?e djelovati iznimno nekonvencionalno, no on ?esto omogu?uje puno intuitivniji rad, pogotovo korisnicima koji nemaju veliko iskustvo s programiranjem. Konkretno, usporedimo naredbu:pokreni(auto, brzina = 20)s naredbom:auto.pokreni(brzina = 20)?itaju?i prvu naredbu, auto do?ivljavamo kao “objekt” (u smislu slu?be rije?i u re?enicu), tj. naredba je oblikovana tako da ne?to radimo “nad” tim objektom. Druga naredba auto postavlja kao subjekt, ?to je uobi?ajena praksa u objektno-orijentiranim jezicima, ali nije u skladu s op?enitim poimanjem obavljanja radnji nad nekim objektima. Drugim rije?ima, u razgovornom jeziku prirodnije je re?i da mi vozimo auto, nego da tra?imo od automobila da vozi samoga sebe.Nadalje, s obzirom na funkcijsku prirodu jezika R, u radu s njim ?esto provodimo “sli?ne” poslove nad razli?itim objektima – ispisujemo njihov sadr?aj, crtamo ih na grafu, tra?imo neke sa?ete detalje o njima i sl. Upravo zbog toga, a i ?injenice da u R-u ?esto radimo interaktivno, R je dizajniran na na?in da razmi?ljamo o tome ?to ?elimo u?initi umjesto da se pitamo gdje je funkcija koju ?elimo pozvati. Ako ?elimo ispisati neki objekt, logi?no je da ga samo proslijedimo funkciji print, ako ga ?elimo nacrtati funkciji plot, a ako ?elimo ispis sa?etka – funkciji summary.Kako pojedina funkcija “zna” ?to u?initi s objektom? Odgovor je jednostavan – generi?ka funkcija je samo “su?elje” prema “pravoj” funkciji koju pozivamo, a logika kako prona?i pravu funkciju je vrlo trivijalna – ako je ime generi?ke funkcije genFun, a naziv klase objekta koju joj proslje?ujemo nazKlase, funkcija koja se zapravo poziva jest genFun.nazKlase. Ako takve funkcije nema, poziva se funkcija genFun.default.U ovo se lako mo?emo uvjeriti samostalno u sklopu sljede?e vje?be.Vje?ba 38: Generi?ke funkcije# ispi?ite tijelo funkcije `summary` # ispi?ite tijelo funkcije koja se zapravo poziva kad pozovete# funkciju `summary` nad objektom klase `factor`Razumijevanjem principa rada generi?kih funkcija upotpunili smo sliku o S3 objektima. Najva?nija stvar koju moramo usvojiti jest da kod ovog modela funkcije nisu dio samog objekta, ve? se definiraju zasebno, a poveznica izme?u objekta i “njegove” metode jest samo u nazivu funkcije pomo?u kojega ?e R “povezati” generi?ku funkciju i taj objekt. Iako je ovaj princip primitivan i podlo?an gre?kama u rukama nepa?ljivoga programera, on je neupitno jednostavan za uporabu i vrlo u?inkovit. Kona?no, uo?imo da ovaj pristup nije u potpunosti svojstven isklju?ivo jeziku R – sli?ne principe nalazimo i u drugim programskim jezicima (npr. Python povezuje print funkciju i objekt preko posebne metode objekta __str__). R je samo specifi?an po tome ?to taj princip koristi kao nazivni mehanizam dizajna metoda za svoje objekte.Objekte i generi?ke funkcije ponovo ?emo posjetiti kada nau?imo stvarati vlastite funkcije, ?to ?e nam omogu?iti da stvorimo kako konstruktore na?ih objekata tako i njihove generi?ke funkcije.Stvaranje vlastitih konstruktorskih i generi?kih funkcijaKonstruktorske funkcijePrisjetimo se pri?e o S3 objektima. Rekli smo da je S3 jedan prili?no neformalan objektni model, gdje programer zapravo s?m “sla?e” vlastiti objekt punjenjem liste novim elementima te pridjeljivanjem (proizvoljnoga) naziva klase. Pogledajmo ponovo primjer stvaranja objekta klase osoba:Primjer 20: Stvaranje novoga S3 objekta (ponavljanje)# stvaramo novi objekt klase `osoba`pero <- list(oib = "12345678", prezime = "Peric", tezina = 78)class(pero) <- "Osoba"Ovakav na?in stvaranja objekata vrlo je problemati?an i podlo?an pogre?kama. Puno bolji na?in je stvaranje zasebne funkcije koja ?e “slo?iti” objekt na osnovu zadanih parametara. Ovo je takozvani konstruktor ili konstruktorska funkcija. Sintaksno gledano, konstruktorska funkcija je samo “obi?na” funkcija koja sla?e objekt umjesto nas, no prebacivanjem odgovornosti stvaranja objekta na zasebnu funkciju pru?amo na?in konzistentnoga, robusnoga stvaranja objekta, pogotovo ako u funkciju ubacujemo razne provjere ispravnosti ulaznih podataka.Primjer 21: Konstruktorska funkcija# konstruktor klase osobaOsoba <- function(oib, prezime, tezina) { stopifnot(is.character(oib)) stopifnot(is.character(prezime)) stopifnot(is.numeric(tezina) && tezina > 0) o <- list(oib = oib, prezime = prezime, tezina = tezina) class(o) <- "Osoba" o}Poku?ajmo sada u idu?oj vje?bi iskoristiti ovu funkciju za stvaranje novog objekta klase Osoba.Vje?ba 39: Stvaranje objekta uz konstruktorsku funkciju# stvorite varijablu `ivo` koja ?e biti klase `Osoba`, a koja ?e imati sljede?e vrijednosti atributa:# OIB: 1357135713, prezime: Ivi?, tezina: 76# ispi?ite varijablu `ivo`Uo?imo da je kod ispisa na?eg objekta R iskoristio funkciju print.default koja je na? objekt ispisala kao listu (?to on zapravo i jest). Ako ?elimo neki druga?iji, prilago?eni ispis, moramo dodati novu generi?ku funkciju ciljano orijentiranu klasi Osoba. Ovo ?emo izvesti u sljede?oj lekciji.Vlastite generi?ke funkcijeU lekciji o generi?kim funkcijama nau?ili smo da R metode objekata definira “izvan” objekata u obliku generi?kih funkcija koje onda proslje?uju poziv “pravim” implementacijama. Tako?er smo nau?ili da je mehanizam koji ovo omogu?uje vrlo jednostavan, tj. da je dovoljno implementirati novu funkciju naziva genFun.nazKlase (uz pretpostavku da je naziv generi?ke funkcije genFun). R ?e potom automatski pozivati doti?nu funkciju kod poziva genFun(objekt), gdje je objekt klase nazKlase.Poku?ajmo sada iskoristiti na?e znanje o stvaranju korisni?ki definiranih funkcija kako bismo omogu?ili prilago?eni ispis objekata klase Osoba uz pomo? funkcije print.Vje?ba 40: Vlastita generi?ka funkcija# napi?ite novu funkciju koja ?e omogu?iti ispis klase `Osoba`# uz pomo? generi?ke funkcije `print`# ispis mora izgledati ovako:# OIB: <oib>, Prezime: <prezime>, tezina: <tezina># unutar tijela funkcije za slaganje ispisa koristite funkciju `paste`# a za sam ispis funkciju `cat`# ispi?ite varijablu `ivo` uz pomo? generi?ke funkcije `print`Ovime zaokru?ujemo pri?u o korisni?ki definiranim funkcijama. U nastavku te?aja usredoto?it ?emo se na funkcije i pakete jezika R koji na? rad ?ine jednostavnijim i u?inkovitijim te omogu?uju brz i ugodan rad s podatkovnim skupovima.Dodatni zadaci za vje?buStvorite podatkovni okvir mjesto uz pomo? sljede?e naredbe:mjesto <- data.frame( pbr = c(10000, 51000, 21000, 31000, 2000), nazivMjesta = c("Zagreb", "Rijeka", "Split", "Osijek", "Dubrovnik"), prirez = c(18, 15, 10, 13, 10))Dodajte ovom okviru stupac prirezOpis koji ?e biti kategorijska varijabla s razinama "mali", "srednji" i "visok" ovisno o tome je li postotak prireza strogo manji od 12, izme?u 12 i 15 ili strogo ve?i od 15. Koristite se naredbom ifelse.Zamijenite petlje u sljede?em bloku ekvivalentnim vektoriziranim operacijama (za drugu petlju prou?ite dokumentaciju funkcije sum).a <- numeric()i <- 1while (i <= 100) { a <- c(a, i) i <- i + 1}suma <- 0for (i in a) { if (i %% 2 == 0) suma <- suma + i*i}print(suma)Stvorite objekt klase Kvadar s atributima visina, sirina i dubina jednakim 10, 20 i 30.Sljede?a naredba stvorit ?e vektor od 20 nasumi?no odabranih prirodnih brojeva od 1 do 100. Uz pomo? internetske tra?ilice i/ili slu?bene dokumentacije prona?ite ugra?ene funkcije koje izvr?avaju zadane zadatke.# u?itavamo 20 prirodnih brojeva od 1 do 100, s ponavljanjemset.seed(1234)a <- sample(1:100, 20, replace = T)Ispi?ite:vektor avrijednosti vektora a poredane obrnutim redoslijedomjedinstvene vrijednosti iz vektora avrijednosti vektora a poredane uzlazno.R ima funkciju which koja pretvara logi?ki vektor u numeri?ki s rednim brojevima elemenata koji su TRUE (tako c(T, F, F, F, F, T, F, T) postaje c(1, 6, 8)). Implementirajte vlastitu ina?icu ove funkcije.Implementirajte konstruktor klase Zaposlenik koja naslje?uje objekt klase Osoba sa sljede?om konstruktorskom funkcijom i funkcijom ispisa:Osoba <- function(oib, prezime, tezina) { o <- list(oib = oib, prezime = prezime, tezina = tezina) class(o) <- "Osoba" o}print.Osoba <- function(o) { rez <- paste("OIB:", o$oib, ", Prezime:", o$prezime, ", tezina:", o$tezina, "\n") cat(rez)}Zaposlenik uz atribute klase Osoba ima i atribut nadredjeni koji predstavlja referencu na nadre?enoga zaposlenika (ako postoji; ina?e je NULL).Stvorite dva objekta klase Zaposlenik (jedan nadre?en drugom) i ispi?ite ih uz pomo? funkcije print. Potom implementirajte vlastitu ina?icu generi?ke funkcije print za klasu Zaposlenik koja ispisuje podatke o zaposleniku i podatke o nadre?enom zaposleniku (ako postoji; ina?e ispisuje poruku da nema nadre?enoga zaposlenika). Ponovo ispi?ite oba zaposlenika uz pomo? funkcije print.Deklarativne programske petljePorodica funkcija applyOp?enito o porodici funkcija applyU prethodnoj lekciji nau?ili smo da su programske petlje u jeziku R relativno “nepo?eljne”. Glavni razlog tomu jest vektorizirana, deklarativna priroda jezika gdje uporabom operatora i/ili pozivom funkcije vrlo ?esto implicitno tra?imo da se obradi vi?e od jednog elementa. Ovo je u suprotnosti s prirodom programskih petlji gdje ?esto programskim naredbama prvo eksplicitno obja?njavamo kako se “pro?etati” po odabranoj podatkovnoj strukturi, da bismo tek unutar petlje objasnili kako obraditi pojedini element te dali eventualne detalje za slaganje rezultata.Kod obrade podataka ?esto nam nije dovoljna jedna programska petlja – na primjer, zamislimo da ?elimo pohraniti zbrojeve redaka neke matrice. Ovo zna?i da moramo pro?i kroz sve retke matrice te da za svaki redak moramo pro?i kroz sve njegove elemente kako bismo ih sumirali. Ovo je ?esto kori?teni scenarij “petlje unutar petlje” gdje opet svu logiku “?etanja” po podatkovnoj strukturi moramo eksplicitno opisati naredbama.Programski jezik R za sve ove scenarije preferira deklarativni pristup. Ovo okvirno zna?i da se u jeziku R potencira usredoto?avanje na samu logiku obrade – ?to ?elimo posti?i – a ne logiku koja opisuje kako prolaziti kroz strukturu. Ovo pogotovo ima smisla ako uo?imo da je logika prola?enja kroz strukturu zapravo relativno trivijalna – za jednodimenzionalne strukture idemo element-po-element, za dvodimenzionalne po redcima ili stupcima unutar kojih opet element-po-element itd. Drugi razlog je ve?a u?inkovitost k?da – ako logiku prola?enja kroz strukturu prepustimo ugra?enim funkcijama umjesto da je eksplicitno sami pi?emo, smanjujemo mogu?nost pogre?ke i omogu?ujemo bolju optimizaciju (uz pretpostavku da dizajneri programskoga jezika implementiraju odre?ene optimizacijske rutine unutar ugra?enih funkcija koje provode samo “petljanje”).Upravo iz ovog razloga osmi?ljena je takozvana porodica funkcija apply. Ovo su funkcije koje nam, uz samu vektoriziranu prirodu jezika, omogu?uju da slo?enije kombinacije programskih petlji tako?er izrazimo deklarativno tj. da prepustimo niskorazinsku logiku “petljanja” i slaganja rezultata ugra?enoj funkciji te da se usredoto?imo na posao koji treba u?initi nad svakim pojedinim elementom. Ovaj princip sukladan je ve? spomenutim principima funkcionalnoga programiranja, ?to ?e pogotovo postati o?ito kada uo?imo ?injenicu da je klju?an ulazni parametar svake funkcije iz porodice apply referenca na neku drugu funkciju koja obavlja tra?eni posao nad elementima.Naziv porodice potje?e od ?injenice da (gotovo) sve funkcije iz nje imaju sufiks “apply”. Neki ?lanovi ove porodice su:applylapplysapplyvapplytapply, mapply, rapply itd.Sve ove funkcije rade na sli?an na?in – kao ulazne argumente primaju skup podataka, funkciju koju ?elimo primijeniti na elemente toga skupa te opcionalne dodatne parametre, a kao izlaz daju skup rezultata funkcije, naj?e??e “upakirane” u prigodni format. Razlika se uglavnom svodi na tipove ulaznih i izlaznih argumenata, te konkretne detalje oko provedbe same funkcije i/ili pripreme rezultata.?lanove apply porodice najlak?e je nau?iti kroz primjere. Zapo?et ?emo s funkcijom koja dijeli ime s cijelom porodicom – funkcijom apply.Funkcija applyKao ?to je re?eno, funkcija apply jedina je koja doslovno dijeli ime s porodicom ovih funkcija. Namijenjena je radu s matricama (zapravo s poljima, ali s obzirom na to da se relativno rijetko radi sa strukturama koje imaju vi?e od dvije dimenzije, ovdje ?emo se usredoto?iti samo na matrice).Sintaksa naredbe je sljede?a:rezultat <- apply( <matrica>, <redovi (1) ili stupci (2)>, <funkcija> )Ili, opisano rije?ima, za provo?enje funkcije apply:odaberemo matricuodlu?imo “?e?emo” li se po redcima ili stupcimaprimjenjujemo odabranu funkciju na sve retke ili stupce jedan po jedan.Ovisno o tome ?to funkcija radi, kao rezultat dobivamo matricu ili (?to je ?e??i slu?aj) vektor.Poku?ajmo primijeniti ovu funkciju na konkretnom primjeru.Vje?ba 41: Funkcija applym <- matrix(1:9, nrow = 3, ncol = 3, byrow = TRUE)# ispi?ite matricu `m`# uz pomo? funkcije `apply` izra?unajte # i ispi?ite zbrojeve stupaca matrice `m` # (funkcija `sum`!)# uz pomo? funkcije `apply` izra?unajte # i ispi?ite umno?ke redaka matrice `m` # (funkcija `prod`!)Ako ?elimo nad redcima/stupcima provesti neki specifi?an zadatak, za to vrlo ?esto koristimo anonimnu funkciju, na primjer:Primjer 22: Funkcija apply i anonimne funkcije# izvla?imo prvi i zadnji element svakoga retkaapply(m, 1, function(x) c(x[1], x[length(x)])) ## [,1] [,2] [,3]## [1,] 1 4 7## [2,] 3 6 9Poku?ajmo ovo samostalno izvesti u sljede?oj vje?bi.Vje?ba 42: Funkcija apply i anonimne funkcije# uz pomo? funkcije `apply` za svaki redak matrice `m` # izra?unajte prirodni logaritam sume elemenata# zaokru?en na 2 decimale (funkcija `round`!)Ponovimo – funkcija apply (i srodne funkcije) implicitno rastavljaju ulaznu podatkovnu strukturu na elemente. U primjerima gore ti elementi – retci ili stupci – zapravo su numeri?ki vektori. Argument x koji prima anonimna funkcija je upravo taj vektor ili, bolje re?eno svaki od tih vektora koji joj se proslje?uju jedan po jedan. Rezultati funkcije se pamte i “pakiraju” u kona?ni rezultat.Poku?ajmo rije?iti zadnju vje?bu bez kori?tenja funkcije apply.Vje?ba 43: Petlja kao alternativa funkciji apply# uz pomo? programske petlje za svaki redak matrice `m` # izra?unajte prirodni logaritam sume elemenata# zaokru?en na 2 decimale (funkcija `round`!)# rezultat pohranite ovdje:rez <- numeric(nrow(m))Ako usporedimo sintakse primjera s i bez kori?tenja funkcije apply, mo?emo se uvjeriti koliko je sintaksa koja koristi apply zapravo “?i??a” i preglednija. Ako koristimo petlje moramo eksplicitno navesti logiku prola?enja strukturom i ?uvanja me?urezultata, ?to odvla?i pa?nju od opisa posla koji zapravo ?elimo obaviti.?to ako apply funkciji ?elimo proslijediti vi?e parametara? Na primjer, recimo da umjesto gornje funkcije koja izvla?i prvi element retka ?elimo funkciju s dva parametra – prvi je vektor, a drugi cijeli broj koji ozna?ava koji broj treba izvu?i. Odgovor je jednostavan – dodatne parametre jednostavno navedemo na kraju poziva funkcije.Primjer 23: Funkcija apply i dodatni parametri pozivajuce funkcije# apply funkcija i ulazna funkcija s vi?e parametaraapply(m, 1, function(x,y) x[y], 2) # izvla?imo drugi element svakoga retka## [1] 2 5 8Ovaj primjer treba shvatiti samo kao demonstraciju proslje?ivanja dodatnih parametara pozvanoj funkciji jer izvla?enje drugog elementa svakoga retka neke matrice zapravo tra?i drugi stupac i u ovom slu?aju u praksi se ne?emo koristiti funkcijom apply ve? jednostavno operatorom indeksiranja.Kona?no, treba napomenuti da za sli?nu obradu podataka u matri?nom obliku ne moramo nu?no koristiti apply – dosta popularnih operacija, kao ?to su zbrajanje elemenata redaka ili stupaca, ra?unanje prosjeka elemenata redaka i stupaca i sl. ve? je implementirano kroz funkcije kao ?to su rowSums, colSums, rowMeans, colMeans i sl. One su jednostavnije za uporabu, no specijalizirane – za dodatnu fleksibilnost naj?e??e je apply najpogodnija opcija.Funkcija lapplyIme funkcije lapply dolazi od rije?i “list apply” – tj. “apply funkcija koja radi s listama”. Jednostavno re?eno radi se o funkciji koja ?e kao ulazni argument primiti listu i neku funkciju, primijeniti funkciju na svaki pojedini element liste i rezultat vratiti opet u obliku liste.Vje?ba 44: Funkcija lapplyl <- list(a = 1:3, b = rep(c(T, F), 10), c = LETTERS)# pomo?u funkcije `lapply` izra?unajte duljinu (broj elemenata) # svakog elementa liste `l`Isto kao kod funkcije apply, kod funkcije lapply ?esto kao parametar koristimo anonimne funkcije. Poku?ajmo u sljede?oj vje?bi napisati malo slo?eniju anonimnu funkciju za obradu elemenata zadane liste.Vje?ba 45: Funkcija lapply i anonimne funkcije# obradite elemente liste `l` na sljede?i na?in:# - izra?unajte srednju vrijednost ako se radi o numeri?kom vektoru# - prebrojite vrijednosti TRUE ako se radi o logi?kom vektoru# - ispi?ite duljinu vektora za sve ostale slu?ajeve# kona?ni rezultati moraju biti pohranjeni u novu listu# koristite funkciju `lapply` i anonimnu funkciju# ne zaboravite da i anonimna funkcija mo?e koristiti blokove!Razmotrimo jednu bitnu ?injenicu – funkcija lapply namijenjena je uporabi nad listama, a podatkovni okviri su zapravo liste. Drugim rije?ima, funkcija lapply je vrlo zgodna za obradu tabli?nih podataka kada ?elimo odre?enu funkciju primijeniti na stupce podatkovnog okvira.Isprobajmo ovo u sljede?oj vje?bi. Jedna od ?e??ih operacija koje se provode kod analize podataka jest takozvana “normalizacija” numeri?kih stupaca podatkovnog okvira, tj. svo?enje svih numeri?kih vrijednosti na “normalnu” distribuciju aritmeti?ke sredine 0 i standardne devijacije 1. Ovo mo?emo uraditi tako da svaku pojedinu vrijednost umanjimo za aritmeti?ku sredinu stupca (funkcija mean) te podijelimo sa standardnom devijacijom stupca (funkcija sd). Ovo je odli?an scenarij za demonstraciju kori?tenja funkcije lapply.Vje?ba 46: Funkcija lapply i podatkovni okviridf <- data.frame( a = 1:10, b = seq(100, 550, 50), c = LETTERS[1:10], d = rep(c(T,F), 5), e = -10:-1)# normalizirajte numeri?ke stupce uz pomo? funkcije `lapply`# ostale stupce nemojte mijenjati# normalizirane vrijednosti zaokru?ite na tri decimale# rezultat pohranite u varijablu df# ispi?ite dfJedna od stvari koja nas mo?e zasmetati jest ta da smo nakon kori?tenja funkcije lapply dobili listu – ovo je posljedica prirode ove funkcije, kod koje su i ulaz i izlaz uvijek lista. Nama bi vjerojatno vi?e odgovaralo da izlaz bude podatkovni okvir. Postoje dva na?ina da ovo vrlo jednostavno omogu?imo: prvi na?in jest da rezultat funkcije proslijedimo funkciji as.data.frame, a drugi da varijabli postoje?eg podatkovnog okvira kojoj pridru?ujemo rezultat dodamo uglate zagrade (?to R interpretira kao “stavi rezultat u stupce ovog podatkovnog okvira”).Primjer 24: Pretvaranje rezultata funkcije lapply u podatkovni okvir# prvi na?indf <- as.data.frame(lapply(df, <funkcija>))# drugi na?indf[] <- lapply(df, <funkcija>)Funkcija sapplyFunkcija lapply je u su?tini dosta jednostavna za kori?tenje i ba? zbog te ?injenice vrlo popularna. No ve? smo napomenuli ?injenicu da ona uvijek kao rezultat vra?a listu, iako bi nam nekada vi?e odgovarala neka druga podatkovna struktura, kao na primjer vektor. Jedna stvar koju mo?emo poku?ati izvesti nad rezultatom funkcije lapply jest primijeniti funkciju unlist koja ?e “pojednostaviti” listu u obi?ni vektor ako ona sadr?i jednostavne, jedno?lane elemente.Vje?ba 47: Funkcija unlistl <- list(a = 1:10, b = 10:20, c = 100:200)# izra?unajte srednje vrijednosti elemenata liste `l`# rezultate ispi?ite kao numeri?ki vektor# koristite lapply i unlistPrikazana kombinacija lapply i unlist ?e nam kao rezultat dati jednodimenzionalni vektor, ?to nam u velikom broju slu?ajeva odgovara. No, ponekad bi nam vi?e odgovarala neka druga podatkovna struktura, na primjer matrica. U ovom slu?aju potreban nam je i dodatni korak preoblikovanja jednodimenzionalnoga vektora u matricu uz pomo? funkcije matrix, pri ?emu moramo eksplicitno zadati broj redaka i stupaca.Mo?e se postaviti pitanje za?to funkcija lapply ne bi mogla “pogledati” rezultat koji je dobila i sama odrediti optimalnu podatkovnu strukturu za oblikovanje rezultata (vektor, matrica ili lista)? Upravo ta ideja stoji iza funkcije sapply ili “simplified list apply”. Ova funkcija prvo interno obavlja lapply, a potom se rezultat pojednostavljuje na vektor, matricu ili polje, ovisno o karakteristikama dobivenih rezultata.Vje?ba 48: Funkcija sapplyl <- list(a = 1:10, b = 10:20, c = 100:200)# izra?unajte medijane elemenata liste `l` # i rezultate ispi?ite kao numeri?ki vektor# koristite funkciju `sapply`# izvucite prvi i zadnji element svakog od elemenata liste `l`# koristite `sapply` i anonimnu funkcijuUo?ite da smo kao rezultat zadnjega primjera dobili matricu, ali da ju je R oblikovao “po stupcima”. Ako bismo htjeli matricu s elementima poredanim po redcima, za to, na?alost, ne mo?emo koristiti sapply jer se matrica formira interno, bez mogu?nosti proslje?ivanja parametra byrow = T. Za dobivanje takve matrice jedna opcija nam je ve? spomenuta kombinacija funkcija lapply, unlist i matrix ili, ?to je jednostavnije, transponiranje rezultata sapply uz pomo? funkcije t (od engl. transpose).Funkcija sapply je prili?no popularna, pogotovo za interaktivni rad. No, moramo napomenuti njezinu pone?to nepredvidljivu prirodu – tip rezultata ?esto nije unaprijed poznat, ve? se on odre?uje na osnovi dobivenoga rezultata. Upravo zbog toga treba biti oprezan ako se ova funkcija ugra?uje u programske skripte koje o?ekuju rezultat to?no odre?enoga tipa. U tim slu?ajevima preporu?uje se pogledati funkciju vapply koja predstavlja “robusnu” ina?icu funkcije sapply, a zapravo kombinira funkciju sapply i deklaraciju “o?ekivanoga” rezultata, tako da ?e skripta prestati s radom ako rezultat ne odgovara o?ekivanom.Za kraj poka?imo jednu ?estu kori?tenu sintagmu funkcije sapply u sprezi s podatkovnim okvirima:Primjer 25: Ispis klasa stupaca podatkovnog okvira# podatkovni okvir `iris` je jedan od# ugra?enih podatkovnih skupovasapply(iris, class) ## Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## "numeric" "numeric" "numeric" "numeric" "factor"Iako smo ovu informaciju mogli dobiti i uz pomo? funkcije str, prikazani na?in je jedan od najbr?ih za dobivanje uvida u klase stupaca podatkovnih okvira te ga R programeri ?esto koriste nakon u?itavanja novoga podatkovnog skupa.Ostale funkcije iz porodice applyU prethodnim poglavljima naveli smo vjerojatno najpopularnije ?lanove porodice apply. Ova porodica ima jo? ?lanova, uklju?uju?i i neke koji nemaju sufiks -apply:mapply, koja primjenjuje funkcije paralelno nad vi?e podatkovnih strukturavapply, ve? spomenuta “robusna” ina?ica sapplyrapply, koja rekurzivno primjenjuje funkcije unutar strukturetapply, koja primjenjuje funkcije nad podskupovima unutar strukture definirane faktorimaMap, ina?ica mapply koja ne pojednostavljuje rezultatby, ina?ica tapply predvi?ena za podatkovne okvireitd.Razlog za?to ove funkcije ne?emo detaljno obra?ivati jest dvojak: prvo, kao ?to je ve? re?eno, ovi ?lanovi porodice apply u praksi se primjenjuju puno rje?e od funkcija apply, lapply i sapply koje smo prikazali u prethodnim poglavljima; drugo, porastom popularnosti jezika R pojavio se i veliki broj paketa orijentiranih upravo pobolj?anju postoje?ih funkcija u smislu lak?eg i u?inkovitijeg programiranja, osobito u radu s podatkovnim okvirima. U nastavku ?emo pogledati neke od ovih paketa i funkcija.Alternativa funkcijama iz porodice applyPaket purrrOsnovna ideja paketa purrr jest definiranje skupa “alata” koji ?e R programerima omogu?iti pra?enje principa funkcijskoga programiranja na konzistentan i pregledan na?in. Jedna od o?itih razlika izme?u funkcija koje pru?a ovaj paket i ?lanova porodice apply jest ta ?to paket purrr umjesto termina apply koristi termin map, ?to je sukladno terminu koji se koristi u drugim programskim jezicima za obavljanje sli?noga posla (tj. gdje se primjena funkcije na sve ?lanove nekoga skupa ?esto naziva “mapiranje”). Isto tako, paket purrr omogu?uje jasno definiranje tipa rezultata ve? kroz sam naziv funkcije, pa ?e tako funkcija map_lgl kao rezultat dati logi?ki vektor, a map_dfr podatkovni okvir.Paket purrr ne?emo detaljno obra?ivati, no korisnicima koji imaju interes ?to vi?e se prilagoditi funkcijskoj programskoj paradigmi definitivno se preporu?uje detaljnije prou?avanje dokumentacije ovoga paketa.Paket plyrPaket plyr nastao je iz ?elje da se “poprave” odre?eni nedostaci porodice funkcija apply, osobito vezani za nekonzistentne potpise funkcija, nazive parametara i tipove rezultata. Ovaj paket tako?er dodaje neke zgodne funkcionalnosti, kao ?to su bolje procesiranje gre?aka, podr?ka za paralelno procesiranje itd.Sli?no funkcijama paketa purrr (koji je zapravo nastao kasnije), paket plyr definira funkcije ?iji naziv opisuje na?in djelovanja funkcije. Osnovica paketa plyr su takozvane XXply funkcije gdje ply zapravo predstavlja skra?enicu od apply, a dva po?etna slova opisuju ulaz i izlaz u funkciju, konkretno:d kao podatkovni okvir (engl. data frame)a kao matricu/polje (engl. array)l kao listu.Tako, na primjer, imamo funkciju ldply koja kao ulaz prima listu te vra?a podatkovni okvir, ili alply koja kao ulaz prima matricu (ili polje) i vra?a listu.Paket plyr dugo je vremena bio jedan od najpopularnijih R paketa, zadr?avaju?i mjesto u top 5 najvi?e kori?tenih CRAN paketa iz godine u godinu. Jedini razlog relativnoga pada njegove popularnosti u zadnjih nekoliko godina jest pojava njegovoga svojevrsnog “nasljednika”, paketa dplyr, koji se strogo orijentirao obradi podataka unutar podatkovnih okvira te uveo novi princip upravljanja okvirima donekle inspiriran jezikom SQL. Ovaj paket je toliko dobro prihva?en da ga veliki dio R programera smatra integralnim i nezaobilaznim dijelom jezika R, tako da ?emo ga djelomi?no upoznati i u nastavku ovoga te?aja.U?inkovito programiranje i upravljanje podatkovnim skupovimaOperator cjevovodaKori?tenje operatora cjevovodaPogledajmo sljede?i primjer: zamislimo da u jeziku R ?elimo stvoriti 100 nasumi?nih realnih varijabli u rasponu [0,100], zaokru?iti ih na dvije decimale, iz ovog skupa odabrati uzorak od 10 varijabli, izra?unati aritmeti?ku sredinu uzorka i ispisati ga na zaslon. Jedno od mogu?ih programskih rje?enja moglo bi biti sljede?e:Primjer 26: Ulan?ano pozivanje funkcijaset.seed(1234) # (zbog ponovljivosti)# rje?enje gornjega primjerarez <- runif(100, 0, 100) # 100 nasumi?nih brojeva iz uniformne razdiobe od 0 do 100rez <- round(rez,2)rez <- sample(rez, 10)rez <- mean(rez)rez## [1] 51.123Ovakav k?d ima dosta nepotrebnoga ponavljanja – u svakom retku koristimo varijablu rez koja ?uva me?urezultate i operator pridru?ivanja pomo?u kojega pridru?ujemo nove rezultate varijabli rez. Alternativno, mogli smo sve obaviti u jednom retku.Vje?ba 49: U?ahurene funkcijeset.seed(1234)# ponovite gornji primjer, ali uz pomo? samo jednoga retka programskoga k?daOvdje vidimo jedan tipi?an primjer “kodnoga sendvi?a”, koji nije problem samo u R-u, ve? se pojavljuje u ve?ini programskih jezika – rezultat jedne funkcije postaje ulaz u drugu te ako ?elimo sve obaviti bez eksplicitnog ?uvanja me?urezultata, kao rezultat ?emo dobiti programski k?d koji je podlo?an gre?kama kod pisanja te je vrlo te?ko ?itljiv.Prirodan na?in interpretacije ovakvoga primjera bio bi “slijeva na desno”; kad obavimo jedan posao, rezultat postaje ulaz u drugi posao i tako sve do zavr?etka procesa. Ako bi postojao na?in za predo?avanje ovakve intuitivne interpretacije programskim k?dom, pojednostavili bismo si ne samo pisanje k?da ve? bi takav k?d postao daleko ?itljiviji i lak?i za odr?avanje i eventualnu naknadnu prilagodbu. Upravo ovo bila je motivacija za razvoj takozvanoga “pipeline” operatora koji nudi paket magrittr.Paket ?udnog imena zapravo je inspiriran imenom apstraktnoga slikara Renea Magrittea, to?nije njegovom slavnom slikom “La trahison des images” koja prikazuje lulu ispod koje su rije?i “Ceci n’est pas une pipe”. Cjevovodni, tj. “pipeline” operator izgleda ovako: %>%, a programski k?d ?ini daleko ?itljivijim te je postao izrazito omiljen u R zajednici, pogotovo kod procedura koje uklju?uju intenzivno “ulan?avanje” funkcija.Kako radi %>%operator? Vrlo jednostavno – postavimo ga nakon poziva neke funkcije i iza njega navedemo poziv druge funkcije u kojem mjesto rezultata prve nazna?imo to?kom. Ovo mo?emo raditi koliko god puta ?elimo, tj. ovisno o tome koliko poziva “ulan?avamo”.h(g(f(x), y), z, w) # k?d bez %>% operatoraf(x) %>% g(., y) %>% h(., z, w) # k?d s %>% operatoromAko je rezultat prethodne funkcije na prvom mjestu sljede?e funkcije, onda se to?ka (?tovi?e, cijeli taj argument) mo?e izbaciti, tako da je sintaksa jo? kra?a:f(x) %>% g(y) %>% h(z,w) # k?d s %>% bez kori?tenja to?keAko ne ?elimo koristiti to?ku, moramo samo voditi ra?una o tome da su pozivi funkcija u lancu zapravo formalno nepravilni, jer imaju “nevidljivi” prvi argument. Usprkos tomu, mnogi R programeri vole ovakvu sintaksu jer zahtijeva manje tipkanja i ne?to je preglednija, a spomenuta nepravilnost ne smeta dok god je programer upoznat s postojanjem “nevidljivog” argumenta.Probajmo sada preoblikovati na? prvi primjer uz pomo? %>% operatora.Vje?ba 50: Operator %>%set.seed(1234)# ponovo rije?ite primjer s po?etka poglavlja, ali uz pomo? %>% operatoraUo?ite kako ?itanjem gornjega programskog k?da vrlo lagano interpretiramo smisao te linije programskoga k?da, pogotovo u usporedbi s istom naredbom napisanom u obliku “sendvi?a”.Krajnji rezultat na?ega “lanca” funkcija mo?emo pohraniti uobi?ajenim na?inom:suma <- 1:10 %>% sum # rezultat se pohranjuje u varijablu 'suma'a ako se ?eli zadr?ati laka interpretacija “slijeva nadesno”, mo?e se koristiti i “obrnuti” operator pridru?ivanja: ->.1:10 %>% sum -> suma # radi istovjetno gornjem primjeruUo?ite da u situacijama kada je rezultat prethodne funkcije jedini parametar sljede?e, zagrade mo?emo izbaciti u potpunosti (dakle, u gornjim primjerima sum, sum() ili sum(.) bi svi radili jednako).Poku?ajmo sada kombinirati %>% operator i lapply.Vje?ba 51: Funkcija lapply i operator %>%l <- list(a = 1:10, b = 10:20, c = 100:200)# stvorite matricu koja ?e sadr?avati prvi i zadnji element svakog elementa liste# elementi moraju biti poredani po redcima# koristite funkcije lapply, unlist i matrix te %>% operator# rezultat spremite u varijablu `rez` # ispi?ite `rez`%>% operator je posebno pogodan za upravljanje podatkovnim skupovima, osobito u scenarijima kada imamo definiranu proceduru transformacije podataka (npr. filtriramo neke retke, potom odaberemo stupce, zatim grupiramo podatke ovisno o nekoj kategorijskoj varijabli). Uz pomo? ovog operatora dobivamo preglednu reprezentaciju na?ega procesa prilagodbe podataka koju kasnije lako prilago?avamo i po potrebi pro?irujemo. Primjeri u nastavku ?e ?esto prema potrebi koristiti ovaj operator, te preporu?ujemo njegovo svladavanje prije nastavka s lekcijama koje slijede.Operator cjevovoda i drugi operatoriOperator cjevovoda vrlo je pogodan u sprezi s “klasi?nim” funkcijama, no mo?emo nai?i na problem kada ga ?elimo kombinirati s drugim operatorima. Uzrok problema jest sintaksa - operator cjevovoda svoju u?inkovitost posti?e upravo nametanjem nove, “slijedne” sintakse, koja nije kompatibilna sa sintaksom koju name?u drugi operatori, kao npr. +, %% ili [.Ukoliko nam je zaista bitno da u na?em programskom kodu imamo “neprekinuti” lanac poziva funkcija koji ?e sadr?avati ne samo funkcije, nego i druge operatore, onda je jedno od rje?enja koristiti operatore kao “obi?ne” funkcije. Naime, svaki operator je zapravo funkcija koja dijeli ime s operatorom (uz kori?tenje backtick navodnika kako bi se mogli koristiti simbolima), tako da su sljede?i parovi izraza zapravo ekvivalentni:Primjer 27: Operatori kao funkcije# svaki par naredbi jest ekvivalentan2 + 3`+`(2, 3)1 : 5`:`(1, 5)x <- c(1, 2, 3)`<-`("x", c(1,2,3))x[1]`[`(x, 1)## [1] 5## [1] 5## [1] 1 2 3 4 5## [1] 1 2 3 4 5## [1] 1## [1] 1Poku?ajmo ovaj princip iskoristiti u sljede?oj vje?bi.Vje?ba 52: Slo?enija uporaba operatora cjevovodaset.seed(1234)# "uredite" sljede?u naredbu uz pomo? operatora cjevovoda matrix(table(sample(round(sqrt(sample(1:10000, 10000, replace = T))), 100))[1:9], 3, 3)## [,1] [,2] [,3]## [1,] 1 2 1## [2,] 1 3 1## [3,] 1 1 2U?inkovito upravljanje podatkovnim skupovimaPaket dplyrPaket dplyr jedan je od novijih paketa jezika R ?ija je glavna funkcija u?inkovito i pojednostavljeno upravljanje podatkovnim okvirima uz pomo? skupa intuitivno dizajniranih funkcija. U trenutku pisanja ove lekcije i dalje se nalazi na vrhu liste najpopularnijih paketa usprkos jakoj “konkurenciji” u ovom podru?ju koju ?ine iznimno popularni paketi kao ?to su plyr, data.table, ali i osnovne, tradicionalne metode za rad s podatkovnim okvirima. Bilo koja od ovih opcija predstavlja dobar izbor, a iako paket dplyr nije naju?inkovitiji glede samih performansi (daleko najbolje performanse trenuta?no nudi paket data.table), prednost ovoga paketa je njegova intuitivna, lako ?itljiva sintaksa koja programski rad s podatkovnim okvirima ?ini brzim i jednostavnim te je odli?an izbor za programere koji se upoznaju s R-om ili se jednostavno ?ele usredoto?iti na rad s podacima kroz razumljiv, pregledan i lako odr?iv programski k?d.Strogo gledano, paket dplyr ima skromniju funkcionalnost od one koju nudi paket plyr. No ova zna?ajka nije nedostatak, ve? rezultat ciljanoga dizajna – funkcije paketa dplyr su orijentirane potrebama korisnika, dizajnirane na na?in da pru?aju podr?ku za onaj tip poslova koji se naj?e??e koriste.Konkretne prednosti koje donosi paket dplyr su sljede?e:jednostavna sintaksa (sli?na SQL-u, ali proceduralna) koja koristi pet glavnih “glagola” za manipulaciju podatkovnim okvirima i kao takva definira svojevrsni samostalni jezik unutar jezika Rve?a u?inkovitost od metoda koje nudi osnovni paket; inicijalno je dplyr dizajniran za ve?u u?inkovitost programiranja, ne nu?no za bolje performanse, no u me?uvremenu implementacija odre?enih rutina u C-u omogu?ila je pobolj?anje i performansi izvo?enjaintegracija s relacijskim bazama podataka; funkcije paketa dplyr mogu se koristiti direktno nad tablicama u bazi uz pomo? automatskog prevo?enja funkcija paketa dplyr u SQL naredbeSpomenutih osnovnih “pet glagola” koje nudi paket dplyr su sljede?i:filter – za filtriranje podatkovnog skupa po redcimaselect – za odabir pojedinih stupacaarrange – za promjenu redoslijeda redakamutate – za stvaranje novih stupaca iz postoje?ihsummarise – za agregiranje podatakaPored pet osnovnih glagola vrlo ?esto koristimo i:group_by – za grupiranje podataka unutar podatkovnog skupaporodicu join – funkcija za spajanje podatkovnih okviraPoznavatelji jezika SQL lako ?e uo?iti paralele izme?u tog jezika i navedenih funkcionalnosti paketa dplyr. Najve?a razlika jest u tome ?to SQL radi “deklarativno”, tj. moramo pratiti pravila izgradnje SQL naredbe koja “sve radi odjednom”, dok u R-u uz pomo? funkcija paketa dplyr i ve? ranije upoznatog operatora %>% radnje nad podatkovnim skupovima mo?emo izvoditi proceduralno, s jasnim tijekom obrade podataka slijeva na desno.Budu?i da su funkcije paketa dplyr uglavnom namijenjene upravljanju podatkovnim skupovima, trebat ?e nam ogledni podatkovni skup – za to mo?emo odabrati skup mtcars kojeg mo?emo u?itati i kratko prou?iti na sljede?i na?in.Primjer 28: Ogledni skup mtcars# u?itavamo skup `mtcars` u globalnu okolinudata(mtcars)# struktura podatkovnoga skupastr(mtcars)# prvih nekoliko redakahead(mtcars)## 'data.frame': 32 obs. of 11 variables:## $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...## $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...## $ disp: num 160 160 108 258 360 ...## $ hp : num 110 110 93 110 175 105 245 62 95 123 ...## $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...## $ wt : num 2.62 2.88 2.32 3.21 3.44 ...## $ qsec: num 16.5 17 18.6 19.4 17 ...## $ vs : num 0 0 1 1 0 1 0 1 1 1 ...## $ am : num 1 1 1 0 0 0 0 0 0 0 ...## $ gear: num 4 4 4 3 3 3 3 4 4 4 ...## $ carb: num 4 4 1 1 2 1 4 2 2 4 ...## mpg cyl disp hp drat wt qsec vs am gear carb## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1Za dodatne informacije o ovom podatkovnom skupu mo?emo isprobati i naredbu ?mtcars ?to ?e nam otvoriti stranicu dokumentacije o istom. Ukratko, radi se o podacima o 32 automobila iz 70-tih godina pro?log stolje?a, objavljenih u ameri?kom ?asopisu Motor Trend. Pored imena automobila, skup sadr?ava sljede?e atribute:mpg – potro?nja (u galonima po milji)cyl – broj cilindaradisp – veli?ina motorahp – broj konjskih snagadrat – omjer stra?nje osovinewt – te?ina (u tisu?ama funti)qsec – ubrzanje (do prelaska ?etvrtine milje)V/S – tip motoraam – tip mjenja?agear – broj brzinacarb – broj karburatora.Prije nastavka napravit ?emo malu prilagodbu skupa mtcars. Budu?i da su imena automobila spremljena kao imena redaka, mogu?e je da ista ne?e biti prisutna u “uljep?anom” ispisu podatkovnih okvira koje koristi R Markdown. Zbog toga ?emo ista spremiti u zasebni stupac, a potom ?emo prerasporediti stupce i obrisati imena redaka.Primjer 29: Prilagodba skupa mtcars# imena redaka stavite u zasebni stupac `carName`mtcars$carName <- rownames(mtcars)# preraspodijelite stupce - zadnji stupac na prvo mjestomtcars <- mtcars[, c(12, 1:11)]# obri?ite imena redakarownames(mtcars) <- NULLPogledajmo sada glavne funkcije koje nam nudi paket dplyr.Odabir redakaU poglavlju o podatkovnim okvirima ve? smo nau?ili da se “rezanje” podatkovnih okvira mo?e raditi sli?no rezanju matrica – uz pomo? indeksnih vektora kojima definiramo koje retke/stupce zadr?avamo. Isto tako, nau?ili smo da indeksni vektori mogu biti cjelobrojni (lokacijski), logi?ki i imenski.Kod definicije podskupa redaka daleko naj?e??i tip indeksnoga vektora je logi?ki – uz pomo? varijabli, tj. stupaca definiramo odre?eni kriterij koji “filtrira” retke. Na?alost, osnovna je R-ova sintaksa kori?tenja logi?kih indeksnih redaka za odre?ivanje podskupa redaka pone?to nespretna. Pretpostavimo da imamo podatkovni okvir df s dva stupca a i b. Klasi?na R-ova sintaksa za odabir redaka (uz pomo? uvjetnog indeksiranja) izgleda ovako:df[df$a > 5 & df$b != 3, ]Prvi i o?iti problem jest potreba ponavljanja imena podatkovnog okvira. Drugi problem jest pitanje ?itljivosti – gornju naredbu nije lako vizualno interpretirati, tj. naknadnim pregledom k?da nije lako odmah uo?iti da se radi o reduciranju broja redaka.Paket dplyr nudi alternativnu funkciju filter koja eksplicitnom sintaksom odaje da se radi o filtriranju redaka, a tako?er omogu?uje kori?tenje imena stupaca bez potrebe za referenciranjem imena podatkovnog okvira:filter(df, a > 5 & b != 3)Isto tako, dobro je uo?iti da je prvi argument funkcije s?m podatkovni skup, ?to nam omogu?uje jednostavno ulan?avanje. Na ovom principu dizajnirana je ve?ina funkcija paketa dplyr.Gore navedena funkcija predstavlja naj?e??i na?in odabira podskupa redaka, a poznavatelji SQL-a uo?iti ?e vrlo veliku sli?nost s WHERE segmentom SQL upita. Pored funkcije filter, za odre?ivanje podskupa redaka imamo i sljede?e funkcije, tako?er vrlo intuitivnih imena (radi lak?e interpretacije umjesto potpisa funkcija dajemo primjere parametara):distinct(df) – za uklanjanje duplikataslice(df, 1:10) – za lokacijsko indeksiranjesample_frac(df, 0.2) – nasumi?ni odabir dijela skupa po danom omjerusample_n(df, 50) – nasumi?ni odabir zadanog broja redakatop_n(df, 10, a) – prvih 10 redaka, gledano po poretku stupca aTako?er, za ?eljeni raspored redaka u ispisu mo?emo koristiti:arrange(df, a, desc(b)) – poredaj po stupcu a uzlazno pa po b silaznoIsprobajmo ove funkcije u sljede?oj vje?bi (zadaci se odnose na podatkovni skup mtcars).Vje?ba 53: Funkcije za odabir redaka# u?itajte paket `dplyr` (ako ve? nije u?itan)# ispi?ite podatke o svim autima koji tro?e manje od 15 galona po milji# ispi?ite podatke o autima u prva tri retka (bez operatora indeksiranja!)# ispi?ite podatke o tri nasumi?no odabrana automobila# ispi?ite podatke o pet najte?ih automobila# ispis poredajte od najte?eg prema najlak?emUo?ite kori?tenje operatora cjevovoda u zadnjem rje?enju. Ve?ina funkcija paketa dplyr dizajnirana je za ovakav pristup kori?tenja istih, kojeg ?emo se i mi dr?ati u primjerima i vje?bama koji slijede.Nadalje, uo?imo ne?to druga?iji ispis nakon uporabe funkcije slice. Ova funkcija dizajnirana je na na?in da rezultat pretvara u takozvani tibble, ?to je klasa (iz istoimenog paketa) koja naslje?uje podatkovni okvir i dodaje mu neke funkcionalnosti koje olak?avaju rad s njima. Najve?a prednost ove klase jest “pametni” ispis, pogotovo u situacijama kada nehotice zadamo R-u da ispi?e podatkovni okvir s iznimno velikim brojem redaka. Kod regularnog podatkovnog okvira ovo ?esto rezultira smrzavanjem konzole, dok kod objekata klase tibble postoji rutina koja presretne ovo pona?anje te ispi?e samo manji dio redaka, omogu?uju?i ugodan daljnji rad. Ako ?elimo iskoristiti ove (i druge) pogodnosti ove klase, mo?emo na?e podatkovne okvire pretvoriti u tibble kori?tenjem funkcije as_tibble:Primjer 30: Pretvorba podatkovnog okvira u tibble# pretvaramo `mtcars` u `tibble`mtcars <- as_tibble(mtcars)Odabir stupacaDruga metoda rezanja podatkovnog okvira jest odabir podskupa stupaca. Za razliku od biranja podskupa redaka, gdje se naj?e??e slu?imo logi?kim indeksiranjem tj. filtriranjem po odre?enom kriteriju, stupce naj?e??e odabiremo po njihovomu imenu. Sintaksa odabira podskupa stupaca po imenu uz pomo? osnovnoga na?ina indeksiranja u R-u izgleda, na primjer, ovako (podatkovni okvir df sa stupcima a, b i c):df[, c("a", "b", "c")]Ovdje tako?er uo?avamo odre?enu nespretnost i te?ko?u interpretacije. Nazivi stupaca moraju biti ugra?eni u funkciju stvaranja vektora ?to smanjuje ?itljivost, a naredba nigdje eksplicitno ne iskazuje da se radi o odabiru stupaca ve? da moramo zaklju?iti iz polo?aja indeksnoga vektora. Dodatno, nema jednostavnoga na?ina za odabir raspona stupaca po imenu, postojanju nekoga podniza ili uzorka unutar imena i sl.Funkcija select nam omogu?uje eksplicitni odabir stupaca uz pomo? sintakse:select(df, a, b, c)Dakle, jednostavno navodimo podatkovni okvir i niz stupaca koje ?elimo odabrati. Ovdje je tako?er lako uo?iti sli?nost sa SQL-om, konkretno SELECT segmentom SQL upita.Gornja sintaksa nije sve ?to ova funkcija nudi – select ima ?itav niz pomo?nih funkcija i operatora koji uvelike pro?iruju njezinu funkcionalnost, od kojih navodimo samo neke:select(podaci, a:c) – odaberi stupce od a do cselect(podaci, -a, -b) – odaberi sve stupce osim a i bselect(podaci, starts_with("PO"))) – odaberi stupce koji po?inju sa slovima "PO"select(podaci, contains("stup")) – odaberi stupce koji sadr?e podniz "stup".U sljede?oj vje?bi isprobat ?emo funkciju select, pri ?emu ?e neki zadaci kombinirati odabir stupaca i odabir redaka. Svi zadaci tako?er se odnose na skup mtcars.NAPOMENA: Ako smo obavili pretvorbu podatkovnog okvira u tibble, onda ?e poku?aj ispisa svih redaka uvijek rezultirati s ispisom samo 10 redaka s napomenom koliko redaka je ostalo neispisano. Kao ?to smo ve? spominjali, ovo je ciljano svojstvo ove klase koje ?titi analiti?ara od “prevelikih” ispisa koji potencijalno mogu zamrznuti razvojno su?elje, no ako zaista ?elimo ispisati vi?e redaka od onog ?to vidimo na zaslonu, onda to mo?emo u?initi na sljede?i na?in:# pretpostavka: df je tibble, ?elim ispis 20 redakadf %>% print(n = 20) # ili samo print(20)Vje?ba 54: Odabir stupaca uz funkciju select# za sve automobile iz skupa ispi?ite ime auta, potro?nju, broj cilindara i te?inu # za aute sa 6 cilindara ispi?ite sve stupce od imena do broja konjskih snaga# za nasumi?no odabranih 10% automobila iz skupa ispi?ite # sve atribute osim te?ine i broja brzina# ispis poredajte po imenu automobila# za aute u prvih 5 redaka ispi?ite sve stupce koji sadr?e slovo `a`Agregacija i grupiranjeU literaturi koja se bavi analizom podataka ?esto ?emo nai?i na takozvanu SAC paradigmu (engl. Split-Apply-Combine). Radi se o strategiji koja se svodi na rastavljanje velikoga zadatka na manje dijelove, obavljanje odre?enoga posla na svakom od dijelova te, kona?no, kombiniranje svih rezultata u jedinstvenu cjelinu. Porodica funkcija apply koju smo upoznali primjer je ovakvoga pristupa.U analizi podatkovnih skupova ?esto primjenjujemo ovaj pristup: prvo podijelimo skup po odabranim kategorijama, a onda nad svakim podskupom radimo neku obradu. Poznavatelji SQL-a ?e ovaj princip lako prepoznati kao “grupiranje i agregaciju” koji se provode kroz GROUP BY segment SQL upita uz prate?e elemente u SELECT dijelu. Paket dplyr nudi vrlo sli?nu funkcionalnost (iako na proceduralni na?in) – prvo provedemo “grupiranje”, tj. stvaranje podskupova redaka nekog okvira, a onda provodimo daljnje obrade paralelno nad svakim podskupom, da bismo na kraju sve rezultate sakupili u jedinstveni podatkovni okvir.Za grupiranje dplyr nudi funkciju group_by kojom tablicu (podatkovni okvir) pretvaramo u “grupiranu tablicu” (grouped_tbl):# grupiranje tablicedf <- group_by(df, a, b, c)Isprobajmo ovu funkciju na na?em okviru mtcars.Vje?ba 55: Grupirana tablica# stvorite novi podatkovni okvir imena `mtcarsCyl`# koji ?e sadr?avati retke iz tablice `mtcars`# grupirane po cilindruGrupiranjem nismo izgubili nikakvu informaciju – grupirani podatkovni okvir i dalje izgleda identi?no kao i originalni “negrupirani” okvir. Grupiranje je samo dodatna informacija koja se upisuje u okvir i koja nazna?ava da se neke daljnje operacije ne izvode nad cijelim okvirom, ve? nad pojedinim grupama.Naj?e??e operacije koje radimo nad grupiranim tablicama su takozvane “agregacijske” operacije – operacije koje niz vrijednosti svode na jednu vrijednost uz pomo? odabrane agregacijske funkcije, kao na primjer minimum, maksimum, suma, prosjek i sl.Za agregaciju paket dplyr koristi funkciju summarise u sprezi s funkcijama (navodimo samo neke):min, max – minimum i maksimummean, median, sd – prosjek, medijan, standardna devijacijafirst, last, nth – prvi element, zadnji, n-tin, n_distinct – broj redaka, broj jedinstvenih redakaSintaksa uporabe agregacijskih funkcija je na primjersummarise(df, mean(a), sd(a))U ovom slu?aju za podatkovni okvir df tra?imo aritmeti?ku sredinu i standardnu devijaciju elemenata stupca a. Ako se ne radi o grupiranoj tablici, dobit ?emo sredinu i devijaciju cijeloga stupca; ako smo tablicu grupirali, onda ?e se ove funkcije izra?unati zasebno za svaki grupirani dio tablice.Isprobajmo ovo na na?im okvirima mtcars i mtcarsCyl.Vje?ba 56: Funkcija summarise# izra?unajte minimalan, maksimalan i prosje?an broj# konjskih snaga za okvir `mtcars`# izra?unajte minimalan, maksimalan i prosje?an broj# konjskih snaga za okvir `mtcarsCyl`Uo?imo da kod grupirane tablice funkcija summarise automatski u ispis uklju?uje i stupce po kojima smo grupirali.U praksi naj?e??e grupiranu tablicu ne pohranjujemo u novu varijablu, ve? unutar jedne naredbe provodimo cijeli proces odabira redaka i stupaca, grupiranja i provo?enja agregacije. Tako jedan slo?eniji izraz mo?e izgledati ovako:filter(df, a > 5) %>% select(a, b, c) %>% group_by(a,b) %>% summarise(prosjekC = mean(c)) %>% arrange(desc(b))NAPOMENA: Uo?ite dodavanje imena prosjekC agregiranom stupcu. Ovo je preporu?eni postupak kod provedbe agregacije, jer ovo ime novoga stupca mo?emo koristiti u daljnjim funkcijama.Spomenimo za kraj funkciju ungroup kojom mo?emo po ?elji ukloniti postoje?a grupiranja – ovo radimo kad god ?elimo da se naknadne operacije vi?e ne rade “po grupama”, ve? na razini cijeloga podatkovnog okvira. Naime, grupiranje ne?e samo utjecati na agregacijske funkcije, ve? ?e se odraziti i na funkcije kao ?to su mutate (npr. rangiranje unutar grupa) ili arrange, tj. promjena redoslijeda (ure?ivanje rasporeda redaka unutar grupa). Kombinacijama ungroup i group_by lako uvodimo i ukidamo grupiranja prema ?elji.Kona?no, ponovimo jo? jednom lako uo?ljivu sli?nost gornjeg izraza sa SQL upitima u relacijskim bazama, uz bitnu razliku da ovdje operacije provodimo proceduralno ?to uvelike pove?ava ?itljivost te da vrlo lako u bilo kojem trenutku mo?emo pohraniti i provjeriti me?urezultat.Poku?ajmo sada napisati slo?eni upit koji koristi ve?i dio nau?enih elemenata:Vje?ba 57: Funkcija summarise (2)# iz skupa automobila `mtcars` odaberite samo aute s ru?nim mjenja?em# zadr?ite samo stupce s imenom, potro?njom, brojem cilindara i te?inom# grupirajte n-torke po broju cilindara i ispi?ite broj n-torki u svakoj grupi# kona?ni rezultat poredajte po broju n-torki svake podgrupe# NAPOMENA: agregacijska funkcija n() ne treba nikakve argumente!Uo?ite da nam je u zadnjem rje?enju select segment zapravo potpuno nepotreban, jer kombinacija funkcija group_by i summarise ionako implicitno uklanja sve stupce koji nisu ni dio grupiranja ni agregacijske funkcije.Zaklju?akZa kraj ponovimo najva?nije stvari nau?ene na ovom te?aju:R je domenski orijentirani jezik ?ije uspje?no svladavanje zahtjeva kako u?enje njegovih programskih elemenata tako i razmi?ljanje o njihovoj primjeni unutar konteksta analize podatkovnih skupovaR se zasniva na principu vektorizacije – vektor je osnovna podatkovna struktura, a operacije se naj?e??e izvode na na?in da se provode nad svim elementima podatkovne strukture odjednomfunkcijska programska paradigma prikladna je prirodi jezika R; u R-u se sve vrti oko funkcija tako da je normalno referencirati funkcije kroz varijable, slati ih kao parametre u druge funkcije ili primati ih kao rezultatR preferira deklarativnu sintaksu gdje programer kori?tenjem odgovaraju?ih funkcija na visokoj razini definira posao koji ?eli obaviti, bez niskorazinskih detalja koji opisuju kako prolaziti nekom podatkovnom strukturom; zbog toga u jeziku R u pravilu treba izbjegavati programske petlje (?to ne zna?i da ih treba potpuno izbaciti, ve? samo uvijek razmi?ljati o mogu?oj alternativi)funkcije porodice apply omogu?uju nam da u?inkovito zaobi?emo kori?tenje petlji; paketi kao ?to su purrr i plyr dodatno olak?avaju rad pru?aju?i kolekcije funkcija s konzistentnijim, preglednijim su?eljimaoperator cjevovoda %>% uvelike pove?ava preglednost programskoga k?da i olak?ava programiranjefunkcije paketa dplyr stvaraju svojevrsni “jezik unutar jezika” i omogu?uju brz i u?inkovit rad nad podatkovnim skupovima?to dalje? Ako ?emo jezik R koristiti za njegovu primarnu svrhu – analizu podatkovnih skupova - onda se isplati prou?iti pakete u kolekciji tidyverse. Ova kolekcija predstavlja preporu?eni skup podataka za “podatkovnu znanost” (engl. data science); ona na odre?eni na?in nadogra?uje jezik R i nudi “platformu unutar platforme”, jer su paketi dizajnirani kori?tenjem iste filozofije dizajna i zajedni?kih, dijeljenih su?elja. Uz pakete dplyr, magrittr. tibble i purrr koje smo spominjali u ovoj lekciji, dio ovoga paketa jesu i paketi:ggplot2 – iznimno popularni paket za crtanje vizualizacijareadr – paket za lako u?itavanje podataka iz razli?itih izvoratidyr – paket za brzo preoblikovanje podatkovnih okvira, posebno pogodan za popravljanje “neurednih”, lo?e strukturiranih podatkovnih skupovastringr – paket za upravljanje znakovnim nizovimalubridate – paket za upravljanje datumima i vremenskim oznakamaDBI – paket za integraciju s relacijskim bazama podatakaitd.U?enje svakog od paketa iz kolekcije tidyverse bitno pro?iruje spektar mogu?nosti jezika R, pogotovo u segmentu pripreme podataka, ?to je ?esto najzahtjevniji i najnaporniji dio podatkovne znanosti. Odli?na knjiga za ovaj segment je R for Data Science, autora Hadley-a Wickham-a (koji je autor velikoga dijela paketa kolekcije tidyverse), besplatno dostupna u elektroni?kom obliku na adresi te?imo produbljivanju znanja o samom programskom jeziku R, onda je preporuka posvetiti vi?e vremena u?enju objektnih modela jezika R, detaljnijim karakteristikama funkcijske programske paradigme i njezine primjene u jeziku R, metodama optimizacije, integracije s rutinama u jeziku C++ i sl. Preporu?ena literatura je knjiga Advanced R, tako?er od Hadley-a Wickhama, isto tako besplatno dostupna u elektroni?kom obliku na adresi , ako te?imo zvanju podatkovnoga znanstvenika i uz znanje R-a ?elimo nau?iti ?to vi?e o metodologiji statisti?ke i dubinske analize podataka te primjenama jednostavnih i slo?enijih metoda strojnog u?enja uz konkretne scenarije kori?tenja u jeziku R, preporu?ena literatura mo?e biti:OpenIntro statistics, autori David M. Diez, Christopher D. Barr i Mine ?etinkaya-Rundel uvodna knjiga o statistici, dostupna na , sadr?i i vlastiti CRAN paket openintro s primjerimaIntroduction to Statistical Learning, autori Gareth James, Daniela Witten, Trevor Hastie i Robert Tibshirani, knjiga koja se bavi primjenom metoda strojnog u?enja s konkretnim primjerima, dostupna na , tako?er ima svoj CRAN paket ISLRNe treba zaboraviti ni na ve? spomenute R podsjetnike koje nudi RStudio, dostupne na poveznici . Ve? samo prou?avanje podsjetnika mo?e pru?iti inspiraciju za daljnje u?enje i odabir paketa, ovisno o ?eljenoj primjeni.U svakom slu?aju jezik R je puno vi?e od “neobi?noga” programskog jezika, a dostupni paketi pro?irenja (uz razvojno su?elje RStudio) doslovno redefiniraju R kao platformu za podatkovnu znanost. Dobar R programer ulo?it ?e trud kako bi razumio sve elemente jezika, kako one osnovne, tako i one koji dodatno oplemenjuju jezik i nude nove na?ine pristupa rje?avanju problema. Usvajanje znanja o tome za?to ne?to radi na odre?eni na?in, te jasno razumijevanje prednosti i mana odre?enih funkcionalnosti i pristupa dugoro?no ?e dovesti do ugodnog kori?tenja ovog programskog jezika za niz potencijalnih scenarija – od jednostavne obrade manjeg podatkovnog skupa uz prigodne vizualizacije, do u?inkovitog upravljanja velikim koli?inama neurednih podataka uz razvoj i usporedbu kompleksnih deskriptivnih i prediktivnih modela.Dodatni zadaci za vje?buUzmimo matricu m stvorenu sljede?om naredbom:m <- rbind(1:5, seq(2, 10, 2), rep(3, 5), 3:7, seq(100, 500, 100))Uz pomo? funkcije apply i nove anonimne funkcije stvorite vektor koji ?e sadr?avati prvi parni element svakoga retka, ili nulu ako pripadaju?i redak nema parnih elemenata.Sljede?e naredbe stvorit ?e listu od 100 elemenata gdje ?e svaki element biti numeri?ki vektor nasumi?ne duljine od 1 do 10.set.seed(1234)lista <- replicate(100, sample(1:10, sample(1:10, 1)))Uz pomo? funkcija lapply ili sapply (i dodatnih naredbi ako je potrebno) stvorite:numeri?ki vektor v s duljinama elemenata listelistu l s normaliziranim numeri?kim vektorima originalne listenumeri?ki vektor ind4 s indeksima svih elemenata liste koji sadr?e broj 4podatkovni okvir df5 koji kao stupce sadr?i sve elemente liste duljine 5Inicijalizirajte generator slu?ajnih brojeva uz pomo? naredbe set.seed(1234). Potom uz pomo? jedne naredbe i %>% operatora izvedite sljede?e:stvorite 100000 nasumi?nih brojeva izvu?enih iz normalne razdiobe s aritmeti?kom sredinom 10000 i standardnom devijacijom 1000zaokru?ite brojeve na prvi ve?i cijeli brojizbacite duplikate iz skupaporedajte skup po veli?inislu?ajnim odabirom iz skupa izvucite 100 elemenataorganizirajte tih 100 elemenata u matricu 10 × 10, slo?enu po redcimaizra?unajte sume redaka matriceispi?ite prosjek suma redaka na zaslon.U sljede?im zadacima za vje?bu poslu?iti ?emo se pro?irenim podatkovnim skupom mammals sleep dostupnim u vizualizacijskom paketu ggplot2. U?itajte paket ggplot2 te potom prenesite podatkovni okvir msleep u globalnu okolinu uz pomo? funkcije data.Prije rje?avanja u?itajte podatkovni skup i upoznajte se s njim uz pomo? uobi?ajenih funkcija.Za 10 biljojeda koji najdulje spavaju ispi?ite ime, koliko dnevno spavaju i tjelesnu te?inu u kilogramima. Ispis poredajte po duljini spavanja silazno.Ispi?ite prosje?no, najdulje i najkra?e vrijeme spavanja ?ivotinja ovisno o njihovomu tipu prehrane. ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download

To fulfill the demand for quickly locating and searching documents.

It is intelligent file search solution for home and business.

Literature Lottery

Related searches