9 Operator cjevovoda i uredni podaci


9.1 Operator cjevovoda

Pogledajmo 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:

## [1] 51.123

Ovakav kod ima dosta nepotrebnog ponavljanja - u svakom retku koristimo varijablu rez koja čuva međurezultate i operator pridruživanja pomoću kojeg pridružujemo nove rezultate varijabli rez. Alternativno, mogli smo sve obaviti u jednom retku.


Zadatak 9.1 - učahurene funkcije


Ovdje vidimo jedan tipičan primjer “kodnog 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 ukoliko želimo sve obaviti bez eksplicitnog čuvanja međurezultata kao rezultat ćemo dobiti programski kod koji je podložan greškama kod pisanja te je vrlo teško čitljiv.

Prirodan način interpretacije ovakvog 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 kada bi mogli ovakvu intuitivnu interpretaciju predočiti programskim kodom, pojednostavili bismo si ne samo pisanje koda, već bi takav kod postao daleko čitljiviji i lakši za održavanje i eventualnu naknadnu prilagodbu. Upravo ovo bila je motivacija za razvoj tzv. “pipeline” operatora kojeg nudi paket magrittr (Bache and Wickham 2014).

Paket čudnog imena zapravo je inspiriran imenom apstraktnog 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”. Na isti način paket magrittr donosi “pipeline” ili “pipe” operator %>% koji “nije lula”. Štogod mislili o navedenom slikarskom djelu ili igri riječi koja je inspirirala ovaj paket, ono što je neporecivo jest činjenica da “pipeline” operator programski kod čini daleko čitljivijim te da 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 koliko poziva “ulančavamo”.

Ako 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:

Ukoliko ne želimo koristiti točku, moramo samo voditi računa da su pozivi funkcija u lancu zapravo formalno nepravilni, jer imaju “nevidljivi” prvi argument. Usprkos tome, 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 sa postojanjem “nevidljivog” argumenta.

Probajmo sada preoblikovati naš prvi primjer uz pomoć %>% operatora.


Zadatak 9.2 - operator %>%


Uočite kako čitanjem gornjeg programskog koda vrlo lagano interpretiramo smisao te linije programskog koda, pogotovo u usporedbi sa istom naredbom napisanom u obliku “sendviča”.

Krajnji rezultat našeg “lanca” funkcija možemo pohraniti uobičajenim načinom:

ali je možda vizualno konzistentnije koristiti “obrnuti” operator pridruživanja: ->.

Uočite da u situacijama kada je rezultat prethodne funkcije jedini parametar sljedeće možemo izbaciti zagrade u potpunosti (dakle u gornjim primjerima sum, sum() ili sum(.) bi svi radili jednako).

Pokušajmo sada kombinirati %>% operator i lapply na primjeru već viđenom u poglavlju o funkcijama iz porodice apply.


Zadatak 9.3 - funkcija lapply i operator %>%


Operator 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 - operatori kao funkcije

## [1] 5
## [1] 5
## [1] 1 2 3 4 5
## [1] 1 2 3 4 5
## [1] 1
## [1] 1

Pokušajmo ovaj princip iskoristiti u sljedećoj vježbi.


Zadatak 9.4 - složenija uporaba operatora cjevovoda

##      [,1] [,2] [,3]
## [1,]    1    2    1
## [2,]    1    3    1
## [3,]    1    1    2

%>% operator je posebno pogodan za upravljanje podatkovnim skupovima, pogotovo 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šeg 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 sa lekcijama koje slijede.


9.2 Uredni podaci

U literaturi možemo naći činjenicu kako je u procesu analize priprema podataka često vremenski najzahtjevniji segment procesa - u knjizi “Exploratory Data Mining and Data Cleaning” spominje se da se na pripremu često troši od 50% do 80% ukupnog vremena. Isto tako, kako navodi Hadley Wickham u svojem članku “Tidy Data”, priprema podataka često nije samo prvi korak već je proces koji se ponavlja kako se otkrivaju nova saznanja ili prikupljaju novi podaci.

Hadley Wickham je uveo termin “urednih podataka” koji se odnosi na organizaciju podatkovnog skupa na način da u što većoj mjeri olakša njihovu daljnju obradu i analizu. Činjenica je da ulazni podaci često nisu originalno namijenjeni za potrebe analize te kao takvi nisu organizirani na način koji bi omogućio njihovo lako korištenje u analitičkom procesu. “Uredni podaci” zapravo predstavljaju princip kako - prema potrebi - “presložiti” podatke tako da njihova struktura odgovara standardnom, očekivanom metapredlošku.

