12 Primjer upravljanja podacima

Ovdje će se prikazati osnove upravljanja podacima na datasetu ‘starwars’ iz paketa dplyr (Yarberry and Yarberry 2021). Ovo poglavlje pruža praktičan uvid u primjenu tehnika upravljanja podacima u R-u, koristeći dataset starwars iz paketa dplyr. Kroz primjere se ilustrira kako pristupiti podacima, odabrati i filtrirati relevantne varijable te kako raditi s podacima koji nedostaju. Posebna pažnja posvećena je osnovnim tehnikama čišćenja podataka: zamjena vrijednosti koje nedostaju, formatiranje podataka te pretvaranje višestrukih unosa u jedinstvene zapise. Prikazani su primjeri kako se koristiti složenim tabličnim prikazima, poput tablica kontingencije, dok se dodatnim statističkim izračunima i vizualizacijama analizira raspodjela i povezanost unutar podataka.

> library(tidyverse)
> library(dplyr)
> data("starwars")
> data("starwars")
> glimpse(starwars)
## Rows: 87
## Columns: 14
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Organa", "Owen Lars", "Beru Whitesun Lars",~
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 228, 180, 173, 175, 170, 180, 66, 170, 183~
## $ mass       <dbl> 77, 75, 32, 136, 49, 120, 75, 32, 84, 77, 84, NA, 112, 80, 74, 1358, 77, 110, 17, 75, 78, 140, 113, ~
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", NA, "black", "auburn, white", "blond", "au~
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "light", "white, red", "light", "fair", "f~
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue", "red", "brown", "blue-gray", "blue", "bl~
## $ birth_year <dbl> 19, 112, 33, 42, 19, 52, 47, NA, 24, 57, 42, 64, 200, 29, 44, 600, 21, NA, 896, 82, 32, 15, 53, 31, ~
## $ sex        <chr> "male", "none", "none", "male", "female", "male", "female", "none", "male", "male", "male", "male", ~
## $ gender     <chr> "masculine", "masculine", "masculine", "masculine", "feminine", "masculine", "feminine", "masculine"~
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "Tatooine", "Tatooine", "Tatooine", "Tatooi~
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Human", "Droid", "Human", "Human", "Human", "~
## $ films      <list> <"A New Hope", "The Empire Strikes Back", "Return of the Jedi", "Revenge of the Sith", "The Force A~
## $ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imperial Speeder Bike", <>, <>, <>, <>, "Tri~
## $ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1", <>, <>, <>, <>, "X-wing", <"Jedi starfig~

Prvo, vidimo da podatkovni okvir sadrži 14 varijabli sa 87 opažanja:

  • varijabla ime je tipa „character”, kao što i očekujemo
  • varijabla visine je numerička cjelobrojna varijabla, „int”
  • varijabla masa/ težina je numerička varijable, „double”
  • varijable boja kose, boja kože, boja očiju, spol, rod, planet s kojeg potječu i vrsta su tipa „character
  • filmovi, vozila i svemirski brodovi su liste

Dodatni uvid u strukturu podataka:

> head(starwars)
## # A tibble: 6 x 14
##   name    height  mass hair_color skin_color eye_color birth_year sex   gender homeworld species films vehicles starships
##   <chr>    <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr>  <chr>     <chr>   <lis> <list>   <list>   
## 1 Luke S~    172    77 blond      fair       blue            19   male  mascu~ Tatooine  Human   <chr> <chr>    <chr [2]>
## 2 C-3PO      167    75 <NA>       gold       yellow         112   none  mascu~ Tatooine  Droid   <chr> <chr>    <chr [0]>
## 3 R2-D2       96    32 <NA>       white, bl~ red             33   none  mascu~ Naboo     Droid   <chr> <chr>    <chr [0]>
## 4 Darth ~    202   136 none       white      yellow          41.9 male  mascu~ Tatooine  Human   <chr> <chr>    <chr [1]>
## 5 Leia O~    150    49 brown      light      brown           19   fema~ femin~ Alderaan  Human   <chr> <chr>    <chr [0]>
## 6 Owen L~    178   120 brown, gr~ light      blue            52   male  mascu~ Tatooine  Human   <chr> <chr>    <chr [0]>

Ovdje ćemo se detaljnije pozabaviti podatkovnim okvirom, pa ćemo odabrati nekoliko varijabli za daljnje uvide. Odabirom stupaca s određenim varijablama (bilo putem rednih brojeva stupaca ili naziva) kreirat ćemo novi podatkovni skup.

> Starwars <- as.data.frame(starwars[,c(1:4,6,10,11)])
> glimpse(Starwars)
## Rows: 87
## Columns: 7
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Organa", "Owen Lars", "Beru Whitesun Lars",~
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 228, 180, 173, 175, 170, 180, 66, 170, 183~
## $ mass       <dbl> 77, 75, 32, 136, 49, 120, 75, 32, 84, 77, 84, NA, 112, 80, 74, 1358, 77, 110, 17, 75, 78, 140, 113, ~
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", NA, "black", "auburn, white", "blond", "au~
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue", "red", "brown", "blue-gray", "blue", "bl~
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "Tatooine", "Tatooine", "Tatooine", "Tatooi~
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Human", "Droid", "Human", "Human", "Human", "~

Provjeru podataka koji nedostaju izvršit ćemo kombinacijom dvije funkcije, summary() i is.na(). Druga funkcija služi provjeri nalaze li se u varijabli NA (vrijednosti koje nedostaju), a summary() će poslužiti za jasan prikaz.

> summary(is.na(Starwars))
##     name           height           mass         hair_color      eye_color       homeworld        species       
##  Mode :logical   Mode :logical   Mode :logical   Mode :logical   Mode :logical   Mode :logical   Mode :logical  
##  FALSE:87        FALSE:81        FALSE:59        FALSE:82        FALSE:87        FALSE:77        FALSE:83       
##                  TRUE :6         TRUE :28        TRUE :5                         TRUE :10        TRUE :4

Za 6 likova nedostaje podatak o visini, za 28 nedostaje podatak o težini, za 5 nedostaje podatak o boji kose…. Ukratko, is.na(starwars) provjerava je li vrijednost prisutna (FALSE) ili nedostaje (TRUE), dok summary te podatke sažima u zbroj podataka koji su navedeni i onih koji nedostaju.

Recimo da pretpostavljamo da bismo mogli znati podatke koji nedostaju o vrsti, pa želimo identificirati gdje se nalaze NA, kako bismo ih eventualno izmijenili.

> na_pozicije <- which(is.na(Starwars$species))
> na_pozicije
## [1] 18 59 60 81

NA se nalaze na pozicijama 18, 59, 60 i 81. Moramo provjeriti o kojim se likovima radi.

> Starwars$name[na_pozicije]
## [1] "Jek Tono Porkins" "Gregar Typho"     "Cordé"            "Sly Moore"

Kratkim pretraživanjem, možemo saznati kojim vrstama pripadaju ovi likovi:

  • Jek Tono Porkins: Human
  • Gregar Typho: Human
  • Cordé: Human
  • Sly Moore: Umbaran

