22 Primjer upravljanja podacima

Ovdje će se prikazati osnove upravljanja podacima na datasetu ‘starwars’ iz paketa dplyr [8].

library(tidyverse)
library(dplyr)

data("starwars")
glimpse(starwars)
## Rows: 87
## Columns: 14
## $ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Or…
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2…
## $ mass       <dbl> 77, 75, 32, 136, 49, 120, 75, 32, 84, 77, 84, NA, 112, 80, …
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N…
## $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "…
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",…
## $ birth_year <dbl> 19, 112, 33, 42, 19, 52, 47, NA, 24, 57, 42, 64, 200, 29, 4…
## $ sex        <chr> "male", "none", "none", "male", "female", "male", "female",…
## $ gender     <chr> "masculine", "masculine", "masculine", "masculine", "femini…
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…
## $ films      <list> <"A New Hope", "The Empire Strikes Back", "Return of the J…
## $ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imp…
## $ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1",…

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 × 14
##   name      height  mass hair_color skin_color eye_color birth_year sex   gender
##   <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
## 1 Luke Sky…    172    77 blond      fair       blue            19   male  mascu…
## 2 C-3PO        167    75 <NA>       gold       yellow         112   none  mascu…
## 3 R2-D2         96    32 <NA>       white, bl… red             33   none  mascu…
## 4 Darth Va…    202   136 none       white      yellow          41.9 male  mascu…
## 5 Leia Org…    150    49 brown      light      brown           19   fema… femin…
## 6 Owen Lars    178   120 brown, gr… light      blue            52   male  mascu…
## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
## #   vehicles <list>, starships <list>

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 Or…
## $ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2…
## $ mass       <dbl> 77, 75, 32, 136, 49, 120, 75, 32, 84, 77, 84, NA, 112, 80, …
## $ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N…
## $ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",…
## $ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
## $ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…

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     
##  Mode :logical   Mode :logical   Mode :logical   Mode :logical  
##  FALSE:87        FALSE:81        FALSE:59        FALSE:82       
##                  TRUE :6         TRUE :28        TRUE :5        
##  eye_color       homeworld        species       
##  Mode :logical   Mode :logical   Mode :logical  
##  FALSE:87        FALSE:77        FALSE:83       
##                  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 37, 40, 80 i 86. 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:

  • Ric Olié: Human
  • Quarsh Panaka: Human
  • Sly Moore: Umbaran
  • Captain Phasma: Human

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[37] <- "Human"
Starwars$species[40] <- "Human"
Starwars$species[80] <- "Umbaran"
Starwars$species[86] <- "Human"

Provjera:

summary(is.na(Starwars$species))
##    Mode   FALSE    TRUE 
## logical      83       4

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("Ric Olié" = "Human", 
                          "Quarsh Panaka" = "Human", 
                          "Sly Moore" = "Umbaran", 
                          "Captain Phasma" = "Human")
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"                
## [4] "Greedo"                "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"        
##  [5] "brown, grey"   "black"         "auburn, white" "auburn, grey" 
##  [9] "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"        
##  [5] "brown, grey"   "black"         "auburn, white" "auburn, grey" 
##  [9] "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"  
##  [8] "unknown" "black"   "auburn"  "blond"   "auburn"  "brown"   "brown"  
## [15] "unknown" "unknown" "brown"   "brown"   "white"   "grey"    "black"  
## [22] "none"    "none"    "black"   "none"    "none"    "auburn"  "brown"  
## [29] "brown"   "none"    "brown"   "none"    "blond"   "brown"   "none"   
## [36] "none"    "none"    "brown"   "black"   "none"    "black"   "black"  
## [43] "none"    "none"    "none"    "none"    "none"    "none"    "none"   
## [50] "none"    "white"   "none"    "black"   "none"    "none"    "none"   
## [57] "none"    "none"    "black"   "brown"   "brown"   "none"    "black"  
## [64] "black"   "brown"   "white"   "black"   "black"   "blonde"  "none"   
## [71] "none"    "none"    "white"   "none"    "none"    "none"    "none"   
## [78] "none"    "brown"   "brown"   "none"    "none"    "black"   "brown"  
## [85] "brown"   "none"    "none"
Starwars$hair_color <- hair_colors_first 
unique(Starwars$hair_color)
## [1] "blond"   "unknown" "none"    "brown"   "black"   "auburn"  "white"  
## [8] "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 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"        
##  [5] "Hutt"           NA               "Yoda's species" "Trandoshan"    
##  [9] "Mon Calamari"   "Ewok"           "Sullustan"      "Neimodian"     
## [13] "Gungan"         "Toydarian"      "Zabrak"         "Twi'lek"       
## [17] "Aleena"         "Vulptereen"     "Xexto"          "Toong"         
## [21] "Cerean"         "Nautolan"       "Tholothian"     "Iktotchi"      
## [25] "Quermian"       "Kel Dor"        "Chagrian"       "Geonosian"     
## [29] "Mirialan"       "Clawdite"       "Besalisk"       "Kaminoan"      
## [33] "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 
##              1              1              1              1              1 
##          Droid           Ewok      Geonosian         Gungan          Human 
##              5              1              1              2             37 
##           Hutt       Iktotchi        Kaleesh       Kaminoan        Kel Dor 
##              1              1              1              2              1 
##       Mirialan   Mon Calamari           Muun       Nautolan      Neimodian 
##              2              1              1              1              1 
##         Pau'an       Quermian         Rodian        Skakoan      Sullustan 
##              1              1              1              1              1 
##     Tholothian        Togruta          Toong      Toydarian     Trandoshan 
##              1              1              1              1              1 
##        Twi'lek        Umbaran     Vulptereen        Wookiee          Xexto 
##              2              1              1              2              1 
## Yoda's species         Zabrak 
##              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" 
## [8] "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 × 3
##   vrsta    prosjek_visina prosjek_tezina
##   <chr>             <dbl>          <dbl>
## 1 Droid              131.           69.8
## 2 Gungan             210            74  
## 3 Human              176.           79.4
## 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    Prosječna visina Prosječna težina
## A Droid    131.2            69.75           
## B Gungan   210              74              
## C Human    176.451612903226 79.36           
## 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, za korisnike koji vole pratiti izračune „korak po korak”, drugi pristup će biti primamljiviji 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 × 3
##   vrsta    prosjek_visina sd_visina
##   <chr>             <dbl>     <dbl>
## 1 Droid              131.     49.1 
## 2 Gungan             210      19.8 
## 3 Human              176.     17.5 
## 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)

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" ...

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 Ewok Geonosian Gungan
##   auburn       0        0      0        0        0     0    0         0      0
##   black        0        0      0        0        0     0    0         0      0
##   blonde       0        0      0        0        1     0    0         0      0
##   brown        0        0      0        0        0     0    1         0      0
##   grey         0        0      0        0        0     0    0         0      0
##   unknown      1        1      0        1        0     5    0         1      2
##   white        0        0      1        0        0     0    0         0      0
##          
##           Human Hutt Iktotchi Kaleesh Kaminoan Kel Dor Mirialan Mon Calamari
##   auburn      3    0        0       0        0       0        0            0
##   black       8    0        0       0        0       0        2            0
##   blonde      3    0        0       0        0       0        0            0
##   brown      13    0        0       0        0       0        0            0
##   grey        1    0        0       0        0       0        0            0
##   unknown     7    1        1       1        2       1        0            1
##   white       2    0        0       0        0       0        0            0
##          
##           Muun Nautolan Neimodian Pau'an Quermian Rodian Skakoan Sullustan
##   auburn     0        0         0      0        0      0       0         0
##   black      0        0         0      0        0      0       0         0
##   blonde     0        0         0      0        0      0       0         0
##   brown      0        0         0      0        0      0       0         0
##   grey       0        0         0      0        0      0       0         0
##   unknown    1        1         1      1        1      1       1         1
##   white      0        0         0      0        0      0       0         0
##          
##           Tholothian Togruta Toong Toydarian Trandoshan Twi'lek Umbaran
##   auburn           0       0     0         0          0       0       0
##   black            0       0     0         1          0       0       0
##   blonde           0       0     0         0          0       0       0
##   brown            0       0     0         0          0       0       1
##   grey             0       0     0         0          0       0       0
##   unknown          1       1     1         0          1       2       0
##   white            0       0     0         0          0       0       0
##          
##           Vulptereen Wookiee Xexto Yoda's species Zabrak
##   auburn           0       0     0              0      0
##   black            0       0     0              0      1
##   blonde           0       0     0              0      0
##   brown            0       2     0              0      0
##   grey             0       0     0              0      0
##   unknown          1       0     1              0      1
##   white            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     8        0        2       0       0      1
##   blonde      0      0     3        0        0       0       0      0
##   brown       0      0    13        0        0       0       2      0
##   grey        0      0     1        0        0       0       0      0
##   unknown     5      2     7        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 veza između visina i težina u uzorku. Također, 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.

Literatura

[8]
W. Yarberry and W. Yarberry, “Dplyr,” CRAN Recipes: DPLYR, Stringr, Lubridate, and RegEx in R, pp. 1–58, 2021.