Principi urednih podataka imaju sličnosti sa relacijskim modelom podataka no definirani su na način koji više odgovara statističarima i programerima. Ugrubo te principe možemo popisati na sljedeći način:

  • podaci su organizirani u tablicu
  • svaki redak predstavlja obzervaciju
  • svaki stupac predstavlja svojstvo ili varijablu te obzervacije

Budući da ovo možda zvuči previše trivijalno, pogledajmo koja svojstva Hadley navodi kao tipična za “neuredne” podatke:

  • imena stupaca nisu nazivi varijabli, već njihove vrijednosti
  • više različitih varijabli spremljeno je u isti stupac
  • varijable su spremljene u retke
  • više tipova različitih obzervacija spremljeno je u istu tablicu
  • jedan tip obzervacije spremljen je u više tablica

U nastavku ćemo dati nekoliko primjera tablica koje ne odgovaraju u potpunosti definiciji urednih podataka te prikazati kako ih na jednostavan način preoblikovati, tj. “urediti”. Za taj posao koristiti ćemo metode paketa tidyr.


9.2.1 Funkcije gather i spread

U radnoj mapi trebala bi se nalaziti datoteka studenti.csv. Učitajmo ju u radnu okolinu. Budući da je datoteka pohranjena uz pomoć UTF-8 kodiranja (budući da sadrži hrvatska slova), naredbi read.csv možete dodati i parametar fileEncoding = "UTF-8" kako bi dobili korektni ispis posebnih znakova.


Zadatak 9.5 - podatkovni skup studenti

## 'data.frame':    27 obs. of  10 variables:
##  $ JMBAG                : int  1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 ...
##  $ Prezime              : chr  "Anic" "Babic" "Crnoja" "Crnjac" ...
##  $ Ime                  : chr  "Iva" "Josip" "Petra" "Lucija" ...
##  $ Matematika.1         : chr  "2" "5" "4" "2" ...
##  $ Fizika.1             : chr  "2" "3" "3" "5" ...
##  $ Programiranje        : chr  "NULL" "4" "4" "2" ...
##  $ Osnove.elektrotehnike: chr  "NULL" "3" "2" "2" ...
##  $ Digitalna.logika     : chr  "4" "NULL" "3" "3" ...
##  $ Matematika.2         : chr  "2" "5" "4" "3" ...
##  $ Algoritmi.1          : chr  "2" "5" "3" "4" ...
##   JMBAG Prezime    Ime Matematika.1 Fizika.1 Programiranje
## 1  1341    Anic    Iva            2        2          NULL
## 2  1342   Babic  Josip            5        3             4
## 3  1343  Crnoja  Petra            4        3             4
## 4  1344  Crnjac Lucija            2        5             2
## 5  1345   Dizla  Stipe         NULL        4             3
## 6  1346   Ermic   Igor         NULL        3          NULL
##   Osnove.elektrotehnike Digitalna.logika Matematika.2 Algoritmi.1
## 1                  NULL                4            2           2
## 2                     3             NULL            5           5
## 3                     2                3            4           3
## 4                     2                3            3           4
## 5                     5                2            2           2
## 6                     5                5            5           5

Uočite da ovaj podatkovni skup ima dosta nedostajućih vrijednosti koje su zapisane kao NULL. Budući da R ne prepoznaje ovo kao nedostajuću vrijednost on je podatke učitao kao znakovne nizove (ili kao faktore, ako smo zaboravili na parametar stringsAsFactors). Budući da su stupci koji se odnose na ocjene očito numerički, možemo ih lako pretvoriti u takve uz pomoć naredbe as.numeric() (ili as.numeric(as.character()) ako su faktori!). No, postoji jednostavniji način - ako znamo na koji način je nedostajuća vrijednost reprezentirana u podatkovnom skupu, možemo to direktno ugraditi u naredbu read.csv uz pomoć parametra na.strings.


Zadatak 9.6 - prilagodba parametara učitavanja podatkovnog skupa