Sada možemo zamijeniti postojeće NA poznatim podacima. To možemo učiniti na dva načina. S obzirom da ih je malo, možemo koristiti „ručni” unos:

> Starwars$species[18] <- "Human"
> Starwars$species[59] <- "Human"
> Starwars$species[60] <- "Human"
> Starwars$species[81] <- "Umbaran"

Provjera:

> summary(is.na(Starwars$species))
##    Mode   FALSE 
## logical      87

Svi su podaci uspješno zamijenjeni i ta varijabla više ne sadrži NA. Kad bi u pitanju bilo više vrijednosti, onda bi bilo praktičnije prvo kreirati vektor koji mapira imena likova na njihove vrste. Potom bi se koristila petlja for ili vektorizirana funkcija za pregled redova u podatkovnom okviru i zamijenile NA vrijednosti odgovarajućim vrstama:

> species_replacements <- c("Jek Tono Porkins" = "Human", 
+                           "Gregar Typho" = "Human", 
+                           "Cordé" = "Human", 
+                           "Sly Moore" = "Umbaran")
> for (name in names(species_replacements)) {
+     na_indices <- is.na(Starwars$species) & Starwars$name == name
+     Starwars$species[na_indices] <- species_replacements[name]
+ }

Ovaj kod prvo identificira redove u kojima je species NA i gdje se ime lika podudara s ključem u species_replacements. Zatim zamjenjuje NA odgovarajućom vrstom.

Sljedeće, provjeravamo za boju kose.

> na_pozicije <- which(is.na(Starwars$hair_color))
> na_pozicije
## [1]  2  3  8 15 16
> Starwars$name[na_pozicije]
## [1] "C-3PO"                 "R2-D2"                 "R5-D4"                 "Greedo"               
## [5] "Jabba Desilijic Tiure"

Za navedene likove boja kose nije primjenjiva. Kako se ne bismo bavili s NA, možemo ih zamijeniti s, na primjer „Unknown” i odmah provjeriti provedbu zamjene.

> Starwars$hair_color[na_pozicije]<- "Unknown"
> 
> summary(is.na(Starwars$hair_color))
##    Mode   FALSE 
## logical      87
> unique(Starwars$hair_color)
##  [1] "blond"         "Unknown"       "none"          "brown"         "brown, grey"   "black"         "auburn, white"
##  [8] "auburn, grey"  "white"         "grey"          "auburn"        "blonde"

Druga stvar koja se može primijetiti kod boje kose jest da se pojavljuje Unknown i unknown kao zasebna „boja”, iako se radi o pojmovno istoj stvari. To je zbog toga što je R osjetljiv na velika i mala slova. No to možemo jednostavno riješiti tako što ćemo sve znakove u varijabli hair_color podesiti na mala slova.

> Starwars$hair_color<-tolower(Starwars$hair_color)
> unique(Starwars$hair_color)
##  [1] "blond"         "unknown"       "none"          "brown"         "brown, grey"   "black"         "auburn, white"
##  [8] "auburn, grey"  "white"         "grey"          "auburn"        "blonde"

Druga stvar koju se može primijetiti kod boje kose jest da da su za neke likove zapisane dvije boje. Recimo da želimo zadržati samo prvu zapisanu boju. To znači da prvo moramo razdvojiti zapisane boje, a potom pohraniti prvu boju u varijablu hair_color.

> hair_colors_first <- sapply(strsplit(Starwars$hair_color, ", "), `[`, 1)
> hair_colors_first
##  [1] "blond"   "unknown" "unknown" "none"    "brown"   "brown"   "brown"   "unknown" "black"   "auburn"  "blond"  
## [12] "auburn"  "brown"   "brown"   "unknown" "unknown" "brown"   "brown"   "white"   "grey"    "black"   "none"   
## [23] "none"    "black"   "none"    "none"    "auburn"  "brown"   "brown"   "none"    "brown"   "none"    "blond"  
## [34] "brown"   "none"    "none"    "none"    "brown"   "black"   "none"    "black"   "black"   "none"    "none"   
## [45] "none"    "none"    "none"    "none"    "none"    "none"    "white"   "none"    "black"   "none"    "none"   
## [56] "none"    "none"    "none"    "black"   "brown"   "brown"   "none"    "black"   "black"   "brown"   "white"  
## [67] "black"   "black"   "blonde"  "none"    "none"    "none"    "white"   "none"    "none"    "none"    "none"   
## [78] "none"    "brown"   "brown"   "none"    "none"    "black"   "brown"   "brown"   "none"    "none"
> Starwars$hair_color <- hair_colors_first 
> unique(Starwars$hair_color)
## [1] "blond"   "unknown" "none"    "brown"   "black"   "auburn"  "white"   "grey"    "blonde"

Uočavamo još dvije stvari: blond i blonde su sinonimi, stoga i to treba korigirati. Također, unknown i none bi također mogli biti vezani za istu situaciju te none možemo zamijeniti s unknown.

> # Zamjena "blond" s "blonde"
> Starwars$hair_color <- gsub("\\bblond\\b", "blonde", Starwars$hair_color) 
> # \\b označava granicu riječi, što osigurava da se zamjena dogodi samo onda
> #kada se „blond" pojavljuje kao zasebna riječ, a ne kao dio druge riječi
> 
> # Zamjena „none" s „unknown"
> Starwars$hair_color <- gsub("none", "unknown", Starwars$hair_color)
> 
> unique(Starwars$hair_color)
## [1] "blonde"  "unknown" "brown"   "black"   "auburn"  "white"   "grey"

Ovime smo završili čišćenje podataka u varijabli hair_color. Daljnja analiza ovisi o kvaliteti podataka. Ako podaci nisu pravilno zapisani, potrebno je provesti „čišćenje” podataka, na način da se podaci ne ujednače na pravilan način, riješi se pitanje NA, definira prikladan tip varijable i slično.

Recimo da nas zbunjuje korištenje engleskih naziva i zbog toga želimo promijeniti nazive varijabli u podatkovnom okviru.

> colnames(Starwars) <-c("ime", "visina", "tezina", 
+                        "boja_kose", "boja_ociju", 
+                        "planet", "vrsta")
> str(Starwars)
## 'data.frame':    87 obs. of  7 variables:
##  $ ime       : chr  "Luke Skywalker" "C-3PO" "R2-D2" "Darth Vader" ...
##  $ visina    : int  172 167 96 202 150 178 165 97 183 182 ...
##  $ tezina    : num  77 75 32 136 49 120 75 32 84 77 ...
##  $ boja_kose : chr  "blonde" "unknown" "unknown" "unknown" ...
##  $ boja_ociju: chr  "blue" "yellow" "red" "yellow" ...
##  $ planet    : chr  "Tatooine" "Tatooine" "Naboo" "Tatooine" ...
##  $ vrsta     : chr  "Human" "Droid" "Droid" "Human" ...

Recimo da nas zanima koliko iznosi prosječna visina i težina za svaku vrstu. Prvo bismo morali provjeriti koliko ima različitih vrsta, a potom za svaku izračunati visinu i težinu. Nakon toga, mogli bismo to prikazati u tablici.