## 'data.frame':    27 obs. of  10 variables:
##  $ JMBAG                : int  1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 ...
##  $ Prezime              : chr  "Anic" "Babic" "Crnoja" "Crnjac" ...
##  $ Ime                  : chr  "Iva" "Josip" "Petra" "Lucija" ...
##  $ Matematika.1         : int  2 5 4 2 NA NA NA 3 3 4 ...
##  $ Fizika.1             : int  2 3 3 5 4 3 3 4 2 2 ...
##  $ Programiranje        : int  NA 4 4 2 3 NA 3 3 3 4 ...
##  $ Osnove.elektrotehnike: int  NA 3 2 2 5 5 3 4 2 2 ...
##  $ Digitalna.logika     : int  4 NA 3 3 2 5 2 4 3 5 ...
##  $ Matematika.2         : int  2 5 4 3 2 5 2 5 NA 4 ...
##  $ Algoritmi.1          : int  2 5 3 4 2 5 5 4 3 2 ...
##   JMBAG Prezime    Ime Matematika.1 Fizika.1 Programiranje
## 1  1341    Anic    Iva            2        2            NA
## 2  1342   Babic  Josip            5        3             4
## 3  1343  Crnoja  Petra            4        3             4
## 4  1344  Crnjac Lucija            2        5             2
## 5  1345   Dizla  Stipe           NA        4             3
## 6  1346   Ermic   Igor           NA        3            NA
##   Osnove.elektrotehnike Digitalna.logika Matematika.2 Algoritmi.1
## 1                    NA                4            2           2
## 2                     3               NA            5           5
## 3                     2                3            4           3
## 4                     2                3            3           4
## 5                     5                2            2           2
## 6                     5                5            5           5

Vidimo da podaci sada imaju odgovarajući tip - no očito ne odgovaraju u potpunosti definiciji “urednih podataka”. Imena stupaca su zapravo kategorije varijable Predmet a “obzervacija” u ovoj tablici reprezentirana je studentom. Dodavanje nove ocjene iz nekog predmeta moguće je jedino dodavanjem novog stupca, pri čemu bismo morali voditi računa da se na taj način dodaju ocjene za sve student, tj. da bi tablica morala imati puno NA vrijednosti za sve kombinacije studenata i predmeta koje su neprimjenjive jer ocjene trenutno nema (i možda je neće ni biti ukoliko student niti ne sluša taj predmet).

Budući da su podaci u tablici zapravo skup ocjena, bilo bi pogodno preoblikovati tablicu tako da svaki redak upravo bude “ocjena koju je dobio neki student na nekom predmetu”. Razmislite koje korake bi trebalo poduzeti da stvorimo takvu tablicu. Trebamo:

  • stvoriti kategorijsku varijablu Predmet koja bi kao razine imala nazive predmeta koji su trenutno stupci
  • stvoriti sve pripadne kombinacije student-predmet
  • popuniti kombinacije pripadajućom vrijednosti ocjene

Ovaj postupak nije nemoguć ali zahtjeva dosta truda oko preoblikovanja podatkovnog okvira. Kako bi se ovaj postupak pojednostavio, možemo koristiti funkciju gather iz paketa tidyr koja obavlja upravo gore opisani postupak: ona “prikuplja” stupce u jedinstvenu varijablu i onda popunjava vrijednosti te varijable uz pomoć postojećih kombinacija naziv stupca / redak. Potpis funkcije izgleda ovako:

Detaljni opis funkcije možete dobiti pozivom naredbe ?gather, a ovdje ćemo samo ukratko objasniti parametre:

  • data očito predstavlja naš podatkovni okvir
  • key predstavlja naziv novog stupca - kategorijske varijable kojeg stvaramo a (u našem slučaju Predmet); kako bi se olakšao posao programeru, ova funkcija ne zahtijeva da naziv stupca stavljamo u navodnike
  • value predstavlja naziv novog stupca - varijable sa vrijednostima (u našem slučaju Ocjena)
  • ... predstavlja skup stupaca koje prikupljamo; možemo navesti samo nazive stupaca odvojene zarezima (navodnici također nisu potrebni) ili se koristiti skraćenom sintaksom prvi_stupac:zadnji_stupac (možemo i naznačiti samo “izbačene” stupce sa predznakom -)
  • na.rm opisuje da li želimo izostaviti stupce sa NA
  • convert će obaviti konverziju podataka ukoliko to smatramo potrebnim
  • factor_key nas pita želimo li faktorizirati novu varijablu koju stvaramo

Obavimo ovu funkciju nad našim podatkovnim okvirom.


Zadatak 9.7 - funkcija gather

## 'data.frame':    168 obs. of  5 variables:
##  $ JMBAG  : int  1341 1342 1343 1344 1348 1349 1350 1351 1352 1353 ...
##  $ Prezime: chr  "Anic" "Babic" "Crnoja" "Crnjac" ...
##  $ Ime    : chr  "Iva" "Josip" "Petra" "Lucija" ...
##  $ Predmet: Factor w/ 7 levels "Matematika.1",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ Ocjena : int  2 5 4 2 3 3 4 2 4 5 ...
##   JMBAG Prezime    Ime      Predmet Ocjena
## 1  1341    Anic    Iva Matematika.1      2
## 2  1342   Babic  Josip Matematika.1      5
## 3  1343  Crnoja  Petra Matematika.1      4
## 4  1344  Crnjac Lucija Matematika.1      2
## 8  1348 Grubiša   Ivan Matematika.1      3
## 9  1349   Gobac  Davor Matematika.1      3

Funkcija koja radi inverzan posao od gather jest funkcija spread. Ona će podatke iz kombinacije kategorijskog stupca i vrijednosti “raširiti” tako da kategorije postaju nazivi stupaca a vrijednosti se “raspršuju” po odgovarajućim stupcima.

Potpis funkcije izgleda ovako:

Dokumentaciju ove funkcije lako dohvaćamo naredbom ?spread a neke elemente već možemo lako prepoznati korištenjem znanja kako radi funkcija gather. Parametri koje možda treba dodatno pojasniti su:

  • fill koji opisuje koju vrijednost staviti kod “nepostojećih” kombinacija nakon “širenja”
  • drop koji opisuje da li treba raditi stupce za nepostojeće kategorije ako je stupac kojeg širimo faktoriziran
  • sep koji nam omogućuje da naziv stupca ne bude samo vrijednost kategorije već kombinacija naziva postojećeg kategorijskog stupca i vrijednosti (uz definirani separator)

Pokušajmo uz pomoć ove naredbe “rekonstruirati” originalni podatkovni okvir studenti.


Zadatak 9.8 - funkcija spread

##   JMBAG Prezime    Ime Matematika.1 Fizika.1 Programiranje
## 1  1341    Anic    Iva            2        2            NA
## 2  1342   Babic  Josip            5        3             4
## 3  1343  Crnoja  Petra            4        3             4
## 4  1344  Crnjac Lucija            2        5             2
## 5  1345   Dizla  Stipe           NA        4             3
## 6  1346   Ermic   Igor           NA        3            NA
##   Osnove.elektrotehnike Digitalna.logika Matematika.2 Algoritmi.1
## 1                    NA                4            2           2
## 2                     3               NA            5           5
## 3                     2                3            4           3
## 4                     2                3            3           4
## 5                     5                2            2           2
## 6                     5                5            5           5
##   JMBAG Prezime    Ime Matematika.1 Fizika.1 Programiranje
## 1  1341    Anic    Iva            2        2            NA
## 2  1342   Babic  Josip            5        3             4
## 3  1343  Crnoja  Petra            4        3             4
## 4  1344  Crnjac Lucija            2        5             2
## 5  1345   Dizla  Stipe           NA        4             3
## 6  1346   Ermic   Igor           NA        3            NA
##   Osnove.elektrotehnike Digitalna.logika Matematika.2 Algoritmi.1
## 1                    NA                4            2           2
## 2                     3               NA            5           5
## 3                     2                3            4           3
## 4                     2                3            3           4
## 5                     5                2            2           2
## 6                     5                5            5           5
## 'data.frame':    27 obs. of  10 variables:
##  $ JMBAG                : int  1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 ...
##  $ Prezime              : chr  "Anic" "Babic" "Crnoja" "Crnjac" ...
##  $ Ime                  : chr  "Iva" "Josip" "Petra" "Lucija" ...
##  $ Matematika.1         : int  2 5 4 2 NA NA NA 3 3 4 ...
##  $ Fizika.1             : int  2 3 3 5 4 3 3 4 2 2 ...
##  $ Programiranje        : int  NA 4 4 2 3 NA 3 3 3 4 ...
##  $ Osnove.elektrotehnike: int  NA 3 2 2 5 5 3 4 2 2 ...
##  $ Digitalna.logika     : int  4 NA 3 3 2 5 2 4 3 5 ...
##  $ Matematika.2         : int  2 5 4 3 2 5 2 5 NA 4 ...
##  $ Algoritmi.1          : int  2 5 3 4 2 5 5 4 3 2 ...
## 'data.frame':    27 obs. of  10 variables:
##  $ JMBAG                : int  1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 ...
##  $ Prezime              : chr  "Anic" "Babic" "Crnoja" "Crnjac" ...
##  $ Ime                  : chr  "Iva" "Josip" "Petra" "Lucija" ...
##  $ Matematika.1         : int  2 5 4 2 NA NA NA 3 3 4 ...
##  $ Fizika.1             : int  2 3 3 5 4 3 3 4 2 2 ...
##  $ Programiranje        : int  NA 4 4 2 3 NA 3 3 3 4 ...
##  $ Osnove.elektrotehnike: int  NA 3 2 2 5 5 3 4 2 2 ...
##  $ Digitalna.logika     : int  4 NA 3 3 2 5 2 4 3 5 ...
##  $ Matematika.2         : int  2 5 4 3 2 5 2 5 NA 4 ...
##  $ Algoritmi.1          : int  2 5 3 4 2 5 5 4 3 2 ...