> unique(Starwars$vrsta)
##  [1] "Human"          "Droid"          "Wookiee"        "Rodian"         "Hutt"           "Yoda's species"
##  [7] "Trandoshan"     "Mon Calamari"   "Ewok"           "Sullustan"      "Neimodian"      "Gungan"        
## [13] "Toydarian"      "Dug"            "Zabrak"         "Twi'lek"        "Aleena"         "Vulptereen"    
## [19] "Xexto"          "Toong"          "Cerean"         "Nautolan"       "Tholothian"     "Iktotchi"      
## [25] "Quermian"       "Kel Dor"        "Chagrian"       "Geonosian"      "Mirialan"       "Clawdite"      
## [31] "Besalisk"       "Kaminoan"       "Skakoan"        "Muun"           "Togruta"        "Kaleesh"       
## [37] "Umbaran"        "Pau'an"

Koristeći naredbu unique(), utvrđujemo da postoji 38 jedinstvenih naziva za vrste. No, izgledno je da će se neke vrste pojavljivati samo jedanput. Za njih nećemo računati prosječne vrijednosti. To znači da prvo moramo utvrditi frekvencije pojavljivanja vrsta. To možemo učiniti na sljedeći način.

> vrsta_frekv <- table(Starwars$vrsta)
> vrsta_frekv
## 
##         Aleena       Besalisk         Cerean       Chagrian       Clawdite          Droid            Dug           Ewok 
##              1              1              1              1              1              6              1              1 
##      Geonosian         Gungan          Human           Hutt       Iktotchi        Kaleesh       Kaminoan        Kel Dor 
##              1              3             38              1              1              1              2              1 
##       Mirialan   Mon Calamari           Muun       Nautolan      Neimodian         Pau'an       Quermian         Rodian 
##              2              1              1              1              1              1              1              1 
##        Skakoan      Sullustan     Tholothian        Togruta          Toong      Toydarian     Trandoshan        Twi'lek 
##              1              1              1              1              1              1              1              2 
##        Umbaran     Vulptereen        Wookiee          Xexto Yoda's species         Zabrak 
##              1              1              2              1              1              2
> vrsta_multiple <- which(vrsta_frekv > 1)
> vrsta_multiple_nazivi <- names(vrsta_multiple)
> vrsta_multiple_nazivi
## [1] "Droid"    "Gungan"   "Human"    "Kaminoan" "Mirialan" "Twi'lek"  "Wookiee"  "Zabrak"

Za svaku od ovih vrsta izračunat ćemo prosjek visine i težine temeljem podskupa podataka samo za tu vrstu. To se može učiniti na više načina, a ovdje će se prikazati dva načina.

U prvom slučaju koristimo dplyr paket i filtriranje skupa podataka, a potom grupiranje i sažimanje.

> filtered_data <- Starwars %>% 
+                  filter(vrsta %in% vrsta_multiple_nazivi)
> 
> prosjek_visina_tezina <- filtered_data %>%
+   group_by(vrsta) %>%
+   summarise(
+     prosjek_visina = mean(visina, na.rm = TRUE),
+     prosjek_tezina = mean(tezina, na.rm = TRUE)
+                      )
> prosjek_visina_tezina
## # A tibble: 8 x 3
##   vrsta    prosjek_visina prosjek_tezina
##   <chr>             <dbl>          <dbl>
## 1 Droid              131.           69.8
## 2 Gungan             209.           74  
## 3 Human              178.           82.8
## 4 Kaminoan           221            88  
## 5 Mirialan           168            53.1
## 6 Twi'lek            179            55  
## 7 Wookiee            231           124  
## 8 Zabrak             173            80

Alternativno, možemo koristiti pristup „pješke” upotrebom podskupa podataka. Na taj način izračunavamo prosjek visine za pojedinu vrstu temeljem filtracije za jednu vrstu. Isto to učinimo za težinu, a potom ponovimo postupak za preostale vrste. Na kraju objedinimo podatke u tablicu.

> prosjek_visine_Droid <- mean(Starwars$visina[Starwars$vrsta=="Droid"], 
+                              na.rm = TRUE)
> 
> # Ovdje moramo koristiti 'na.rm = TRUE' zato jer varijable 
> # visine i težine sadrže nepoznanice koje nismo korigirali
> # zbog na.rm će funkcija mean() ignorirati vrijednosti koje nedostaju; 
> # u suprotnom bismo dobili NA ili error
> 
> prosjek_tezine_Droid <- mean(Starwars$tezina[Starwars$vrsta=="Droid"], 
+                              na.rm = TRUE)
> 
> prosjek_visine_Gungan <- mean(Starwars$visina[Starwars$vrsta=="Gungan"], 
+                               na.rm = TRUE)
> prosjek_tezine_Gungan <- mean(Starwars$tezina[Starwars$vrsta=="Gungan"], 
+                               na.rm = TRUE)
> 
> prosjek_visine_Human <- mean(Starwars$visina[Starwars$vrsta=="Human"], 
+                              na.rm = TRUE)
> prosjek_tezine_Human <- mean(Starwars$tezina[Starwars$vrsta=="Human"], 
+                              na.rm = TRUE)
> 
> prosjek_visine_Kaminoan <- mean(Starwars$visina[Starwars$vrsta=="Kaminoan"], 
+                                 na.rm = TRUE)
> prosjek_tezine_Kaminoan <- mean(Starwars$tezina[Starwars$vrsta=="Kaminoan"], 
+                                 na.rm = TRUE)
> 
> prosjek_visine_Mirialan <- mean(Starwars$visina[Starwars$vrsta=="Mirialan"], 
+                                 na.rm = TRUE)
> prosjek_tezine_Mirialan <- mean(Starwars$tezina[Starwars$vrsta=="Mirialan"], 
+                                 na.rm = TRUE)
> 
> prosjek_visine_Twilek <- mean(Starwars$visina[Starwars$vrsta=="Twi'lek"], 
+                               na.rm = TRUE)
> prosjek_tezine_Twilek <- mean(Starwars$tezina[Starwars$vrsta=="Twi'lek"], 
+                               na.rm = TRUE)
> 
> prosjek_visine_Wookiee <- mean(Starwars$visina[Starwars$vrsta=="Wookiee"], 
+                                na.rm = TRUE)
> prosjek_tezine_Wookiee <- mean(Starwars$tezina[Starwars$vrsta=="Wookiee"], 
+                                na.rm = TRUE)
> 
> prosjek_visine_Zabrak <- mean(Starwars$visina[Starwars$vrsta=="Zabrak"], 
+                               na.rm = TRUE)
> prosjek_tezine_Zabrak<- mean(Starwars$tezina[Starwars$vrsta=="Zabrak"], 
+                              na.rm = TRUE)
> 
> # Kreiramo tablicu prikaza
> 
> visina_tezina_vrsta <-matrix(c("Droid", 
+                                prosjek_visine_Droid, prosjek_tezine_Droid,
+                                "Gungan", 
+                                prosjek_visine_Gungan, prosjek_tezine_Gungan,
+                                "Human", 
+                                prosjek_visine_Human, prosjek_tezine_Human,
+                                "Kaminoan", 
+                                prosjek_visine_Kaminoan, prosjek_tezine_Kaminoan,
+                                "Mirialan", 
+                                prosjek_visine_Mirialan, prosjek_tezine_Mirialan,
+                                "Twi'lek", 
+                                prosjek_visine_Twilek, prosjek_tezine_Twilek,
+                                "Wookiee", 
+                                prosjek_visine_Wookiee, prosjek_tezine_Wookiee,
+                                "Zabrak", 
+                                prosjek_visine_Zabrak, prosjek_tezine_Zabrak),
+                              nrow = 8, byrow = TRUE)
> 
> colnames(visina_tezina_vrsta) <- c("Vrsta", "Prosječna visina", 
+                                    "Prosječna težina")
> 
> visina_tezina_vrsta<-as.table(visina_tezina_vrsta)
> visina_tezina_vrsta
##   Vrsta    Prosjecna visina Prosjecna težina
## A Droid    131.2            69.75           
## B Gungan   208.666666666667 74              
## C Human    177.636363636364 82.7818181818182
## D Kaminoan 221              88              
## E Mirialan 168              53.1            
## F Twi'lek  179              55              
## G Wookiee  231              124             
## H Zabrak   173              80