U prethodnom primjeru demonstrirali smo inverznu funkcionalnost funkcija gather i spread ali narednom spread nismo postigli uredne podatke, samo smo se vratili na originalni okvir. Pogledajmo sada primjer gdje upravo naredbom spread “sređujemo” podatke.

Učitajmo podatke iz datoteke auti.csv koja pohranjuje tehničke karakteristike određenih automobila.


Zadatak 9.9 - podatkovni skup auti

## 'data.frame':    18 obs. of  3 variables:
##  $ Model.auta             : chr  "Opel Astra" "Opel Astra" "Opel Astra" "Opel Astra" ...
##  $ Tehnicka.karakteristika: chr  "Cilindara" "KS" "Dužina m" "Masa kg" ...
##  $ Vrijednost             : num  4 125 4.27 1285 4 ...
##   Model.auta Tehnicka.karakteristika Vrijednost
## 1 Opel Astra               Cilindara      4.000
## 2 Opel Astra                      KS    125.000
## 3 Opel Astra                Dužina m      4.267
## 4 Opel Astra                 Masa kg   1285.000
## 5    Audi A4               Cilindara      4.000
## 6    Audi A4                      KS    136.000

U ovoj tablici očito je narušen princip urednih podataka da u jedan stupac treba biti pohranjen samo jedan tip varijable - tehničke karakteristike automobila smještene su u jedinstveni stupac naziva Tehnicka.karakteristika a u stupcu Vrijednost nalaze se vrijednosti vrlo različitih tipova (masa u kg, dužina u m i sl.).

Pokušajte urediti ovaj okvir uz pomoć naredbe spread.


Zadatak 9.10 - funkcija spread (2)

## 'data.frame':    5 obs. of  6 variables:
##  $ Model.auta: chr  "Audi A4" "Citroen C6" "Fiat 500L" "Opel Astra" ...
##  $ Cilindara : num  4 6 2 4 4
##  $ Dužina m  : num  4.7 NA NA 4.27 4.56
##  $ KS        : num  136 215 103 125 110
##  $ Masa kg   : num  1470 1816 1260 1285 NA
##  $ Ventila   : num  NA NA NA NA 16
##             Model.auta Cilindara Dužina m  KS Masa kg Ventila
## 1              Audi A4         4    4.703 136    1470      NA
## 2           Citroen C6         6       NA 215    1816      NA
## 3            Fiat 500L         2       NA 103    1260      NA
## 4           Opel Astra         4    4.267 125    1285      NA
## 5 Renault Grand Scenic         4    4.560 110      NA      16

Naredbe gather i spread ne koriste se samo za “neuredne” podatke. One mogu biti vrlo korisne kod pretvorbe tzv. “širokih” podatka (wide data) u “dugačke” (long data). Prikažimo ovo na primjeru tzv. podataka o potrošačkim košaricama.

Potrošačka košarica predstavlja zapis artikala koje je kupac kupio tijekom jednog dolaska u trgovinu (bilo da se radi o virtualnoj trgovini ili stvarnom prodajnom mjestu). Ako podatke o potrošačkoj košarici zapisujemo u “širokom” formatu, onda podatke organiziramo tako da stupci predstavljaju pojedine artikle a retci jednu kupnju (ili račun). Vrijednost 1 znači da se artikl našao u košarici, 0 da nije bio prisutan. Ovakav prikaz pogodan je za različite tipove analiza, ali nije ekonomičan - podaci će često imati jako puno “nula”. S druge strane, “dugački” format jednostavno u svaki redak stavlja kombinaciju identifikatora košarice (ili broja računa) i naziv (ili šifru) kupljenog artikla. Ovakav zapis imati će znatno više redaka, ali je znatno pogodniji u slučajevima kada je broj artikala u asortimanu daleko veći od broja artikala u prosječnoj košarici.


Zadatak 9.11 - podatkovni skup potrosackaKosarica