Rezultat je isti, iako je prvi pristup puno brži. No, ako preferirate pratiti izračune „korak po korak”, drugi pristup će vam biti prihvatljiviji unatoč većem broju linija koda.

Recimo da bismo htjeli vizualno prikazati distribucije visina po vrstama i pretpostavljamo da su visine normalno distribuirane varijable za svaku od vrsta. U tom slučaju, potrebna nam je standardna devijacija za svaku vrstu.

Treba napomenuti da ovo činimo zbog primjera za vježbu i grafičkog prikaza te u inferencijalnoj statistici nećete običavati koristiti podatke ovako malih uzoraka da biste pretpostavljali distribuciju bilo koje karakteristike čitave vrste ili bilo koje veće populacije.

> prosjek_sd_visina <- filtered_data %>%
+   group_by(vrsta) %>%
+   summarise(
+     prosjek_visina = mean(visina, na.rm = TRUE),
+     sd_visina = sd(visina, na.rm = TRUE)
+                      )
> prosjek_sd_visina
## # A tibble: 8 x 3
##   vrsta    prosjek_visina sd_visina
##   <chr>             <dbl>     <dbl>
## 1 Droid              131.     49.1 
## 2 Gungan             209.     14.2 
## 3 Human              178.     12.1 
## 4 Kaminoan           221      11.3 
## 5 Mirialan           168       2.83
## 6 Twi'lek            179       1.41
## 7 Wookiee            231       4.24
## 8 Zabrak             173       2.83
> Droidi <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[1], 
+                         prosjek_sd_visina$sd_visina[1]))
> Gungan <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[2], 
+                         prosjek_sd_visina$sd_visina[2]))
> Human <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[3], 
+                        prosjek_sd_visina$sd_visina[3]))
> Kaminoan <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[4], 
+                           prosjek_sd_visina$sd_visina[4]))         
> Mirialan  <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[5], 
+                            prosjek_sd_visina$sd_visina[5]))        
> Twilek  <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[6], 
+                          prosjek_sd_visina$sd_visina[6]))       
> Wookiee  <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[7], 
+                           prosjek_sd_visina$sd_visina[7]))         
> Zabrak  <- density(rnorm(1000,prosjek_sd_visina$prosjek_visina[8], 
+                          prosjek_sd_visina$sd_visina[8]))
> 
> plot(Droidi, main="Visine vrsta", xlab="Visina", ylab="Gustoća",
+      col="red", lwd=2, xlim=c(25,275), ylim=c(0,0.3))
> lines(Gungan, col="blue", lwd=2)
> lines(Human, col="green", lwd=2)
> lines(Kaminoan, col="yellow", lwd=2)
> lines(Mirialan, col="orange", lwd=2)
> lines(Twilek, col="purple", lwd=2)
> lines(Wookiee, col="brown", lwd=2)
> lines(Zabrak, col="pink", lwd=2)
> legend("topright", legend=c("Droidi", "Gungan", "Human", "Kaminoan", 
+                             "Mirialan", "Twi'lek", "Wookiee", "Zabrak"),
+        col=c("red", "blue", "green", "yellow", 
+              "orange", "purple", "brown", "pink"), lwd=2)

Alternativno, možda želimo dobiti uvid u distribuciju podataka o opaženim visinama (a ne generiranim vrijednostima) koristeći box-plot. Ako kreiramo usporedne box-plotove za sve vrste iz podskupa filtered_data, moći ćemo ih međusobno usporediti.

> ggplot(filtered_data, aes(x = vrsta, y = visina, fill = vrsta)) +
+   geom_boxplot(alpha = 0.7) + 
+   labs(
+     title = "Box-plot visina po vrstama",
+     x = "Vrsta",
+     y = "Visina"
+   ) +
+   theme_minimal() +
+   theme(
+     plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
+     axis.text.x = element_text(angle = 45, hjust = 1) 
+   ) +
+   scale_fill_brewer(palette = "Set3")

Box-plot prikazuje značajne razlike u visinama među vrstama. Kaminoan i Wookiee ističu se kao najviše vrste, s visokim vrijednostima medijana, dok Droidi i Mirialan imaju najniže medijane. Raspon visina je najširi kod Droida, što sugerira veliku varijabilnost unutar te vrste, dok vrste poput Wookiee i Zabrak imaju uže raspone, što znači da su visine unutar tih vrsta konzistentnije. Human i Gungan imaju slične raspone varijacija.

Neke vrste, poput Kaminoan, nemaju izdvojenice, dok druge vrste pokazuju visine koje su izvan tipičnih vrijednosti. Ova usporedba omogućuje bolji uvid u razlike među vrstama, naglašavajući kako se vrste razlikuju ne samo po prosječnoj visini već i po varijabilnosti i ekstremnim vrijednostima unutar svojih distribucija.

No, za pokazatelje deskriptivne statistike, možemo, na primjer, koristiti i paket summarytools. S obzirom da želimo izračunati pokazatelje za svaku vrstu zasebno, kombinirat ćemo s naredbom stby() iz paketa dplyr. Prva naredba, kojom bismo utvrdili sve vrste, neće se pokrenuti, jer je ispis podugačak. No, možete isprobati sami. Drugom skupinom naredbi kreira se podskup podataka koji obuhvaća dvije vrsta (Droide i ljude), a potom se izračunavaju pokazatelji deskriptivne statistike za svaku vrstu likova.