## 'data.frame':    104 obs. of  21 variables:
##  $ racunID        : int  15671 15672 15673 15674 15675 15676 15677 15678 15679 15680 ...
##  $ Coca.cola.2l   : int  0 1 1 0 1 0 0 0 0 0 ...
##  $ Cipi.Cips      : int  0 0 1 0 0 0 0 1 0 0 ...
##  $ Nutella.400.g  : int  0 1 0 0 1 0 0 0 0 0 ...
##  $ Karlovacko.pivo: int  0 1 0 0 0 0 0 0 0 1 ...
##  $ Ožujsko.pivo   : int  1 0 0 1 0 0 0 0 0 1 ...
##  $ Omekšivac.1.5l : int  0 0 0 0 0 0 0 1 0 1 ...
##  $ Voda.2l        : int  0 0 1 0 0 0 0 0 1 1 ...
##  $ Narance        : int  0 0 0 1 1 0 0 0 1 1 ...
##  $ Jabuke         : int  1 0 0 1 0 0 0 0 0 0 ...
##  $ Mandarine      : int  0 0 1 0 0 0 0 1 1 1 ...
##  $ Salvete        : int  0 0 0 0 1 1 0 0 0 0 ...
##  $ Ajvar          : int  0 0 1 1 0 0 0 0 0 1 ...
##  $ Ketchup        : int  1 0 0 1 0 0 0 0 0 1 ...
##  $ Senf           : int  1 0 0 0 0 0 0 1 0 0 ...
##  $ Mlijeko.0.5l   : int  0 1 0 1 1 0 0 0 0 0 ...
##  $ Kiselo.vrhnje  : int  0 1 0 0 0 0 1 0 0 1 ...
##  $ Feta.sir       : int  0 0 0 1 0 0 0 0 0 0 ...
##  $ Sardine        : int  0 0 0 0 0 0 0 0 0 1 ...
##  $ Tuna.pašteta   : int  1 1 1 0 0 1 0 0 0 0 ...
##  $ Nescaffe       : int  0 0 1 0 0 0 0 0 1 0 ...
##   racunID Coca.cola.2l Cipi.Cips Nutella.400.g Karlovacko.pivo
## 1   15671            0         0             0               0
## 2   15672            1         0             1               1
## 3   15673            1         1             0               0
## 4   15674            0         0             0               0
## 5   15675            1         0             1               0
## 6   15676            0         0             0               0
##   Ožujsko.pivo Omekšivac.1.5l Voda.2l Narance Jabuke Mandarine Salvete
## 1            1              0       0       0      1         0       0
## 2            0              0       0       0      0         0       0
## 3            0              0       1       0      0         1       0
## 4            1              0       0       1      1         0       0
## 5            0              0       0       1      0         0       1
## 6            0              0       0       0      0         0       1
##   Ajvar Ketchup Senf Mlijeko.0.5l Kiselo.vrhnje Feta.sir Sardine
## 1     0       1    1            0             0        0       0
## 2     0       0    0            1             1        0       0
## 3     1       0    0            0             0        0       0
## 4     1       1    0            1             0        1       0
## 5     0       0    0            1             0        0       0
## 6     0       0    0            0             0        0       0
##   Tuna.pašteta Nescaffe
## 1            1        0
## 2            1        0
## 3            1        1
## 4            0        0
## 5            0        0
## 6            1        0

Zadatak 9.12 - pretvorba okvira u ‘dugi’ format

##   racunID Coca.cola.2l Cipi.Cips Nutella.400.g Karlovacko.pivo
## 1   15671            0         0             0               0
## 2   15672            1         0             1               1
## 3   15673            1         1             0               0
## 4   15674            0         0             0               0
## 5   15675            1         0             1               0
## 6   15676            0         0             0               0
##   Ožujsko.pivo Omekšivac.1.5l Voda.2l Narance Jabuke Mandarine Salvete
## 1            1              0       0       0      1         0       0
## 2            0              0       0       0      0         0       0
## 3            0              0       1       0      0         1       0
## 4            1              0       0       1      1         0       0
## 5            0              0       0       1      0         0       1
## 6            0              0       0       0      0         0       1
##   Ajvar Ketchup Senf Mlijeko.0.5l Kiselo.vrhnje Feta.sir Sardine
## 1     0       1    1            0             0        0       0
## 2     0       0    0            1             1        0       0
## 3     1       0    0            0             0        0       0
## 4     1       1    0            1             0        1       0
## 5     0       0    0            1             0        0       0
## 6     0       0    0            0             0        0       0
##   Tuna.pašteta Nescaffe
## 1            1        0
## 2            1        0
## 3            1        1
## 4            0        0
## 5            0        0
## 6            1        0
##      racunID       artikl
## 417    15671 Ožujsko.pivo
## 833    15671       Jabuke
## 1249   15671      Ketchup
## 1353   15671         Senf
## 1873   15671 Tuna.pašteta
## 2      15672 Coca.cola.2l

Zadatak 9.13 - pretvorba okvira u ‘široki’ format

##   racunID Ajvar Cipi.Cips Coca.cola.2l Feta.sir Jabuke Karlovacko.pivo
## 1   15671     0         0            0        0      1               0
## 2   15672     0         0            1        0      0               1
## 3   15673     1         1            1        0      0               0
## 4   15674     1         0            0        1      1               0
## 5   15675     0         0            1        0      0               0
## 6   15676     0         0            0        0      0               0
##   Ketchup Kiselo.vrhnje Mandarine Mlijeko.0.5l Narance Nescaffe
## 1       1             0         0            0       0        0
## 2       0             1         0            1       0        0
## 3       0             0         1            0       0        1
## 4       1             0         0            1       1        0
## 5       0             0         0            1       1        0
## 6       0             0         0            0       0        0
##   Nutella.400.g Omekšivac.1.5l Ožujsko.pivo Salvete Sardine Senf
## 1             0              0            1       0       0    1
## 2             1              0            0       0       0    0
## 3             0              0            0       0       0    0
## 4             0              0            1       0       0    0
## 5             1              0            0       1       0    0
## 6             0              0            0       1       0    0
##   Tuna.pašteta Voda.2l
## 1            1       0
## 2            1       0
## 3            1       1
## 4            0       0
## 5            0       0
## 6            1       0

9.2.2 Funkcije separate i unite


Paket tidyr ima još niz korisnih funkcija namijenjenih “uređivanju” podataka a mi ćemo ovdje obratiti još dvije koje se relativno često koriste - separate i unite.

Funkcija separate je korisna kada neki stupac ima “složene” vrijednosti koje želimo rastaviti u dva ili više stupaca.

Zadatak 9.14 - podatkovni skup odjeli

## 'data.frame':    28 obs. of  4 variables:
##  $ Odjel   : chr  "A" "A" "A" "A" ...
##  $ Kvartal : chr  "Q1-2015" "Q2-2015" "Q3-2015" "Q4-2015" ...
##  $ PrihodKn: num  12416 224290 10644 191229 258697 ...
##  $ RashodKn: num  23101 63886 35468 12249 61515 ...
##   Odjel Kvartal PrihodKn RashodKn
## 1     A Q1-2015  12416.2  23100.5
## 2     A Q2-2015 224290.1  63886.1
## 3     A Q3-2015  10643.7  35467.8
## 4     A Q4-2015 191229.3  12249.1
## 5     A Q1-2016 258697.4  61514.6
## 6     A Q2-2016 121865.3  46092.6

Ova tablica prikazuje prihode i rashode odjela neke tvrtke po kvartalima. Kvartali su trenutno pohranjeni u složenu varijablu Kvartal koja se sastoji od identifikatora godišnjeg kvartala (Q1, Q2, Q3 ili Q4) i godine. Za potrebe analize vjerojatno bi bilo zgodno ovo rastaviti u dva stupca - Kvartal (koji bi pohranjivao samo identifikator kvartala) i Godina.

Paket tidyr za ovakve potrebe nudi funkciju separate sa sljedećim potpisom:

Potpunu dokumentaciju funkcije možemo pogledati naredbom ?separate a ovdje ćemo navesti objašnjenje nekih važnijih parametara:

  • col - stupac kojeg rastavljamo (ne moramo koristiti navodnike)
  • into - imena novih stupaca (preporučuje se koristiti znakovni vektor)
  • sep - separator vrijednosti u originalnom stupcu, default-na vrijednost je zapravo regularni izraz za “nešto što nije alfanumerički znak”
  • remove - opisuje da li je potrebno ukloniti originalni stupac ili ne

Pokušajmo primijeniti ovu funkciju na tablicu odjeli. Ponovimo usput princip korištenja pipeline operatora.


Zadatak 9.15 - funkcija separate

## 'data.frame':    28 obs. of  5 variables:
##  $ Odjel   : chr  "A" "A" "A" "A" ...
##  $ Kvartal : chr  "Q1" "Q2" "Q3" "Q4" ...
##  $ Godina  : chr  "2015" "2015" "2015" "2015" ...
##  $ PrihodKn: num  12416 224290 10644 191229 258697 ...
##  $ RashodKn: num  23101 63886 35468 12249 61515 ...
##   Odjel Kvartal Godina PrihodKn RashodKn
## 1     A      Q1   2015  12416.2  23100.5
## 2     A      Q2   2015 224290.1  63886.1
## 3     A      Q3   2015  10643.7  35467.8
## 4     A      Q4   2015 191229.3  12249.1
## 5     A      Q1   2016 258697.4  61514.6
## 6     A      Q2   2016 121865.3  46092.6