> # stby(data = Starwars, INDICES = Starwars$vrsta, 
> #      FUN = function(x) descr(Starwars[,2:3], stats = "all"))
> starwars_subset <- Starwars %>%
+   filter(Starwars$vrsta %in% c("Human", "Droid"))
> 
> stby(data = starwars_subset[, c("tezina", "visina")], 
+                INDICES = starwars_subset$vrsta, 
+                FUN = descr, 
+                stats = "all")
## Descriptive Statistics  
## starwars_subset  
## Group: vrsta = Droid  
## N: 6  
## 
##                     tezina   visina
## ----------------- -------- --------
##              Mean    69.75   131.20
##           Std.Dev    51.03    49.15
##               Min    32.00    96.00
##                Q1    32.00    96.00
##            Median    53.50    97.00
##                Q3   107.50   167.00
##               Max   140.00   200.00
##               MAD    31.88     1.48
##               IQR    59.25    71.00
##                CV     0.73     0.37
##          Skewness     0.45     0.41
##       SE.Skewness     1.01     0.91
##          Kurtosis    -1.95    -2.02
##           N.Valid     4.00     5.00
##         Pct.Valid    66.67    83.33
## 
## Group: vrsta = Human  
## N: 38  
## 
##                     tezina   visina
## ----------------- -------- --------
##              Mean    82.78   177.64
##           Std.Dev    19.38    12.12
##               Min    45.00   150.00
##                Q1    77.00   170.00
##            Median    79.00   180.00
##                Q3    84.00   185.00
##               Max   136.00   202.00
##               MAD     5.93    11.86
##               IQR     7.00    15.00
##                CV     0.23     0.07
##          Skewness     0.80    -0.54
##       SE.Skewness     0.49     0.41
##          Kurtosis     1.46    -0.17
##           N.Valid    22.00    33.00
##         Pct.Valid    57.89    86.84

Droidi su prosječno teški 69.75 kg, uz standardno odstupanje težina od prosjeka za 51.03 kg ukazuje na relativno veliku varijabilnost. U malim uzorcima uobičajeno se opaža veća varijabilnost u podacima. Raspon težina, od 32 kg do 140 kg, dodatno potvrđuje postojanje ekstremnih vrijednosti. Polovica Droida u uzorku teška je 53 kg ili manje od toga, dok je preostala polovica teška toliko ili više. Središnjih 50% podataka o visini nalazi se između 55 i 85 kg. Distribucija težine Droida blago je pozitivno asimetrična, dok je distribucija vrhom zaobljenija od normalne.

Droidi su prosječno visoki 131.20 cm, uz standardno odstupanje visine od prosjeka za 49.15 cm. Raspon varijacija visina kreće se od 96 do 200 cm. Središnjih 50% Droida visoko je između 96 i 167 cm, ukazujući na izdvojenice s desne strane distribucije. To potvrđuje i pokazatelj asimetrije, ukazujući na to da je distribucija visina Droida blago pozitivno asimetrična. Slično kao i distribucija težina, distribucija visina Droida je vrhom zaobljenija od normalne.

Ljudi u uzorku su prosječno teški 82.78 kg, uz standardno odstupanje težine od prosjeka za 19.38 kg, što ukazuje na umjerenu varijabilnost težina među ljudima. Polovica ljudi u uzorku ima težinu od 79 kg ili manje, dok druga polovica ima težinu veću od toga. Prosjek je veći od medijana, što upućuje na postojanje nekolicine velikih vrijednosti u nizu, koje odvlače prosjek k većim vrijednostima. Raspon težina kreće se od minimalnih 45 kg do maksimalnih 136 kg, dok se središnjih 50% podataka o težini nalazi u intervalu između 77 kg i 84 kg. Distribucija težine je blago pozitivno asimetrična, što potvrđuje da postoji nekoliko ljudi s većim težinama koje odstupaju od većine opažanja. Kurtosis, ili zaobljenost distribucije, ukazuje na izduženiji vrh distribucije u odnosu na normalnu i veću koncentraciju opažanja oko prosjeka.

Prosječna visina ljudi u uzorku iznosi 177.64 cm, uz standardno odstupanje od 12.12 cm, što ukazuje na nisku varijabilnost visina. Raspon visina kreće se od minimalnih 150 cm do maksimalnih 202 cm. Središnjih 50% ljudi visoko je između 170 cm i 185 cm. Distribucija visina je blago negativno asimetrična, što znači da postoji nekoliko ljudi s nižim visinama koje povlače distribuciju ulijevo. Kurtosis ukazuje na distribuciju koja je oblikom blizu normalnoj distribuciji, s blago zaobljenijim vrhom.

No, može nas zanimati i postoji li veza između visina i težina likova Starwarsa.

> starwars_clean <- Starwars %>%
+   select(vrsta, tezina, visina) %>%
+   filter(!is.na(visina) & !is.na(tezina))
> 
> cor(starwars_clean[2:3], use = "pairwise.complete.obs")
##        tezina visina
## tezina   1.00   0.13
## visina   0.13   1.00

Vrijednost korelacije 0.13 sugerira da postoji vrlo slab pozitivan odnos između težine i visine. To znači da, u prosjeku, s povećanjem visine, težina blago raste. Ipak, radi se o vrlo slaboj povezanosti, koja ne ukazuje na izraženu pravilnost.

Budući da skup podataka sadrži različite vrste likova, moguće je da razlike između skupina značajno smanjuju ukupnu korelaciju. Na primjer, Droidi mogu imati različite obrasce povezanosti težine i visine u usporedbi s ljudima. Bilo bi korisno izračunati korelacije unutar specifičnih skupina (npr. za ljude i Droide) kako bismo vidjeli postoji li jača povezanost u homogenijim podskupinama.

> library(ggplot2)
> 
> ggplot(data = starwars_subset, aes(x = visina, y = tezina, color = vrsta)) +
+   geom_point(size = 3, alpha = 0.7) +
+   labs(
+     x = "Visina (cm)",
+     y = "Težina (kg)",
+     color = "Vrsta"
+   ) +
+   theme_minimal() +
+   theme(
+     plot.title = element_text(hjust = 0.5, size = 14),
+     axis.title = element_text(size = 12),
+     legend.title = element_text(size = 12),
+     legend.text = element_text(size = 10)
+   )

> cor_droid <- starwars_subset %>%
+   filter(vrsta == "Droid") %>%
+   select(tezina, visina) %>%
+   cor(use = "pairwise.complete.obs")
> cor_droid
##        tezina visina
## tezina   1.00   0.96
## visina   0.96   1.00

Koeficijent korelacije između težine i visine Droida iznosi 0.96, što ukazuje na vrlo snažnu pozitivnu linearnu vezu. To znači da, kako se povećava visina Droida, težina također gotovo proporcionalno raste. Ovaj visok koeficijent može biti posljedica malog uzorka Droida i homogennosti njihovih karakteristika u skupu podataka, ali je vjerojatnije da je težina rezultat njihove visine i materijala koji su korišteni u njihovoj konstrukciji (veći Droidi zahtijevaju više materijala, što povećava njihovu težinu). S obzirom da Droidi nemaju biološke varijacije poput ljudi (npr., razlike u masi mišića, gustoći kostiju ili postotku masti), veza između težine i visine je jača.

> cor_human <- starwars_subset %>%
+   filter(vrsta == "Human") %>%
+   select(tezina, visina) %>%
+   cor(use = "pairwise.complete.obs")
> cor_human
##        tezina visina
## tezina   1.00   0.51
## visina   0.51   1.00

Koeficijent krelacije između težine i visine iznosi 0.51, što ukazuje na umjerenu pozitivnu linearnu vezu. Ovo je očekivano jer su kod ljudi visina i težina povezane, ali nisu savršeno proporcionalne (npr., razlike u građi tijela, masi mišića, itd.). Dakle umjerena pozitivna korelacija je u skladu s raznolikošću podataka o ljudima u uzorku.

Također, sličnu analizu možemo provesti i za sve vrste, no ovdje ćemo samo grafički prikazati uvide koje možemo dobiti dijagramom rasipanja.

> library(ggplot2)
> library(dplyr)
> 
> starwars_clean <- Starwars %>%
+   # odabiremo opažanja koja ne sadrže NA 
+   # te eliminiramo jednu izdvojenicu
+   filter(!is.na(visina) & !is.na(tezina) & tezina <= 1000) %>%
+   select(vrsta, visina, tezina)
> 
> ggplot(data = starwars_clean, aes(x = visina, y = tezina, color = vrsta)) +
+   geom_point(size = 3, alpha = 0.7) +
+   labs(
+     title = "Raspršenost visine i težine u Starwars skupu podataka",
+     x = "Visina (cm)",
+     y = "Težina (kg)",
+     color = "Vrsta"
+   ) +
+   theme_minimal() +
+   theme(
+     plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
+     axis.title = element_text(size = 12),
+     legend.title = element_text(size = 12),
+     legend.text = element_text(size = 10),
+     legend.position = "bottom"
+   )

Ako želite, možete samostalno provesti daljnju analizu visina i težina za svaku vrstu, po uzoru na postupak proveden za Droide i ljude.

Sljedeće nas zanima koji likovi iz određenih vrsta imaju visinu i težinu iznad dvije standardne devijacije od prosjeka za svoju vrstu? Odgovor na to pitanje iziskuje nekoliko koraka u analizi. Prvo je potrebno izračunati prosječnu visinu i težinu za svaku vrstu u skupu podataka. Nakon toga trebamo filtrirati likove koji su iznad prosječne visine i težine za svoju vrstu. I naravno, na kraju treba ispisati ili prikazati rezultate. Ovo je izvrstan primjer na kojem se može prikazati kreiranje vlastitih funkcija u kontekstu analize podataka.

> library(dplyr)
> 
> # Funkcija za pronalazak likova iznad prosječne visine i težine
> iznadprosjecni_likovi <- function(data, vrsta, visina, tezina) {
+   
+   # 1. Grupiranje podataka po vrsti i računanje prosjeka
+   avg_stats <- data %>%
+     group_by(!!sym(vrsta)) %>%
+     summarize(
+       avg_visina = mean(!!sym(visina), na.rm = TRUE),
+       sd_visina = sd(!!sym(visina), na.rm = TRUE),
+       avg_tezina = mean(!!sym(tezina), na.rm = TRUE),
+       sd_tezina = sd(!!sym(tezina), na.rm = TRUE)
+     )
+   
+   # 2. Spajanje originalnih podataka s prosjecima
+   data_with_avg <- data %>%
+     left_join(avg_stats, by = vrsta)
+   
+   # 3. Filtriranje likova čija visina i težina odstupaju više od 2 standardne devijacije iznad prosjeka
+   above_2sd <- data_with_avg %>%
+     filter(
+       !!sym(visina) > avg_visina + 2 * sd_visina &
+       !!sym(tezina) > avg_tezina + 2 * sd_tezina
+     ) %>%
+     select(ime, !!sym(vrsta), !!sym(visina), !!sym(tezina))
+   
+   return(above_2sd)
+ }
> 
> # Primjena funkcije
> likovi <- iznadprosjecni_likovi(
+   data = Starwars,
+   vrsta = "vrsta",
+   visina = "visina",
+   tezina = "tezina"
+ )
> 
> # Prikaz rezultata
> likovi
##           ime vrsta visina tezina
## 1 Darth Vader Human    202    136

Recimo da se sad želimo usredotočiti na raznovrsnost imena i želimo ih prvo poredati po abecedi. Jedan od načina kako možemo dobiti takav prikaz i čitav skup podataka poredati prema imenima likova je koristeći funkciju arrange().

> sorted_Starwars <- arrange(Starwars, ime)  
> # kad bismo htjeli poredati silazno po imenima Z->A, 
> # onda bi umjesto imena upisali desc(ime)
> str(sorted_Starwars)
## 'data.frame':    87 obs. of  7 variables:
##  $ ime       : chr  "Ackbar" "Adi Gallia" "Anakin Skywalker" "Arvel Crynyd" ...
##  $ visina    : int  180 184 188 NA 178 NA 191 166 163 165 ...
##  $ tezina    : num  83 50 84 NA 55 NA NA 50 65 75 ...
##  $ boja_kose : chr  "unknown" "unknown" "blonde" "brown" ...
##  $ boja_ociju: chr  "orange" "blue" "blue" "brown" ...
##  $ planet    : chr  "Mon Cala" "Coruscant" "Tatooine" NA ...
##  $ vrsta     : chr  "Mon Calamari" "Tholothian" "Human" "Human" ...

Ako nas zanima koliko je jedinstvenih imena, odnosno likova, obuhvaćeno ovim skupom podataka, možemo koristiti funkciju unique().

> unique(sorted_Starwars$ime)
##  [1] "Ackbar"                "Adi Gallia"            "Anakin Skywalker"      "Arvel Crynyd"         
##  [5] "Ayla Secura"           "BB8"                   "Bail Prestor Organa"   "Barriss Offee"        
##  [9] "Ben Quadinaros"        "Beru Whitesun Lars"    "Bib Fortuna"           "Biggs Darklighter"    
## [13] "Boba Fett"             "Bossk"                 "C-3PO"                 "Captain Phasma"       
## [17] "Chewbacca"             "Cliegg Lars"           "Cordé"                 "Darth Maul"           
## [21] "Darth Vader"           "Dexter Jettster"       "Dooku"                 "Dormé"                
## [25] "Dud Bolt"              "Eeth Koth"             "Finis Valorum"         "Finn"                 
## [29] "Gasgano"               "Greedo"                "Gregar Typho"          "Grievous"             
## [33] "Han Solo"              "IG-88"                 "Jabba Desilijic Tiure" "Jango Fett"           
## [37] "Jar Jar Binks"         "Jek Tono Porkins"      "Jocasta Nu"            "Ki-Adi-Mundi"         
## [41] "Kit Fisto"             "Lama Su"               "Lando Calrissian"      "Leia Organa"          
## [45] "Lobot"                 "Luke Skywalker"        "Luminara Unduli"       "Mace Windu"           
## [49] "Mas Amedda"            "Mon Mothma"            "Nien Nunb"             "Nute Gunray"          
## [53] "Obi-Wan Kenobi"        "Owen Lars"             "Padmé Amidala"         "Palpatine"            
## [57] "Plo Koon"              "Poe Dameron"           "Poggle the Lesser"     "Quarsh Panaka"        
## [61] "Qui-Gon Jinn"          "R2-D2"                 "R4-P17"                "R5-D4"                
## [65] "Ratts Tyerel"          "Raymus Antilles"       "Rey"                   "Ric Olié"             
## [69] "Roos Tarpals"          "Rugor Nass"            "Saesee Tiin"           "San Hill"             
## [73] "Sebulba"               "Shaak Ti"              "Shmi Skywalker"        "Sly Moore"            
## [77] "Tarfful"               "Taun We"               "Tion Medon"            "Wat Tambor"           
## [81] "Watto"                 "Wedge Antilles"        "Wicket Systri Warrick" "Wilhuff Tarkin"       
## [85] "Yarael Poof"           "Yoda"                  "Zam Wesell"