Uočite da su stupci Kvartal i Godina zapravo kategorijske varijable i da bi ih bilo dobro faktorizirati. Faktoriziranje stupaca je nešto teže izvesti uz pomoć pipeline operatora (iako je izvedivo!) no u narednim poglavljima naučiti ćemo kako to puno lakše napraviti uz pomoć funkcija iz paketa dplyr.

Funkcija separate se često koristi za rastavljanje datuma (npr. 2016-10-28 u godinu, mjesec i dan) no u takvim situacijama preporuka je koristiti paket lubridate koji je stvoren upravo za lakše upravljanje datumima. Ovaj paket upoznati ćemo u jednom od sljedećih poglavlja.


Za kraj naučimo još funkciju unite koja se nešto rijeđe koristi a zapravo je inverz funkcije separate. Potpis funkcije unite je:

I u ovom slučaju dokumentaciju lako dohvaćamo sa ?unite, a ovdje dajemo opis parametara koji potencijalno zahtijevaju dodatno objašnjenje:

  • col - ime novog stupca (nije nužno koristiti navodnike)
  • ... - imena stupaca koje spajamo - ne moramo koristiti navodnike, a ukoliko ima puno stupaca možemo se koristiti sličnom sintaksom za odabir kao i kod funkcije gather

Isprobajmo naredbu na okviru odjeli2.


Zadatak 9.16 - funkcija unite

## 'data.frame':    28 obs. of  4 variables:
##  $ Odjel   : chr  "A" "A" "A" "A" ...
##  $ Kvartal : chr  "Q1-2015" "Q2-2015" "Q3-2015" "Q4-2015" ...
##  $ PrihodKn: num  12416 224290 10644 191229 258697 ...
##  $ RashodKn: num  23101 63886 35468 12249 61515 ...
## 'data.frame':    28 obs. of  4 variables:
##  $ Odjel   : chr  "A" "A" "A" "A" ...
##  $ Kvartal : chr  "Q1-2015" "Q2-2015" "Q3-2015" "Q4-2015" ...
##  $ PrihodKn: num  12416 224290 10644 191229 258697 ...
##  $ RashodKn: num  23101 63886 35468 12249 61515 ...
##   Odjel Kvartal PrihodKn RashodKn
## 1     A Q1-2015  12416.2  23100.5
## 2     A Q2-2015 224290.1  63886.1
## 3     A Q3-2015  10643.7  35467.8
## 4     A Q4-2015 191229.3  12249.1
## 5     A Q1-2016 258697.4  61514.6
## 6     A Q2-2016 121865.3  46092.6
##   Odjel Kvartal PrihodKn RashodKn
## 1     A Q1-2015  12416.2  23100.5
## 2     A Q2-2015 224290.1  63886.1
## 3     A Q3-2015  10643.7  35467.8
## 4     A Q4-2015 191229.3  12249.1
## 5     A Q1-2016 258697.4  61514.6
## 6     A Q2-2016 121865.3  46092.6

Zadaci za vježbu

  1. Inicijalizirajte 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 za aritmetičkom sredinom 10000 i standardnom devijacijom 1000
  • zaokružite brojeve na prvi veći cijeli broj
  • izbacite duplikate iz skupa
  • poredajte skup po veličini
  • slučajnim odabirom iz skupa izvucite 100 elemenata
  • organizirajte tih 100 elemenata u matricu 10 x 10, složenu po retcima
  • izračunajte sume redaka matrice
  • ispišite prosjek suma redaka na zaslon.
  1. U datoteci weather.csv nalaze se podaci o izmjerenim vremenskim uvjetima od strane meteorološke stanice koja svaki sat vremena mjeri temperaturu, tlak, vlažnost i brzinu vjetra (podaci su preuzeti i prilagođeni iz podatkovnog skupa paketa weatherData dostupnog na CRAN-u). Izvedite sljedeće:
  • učitajte datoteku u podatkovni okvir i proučite učitane podatke (names, str, summary, head…)
  • odgovorite: da li se radi o urednim podacima? Zašto?
  • poduzmite odgovarajuće korake kako bi dobili podatkovni okvir koji odgovara principu urednih podataka
  • spremite “uređeni” u okvir u datoteku weatherClean.csv

Creative Commons License
Programirajmo u R-u by Damir Pintar is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Based on a work at https://ratnip.github.io/FER_OPJR/

References

Bache, Stefan Milton, and Hadley Wickham. 2014. Magrittr: A Forward-Pipe Operator for R. https://CRAN.R-project.org/package=magrittr.