Recimo da nas u sljedećem koraku zanimaju boje kose prema vrsti likova te apsolutne frekvencije u kojima se pojedine kombinacije pojavljuju. Za to nam je potrebna tablica kontingence.

> contingency_table <- table(Starwars$boja_kose, Starwars$vrsta)
> 
> # Prikazivanje tablice
> contingency_table
##          
##           Aleena Besalisk Cerean Chagrian Clawdite Droid Dug Ewok Geonosian Gungan Human Hutt Iktotchi Kaleesh Kaminoan
##   auburn       0        0      0        0        0     0   0    0         0      0     3    0        0       0        0
##   black        0        0      0        0        0     0   0    0         0      0     9    0        0       0        0
##   blonde       0        0      0        0        1     0   0    0         0      0     3    0        0       0        0
##   brown        0        0      0        0        0     0   0    1         0      0    16    0        0       0        0
##   grey         0        0      0        0        0     0   0    0         0      0     1    0        0       0        0
##   unknown      1        1      0        1        0     6   1    0         1      3     4    1        1       1        2
##   white        0        0      1        0        0     0   0    0         0      0     2    0        0       0        0
##          
##           Kel Dor Mirialan Mon Calamari Muun Nautolan Neimodian Pau'an Quermian Rodian Skakoan Sullustan Tholothian
##   auburn        0        0            0    0        0         0      0        0      0       0         0          0
##   black         0        2            0    0        0         0      0        0      0       0         0          0
##   blonde        0        0            0    0        0         0      0        0      0       0         0          0
##   brown         0        0            0    0        0         0      0        0      0       0         0          0
##   grey          0        0            0    0        0         0      0        0      0       0         0          0
##   unknown       1        0            1    1        1         1      1        1      1       1         1          1
##   white         0        0            0    0        0         0      0        0      0       0         0          0
##          
##           Togruta Toong Toydarian Trandoshan Twi'lek Umbaran Vulptereen Wookiee Xexto Yoda's species Zabrak
##   auburn        0     0         0          0       0       0          0       0     0              0      0
##   black         0     0         1          0       0       0          0       0     0              0      1
##   blonde        0     0         0          0       0       0          0       0     0              0      0
##   brown         0     0         0          0       0       0          0       2     0              0      0
##   grey          0     0         0          0       0       0          0       0     0              0      0
##   unknown       1     1         0          1       2       1          1       0     1              0      1
##   white         0     0         0          0       0       0          0       0     0              1      0

S obzirom da postoji puno jedinstvenih kombinacija i jako puno kombinacija koje se ne pojavljuju, možemo isto ispitati za podskup vrsta za koje smo ranije utvrdili da su učestalije i spremili u df filtered_data.

> contingency_table <- table(filtered_data$boja_kose, filtered_data$vrsta)
> 
> # Prikazivanje tablice
> contingency_table
##          
##           Droid Gungan Human Kaminoan Mirialan Twi'lek Wookiee Zabrak
##   auburn      0      0     3        0        0       0       0      0
##   black       0      0     9        0        2       0       0      1
##   blonde      0      0     3        0        0       0       0      0
##   brown       0      0    16        0        0       0       2      0
##   grey        0      0     1        0        0       0       0      0
##   unknown     6      3     4        2        0       2       0      1
##   white       0      0     2        0        0       0       0      0

Svi Droidi imaju nepoznatu boju kose, odnosno nemaju kose. Slična je situacija i sa svim Gunganima, Kaminoanima, Twi’lekima i jednim/om Zabrakom. Kosa ljudi se pojavljuje u najviše boja. Temeljem ovog uzorka, moglo bi se zaključiti da Mirilalani imaju crnu kosu, Wookiee imaju smeđu kosu, a Zabraci imaju crnu ili nemaju kose.

Što bi nas moglo zanimati dalje? Moglo bi nas zanimati postoji li statistički značajna razlika u težinama s obzirom na vrstu. Mogli bismo htjeti kreirati dodatne grafičke prikaze… Uz dovoljno podataka i predznanja te malo znatiželje, dostupni skupovi podataka u R-u mogu postati nepresušna oaza za vježbanje i kalibriranje vještina upravljanja podacima.

Pitanja za ponavljanje

  1. Koje funkcije možete koristiti za pregled strukture skupa podataka i uvida u varijable s nedostajućim vrijednostima?

  2. Kako biste identificirali sve pozicije s vrijednostima koje nedostaju za određenu varijablu, npr. species?

  3. Na koji način možemo ručno zamijeniti specifične NA vrijednosti u varijabli species u skupu podataka Starwars?

  4. Objasnite kako koristiti funkciju tolower() za ujednačavanje teksta u varijabli hair_color. Koji je problem riješen ovom funkcijom?

  5. Kako bi izgledao kod za zamjenu riječi „blond“ s „blonde“ u varijabli hair_color? Koji je dodatni simbol korišten kako bi se zamjena izvršila samo za tu riječ?

  6. Na koji način biste prikazali različite vrste unutar skupa podataka Starwars i koliko puta se svaka od njih pojavljuje?

  7. Koristeći dplyr, kako biste dobili prosječne vrijednosti visine i težine po vrsti u skupu podataka?

  8. Na koji način biste kreirali vizualni prikaz distribucija visina za svaku vrstu? Koje pretpostavke su ovdje korištene?

  9. Kako biste poredali podatke u Starwars prema imenima likova u uzlaznom redoslijedu koristeći dplyr?

  10. Na koji način biste ispitali odnos između boje kose i vrste likova te prikazali apsolutne frekvencije za kombinacije pomoću tablice kontingencije?

Zadaci

Otvorite novi R Script dokument.

  1. Kreirajte vektor z koji će sadržavati sve parne brojeve između 50 i 100.
  2. Provjerite tip z-a.
  3. Izračunajte prosjek vrijednosti varijable z.
  4. Kreirajte podatkovni okvir prema podacima iz tablice na 32. stranici u Statističkim informacijama
  5. Pretvorite podatkovni okvir iz prošlog zadatka u tablicu.
  6. Kreirajte vektor temeljem podataka iz tablice na 33. stranici Statističkih informacija, na način da koristite samo opažanja iz 2020. godine za minimalno šest varijabli.
  7. Kreirajte vektor temeljem podataka iz tablice na 33. stranici Statističkih informacija, na način da koristite samo opažanja iz 2019. godine za iste varijable koje ste odabrali u prethodnom zadatku.
  8. Vektorima iz 6. i 7. zadatka pridružite nazive.
  9. Spojite vektore iz 6. i 7. zadatka.
  10. Vektor iz prethodnog zadatka pretvorite u matricu.
  11. Matrici iz prethodnog zadatka pridodajte opažanja iz 2018., za iste varijable, iz istog izvora podataka.
  12. Matricu pretvorite u podatkovni okvir.
  13. Iz podatkovnog okvira obrišite jedan podatak iz 2018. godine.
  14. Iz podatkovnog okvira obrišite jednu, proizvoljno odabranu, varijablu.
  15. Izračunajte nekoliko statističkih pokazatelja za preostale varijable.
  16. Je li moguće spojiti dva podatkovna okvira koja ste kreirali? Obrazložite odgovor.
  17. Ako vas zanima udio nezaposlenih žena prema razinama obrazovanja, na koji način možete sortirati/filtrirati podatkovni okvir?
  18. Na stranici 36. Statističkih informacija pogledajte dio podataka pod nazivom Upisani studenti. Na koje je sve načine moguće podatke zapisati u R-u? O kakvim se podacima radi? Što su opažanja, a što su varijable?
  19. Na stranici 53 istog dokumenta, nalazi se tablica „BRUTO DOMAĆI PROIZVOD REPUBLIKE HRVATSKE”. Razmislite o kakvim se podacima radi, što su varijable, a što opažanja i na koji bi način bilo potrebno upisati podatke u R da se kreira podatkovni okvir.
  20. Ako niste ranije, bilo bi dobro sad proći sve primjere naredbi u ovom dokumentu. Osobitu pozornost posvetite onim funkcijama koje su vam nejasne i ne zaboravite koristiti prozor Help. Ako i nakon toga imate poteškoće, javite se za konzultacije ili pitajte na početku sljedećeg sata.

Otvorite novi R Script dokument.

  1. Iz paketa nycflights13 uvezite podatke flights.
  2. Izdvojite sve letove koji su poletjeli iz zračne luke JFK i imali kašnjenje pri polasku veće od 60 minuta.
  3. Sortirajte letove prema duljini leta (air_time) u silaznom redoslijedu.
  4. Dodajte novu varijablu koja prikazuje razliku između planiranog i stvarnog vremena dolaska (arr_delay - dep_delay).
  5. Kreirajte novi podatkovni okvir koji uključuje samo varijable origin, dest, air_time, i distance.
  6. Koliko je ukupno letova bilo iz svake zračne luke (origin)?
  7. Koji je bio najdulji let (air_time) iz zračne luke EWR?
  8. Kolika je prosječna udaljenost (distance) letova s obzirom na polazište (origin)?
  9. Kreirajte histogram koji prikazuje distribuciju kašnjenja pri polasku (dep_delay).
  10. Izračunajte pokazatelje deskriptivne statistike za varijable air_time i distance.

Otvorite novi R Script dokument.

  1. Učitajte podatke dostupne na: “http://sites.williams.edu/rdeveaux/files/2014/09/Saratoga.txt
  2. Jesu li cijene kuća uz obalu (Waterfront == 1) više u usporedbi s onima koje nisu uz obalu? Odgovor potkrijepite grafički.
  3. Kako se cijene nekretnina mijenjaju s obzirom na broj soba (Rooms)?
  4. Jesu li cijene novoizgrađene nekretnine (New.Construct == 1) više u odnosu na one koje nisu novogradnja?
  5. Imaju li kuće s više kamina (Fireplaces) veću prosječnu cijenu? Kako se cijena razlikuje za kuće s jednim, dva ili više kamina?
  6. Kako je omjer broja kupaonica (Bathrooms) i broja soba (Rooms) vezan uz cijenu kuće? Jesu li kuće s većim brojem kupaonica po sobi skuplje?
  7. Izračunajte pokazatelje deskriptivne statistike za sve kvantitativne varijable.
  8. Kreirajte prikladan grafički prikaz za svaku varijablu u ovom podatkovnom okviru.
  9. Korištenjem grafičkog prikaza provjerite razlike u medijalnim cijenama kuća s obzirom na centralno grijanje (Central.Air)?
  10. Kreirajte tablice frekvencija za sve kvalitativne varijable o ovom skupu podataka.

Otvorite novi R Script dokument.

  1. U svibnju 2024., više od 65000 programera odgovorilo je na godišnju anketu o kodiranju, tehnologijama i alatima koje koriste i koje žele naučiti, umjetnoj inteligenciji i iskustvu programera na poslu. Podaci su dostupni za preuzimanje putem linka u .zip datoteci. Ta datoteka uključuje provedeni upitnik (u pdf formatu) te dva .csv dokumenta. Učitajte survey_results_public.csv.
  2. Izračunajte udio vrijednosti koje nedostaju za svaku varijablu. Je li možda samo pitanje razlog izostanka odgovora?
  3. Pronađite 10 najčešćih zemalja (Country) među ispitanicima i izračunajte njihovu relativnu učestalost.
  4. Kreirajte tablicu frekvencija za starosne skupine (Age) i prikažite podatke grafički.
  5. Kreirajte tablicu kontingence za varijable Employment i LearnCode.
  6. Izdvojite jedinstvene vrijednosti za sve OfficeStackAsync te sve OfficeStackSync varijable, a nakon toga utvrdite učestalosti. Koje su najpoželjnije baze?
  7. Izdvojite najčešće jezike koje ispitanici koriste (LanguageHaveWorkedWith) i prikažite njihove frekvencije.Koristeći tablicu kontingencije, povežite s načinom na koji su naučili kodirati (LearnCode)
  8. Izdvojite sve varijable koje sadrže Admired u nazivu i utvrdite učestalosti svakog modaliteta.
  9. Izdvojite i grafički prikažite najčešće načine upotrebe AI-a.
  10. Zadovoljstvo poslom mjereno je varijablama koje u nazivu sadrže JobSatPoints. Kreirajte novu varijablu, na način da ona predstavlja niz prosječnih opažanja po recima, a nakon toga, tu novu varijablu prikažite histogramom i box-plotom.
  11. Pronađite jezike koje ispitanici žele koristiti (LanguageWantToWorkWith) i usporedite s jezicima koje trenutno koriste.
  12. Izračunajte osnovne statističke pokazatelje za godišnje plaće (ConvertedCompYearly), uklanjajući vrijednosti koje nedostaju.
  13. Prikažite distribuciju veličina organizacija (OrgSize) u kojima ispitanici rade.
  14. Izračunajte prosječno radno iskustvo u godinama (WorkExp) za ispitanike koji rade puno radno vrijeme.
  15. Postoji li veza između radnog iskustva u godinama (WorkExp) i godišnjih plaća (ConvertedCompYearly) zaposlenika? Je li ta veza jača ili slabija, ako se odnos tih varijabli ispituje zasebno za ispitanike po državama?

Važno je ne zaboraviti - na kraju rada pohraniti projekt/ skriptu…