class: center, middle, inverse, title-slide # OBRADA PODATAKA ## Predavanje 5: Manipulacija i prilagodba podataka (tidyverse) ### Luka Sikic, PhD ### Fakultet hrvatskih studija |
OP
--- name: toc # Pregled predavanja <br> <br> <br> <br> 1. [Set-up](#prologue) 2. [Tidyverse osnove](#basics) 3. [Manipulacija podatcima sa dplyr paketom](#dplyr) 4. [Manipulacija podatcima sa tidyr paketom](#tidyr) 5. [Pregled](#summary) --- class: inverse, center, middle name: prologue # Set-up <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Postavke za rad sa tidyverse paketima!) --- # Što su "tidy" podatci? <br> <br> Resursi: - [Vignette](https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html) (iz **tidyr** paketa) <br> - [Članak](https://vita.had.co.nz/papers/tidy-data.pdf) (Hadley Wickham, 2014 JSS) -- </br> Ključni elementi: 1. Svaka varijabla je u koloni. 2. Svaka opservacija je red. 3. Opservacija formiraju tablicu. -- </br> *Tidy* podatci će najćešće biti u [long (i.e. narrow) formatu](https://en.wikipedia.org/wiki/Wide_and_narrow_data). --- # Checklist <br> <br> <br> <br> <br> ☑ Instaliran [**tidyverse**](https://www.tidyverse.org/) paket. <br> <br> ☑ Potrebno instalirati [**nycflights13**](hhttps://github.com/hadley/nycflights13) paket. - Izvršite naredbu: `install.packages('nycflights13', repos = 'https://cran.rstudio.com')` --- class: inverse, center, middle name: basics # Tidyverse osnove <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Osnovna sintaksa.) --- # Tidyverse vs. base R Debata na temu *tidyverse vs. base R* u R zajednici. -- Nećemo ulaziti dublje u ovu raspravu jer je odgovor [očit](http://varianceexplained.org/r/teach-tidyverse/) : Bilo bi najbolje naučiti `tidyverse` na početku (što ranije). - Dokumentacija i podrška su izvrsni. - Konzistentna filozofija i sintaksa olakšava učenje. - `Tidyverse` omogućava praktičan"front-end" za neke važne big-data alate. - Za čišćenje, manipulaciju i vizualizaciju ... `tidyverse` je relativno jednostavan.<sup>1</sup> .footnote[ <sup>1</sup>Altertnativni pristup je [**data.table**](http://r-datatable.com/).] -- Ovo sve ne znači da treba preskočiti učenje `base R`. - Base R je ekstremno fleksibilan i moćan, posebno u kombinaciji sa drugim paketima. - Neke stvari se ne mogu napraviti u tidyverse-u. - Kombinacija `tidyverse` i `base R` je često rješenje. --- # Tidyverse vs. base R (dalje) Često postoje ekvivalenti između `base R` i `tidyverse`-a. Ovo se generalno odražava u sintaksi `tidyverse::snake_case` vs `base::period.case`. E.g. Usporedi: | tidyverse | base | |---|---| | `?readr::read_csv` | `?utils::read.csv` | | `?dplyr::if_else` | `?base::ifelse` | | `?tibble::tibble` | `?base::data.frame` | Etc... `Tidyverse` alternative uglavnom nude neka poboljšanja ili druge korisne opcije (ponekad i restrikcije) u odnosu na` base R`. - **Hint**: Uvijek postoji mnoštvo načina da se nešto izvede u R. --- <br> # Tidyverse paketi Učitajte `tidyverse` meta-paket i pogledajte output. ```r library(tidyverse) ``` ``` ## -- Attaching packages --------------------------------------- tidyverse 1.3.1 -- ``` ``` ## v ggplot2 3.3.5 v purrr 0.3.4 ## v tibble 3.1.3 v dplyr 1.0.7 ## v tidyr 1.1.3 v stringr 1.4.0 ## v readr 2.0.1 v forcats 0.5.1 ``` ``` ## -- Conflicts ------------------------------------------ tidyverse_conflicts() -- ## x dplyr::filter() masks stats::filter() ## x dplyr::lag() masks stats::lag() ``` -- Primjetite da smo učitali mnoštvo paketa (što je moguće napraviti i pojedinačno) : **ggplot2**, **tibble**, **dplyr**, etc. - Vidljive su i informacije o verzijama paketa i [namespace konfliktima](https://raw.githack.com/uo-ec607/lectures/master/04-rlang/04-rlang.html#59). --- # Tidyverse paketi (dalje) `Ttidyverse` se zapravo sastoji od više paketa nego što se automatski učitava.<sup>1</sup> ```r tidyverse_packages() ``` ``` ## [1] "broom" "cli" "crayon" "dbplyr" ## [5] "dplyr" "dtplyr" "forcats" "googledrive" ## [9] "googlesheets4" "ggplot2" "haven" "hms" ## [13] "httr" "jsonlite" "lubridate" "magrittr" ## [17] "modelr" "pillar" "purrr" "readr" ## [21] "readxl" "reprex" "rlang" "rstudioapi" ## [25] "rvest" "stringr" "tibble" "tidyr" ## [29] "xml2" "tidyverse" ``` Neke od ovih dodatnih paketa ćemo koristiti u okviru kolegija. — Na primjer, **lubridate** paket za raad sa datumima i **rvest** paket za webscraping. - Ipak, ti se paketi moraju učitati zasebno. .footnote[ <sup>1</sup> `Tidyverse` uključuje *puno* zavisnosti pri instalaciji. Ovo je tema uz koju se vežu određene [kontroverze](http://www.tinyverse.org/). ]. --- # Tidyverse paketi (dalje) <br> <br> <br> Cilj je upoznati većinu `tidyverse` paketa kroz ovaj kolegij. Naglasak današnjeg predavanja je na dva paketa: 1. [**dplyr**](https://dplyr.tidyverse.org/) 2. [**tidyr**](https://tidyr.tidyverse.org/) Ovo su glavni paketi za **čišćenje i manipulaciju** podatcima. Zbog toga će se jako često koristiti (naravno, uz **ggplot2**). <br> - Na čišćenje i manipulaciju podatcima odlazi jako puno vremena u radu sa podatcima. --- # Dodatak o pipe-ovima: %>% `%>%` se u R naziva **pipe operator** i automatski se učita sa `tidyverse`-om. Pipe operatori su sjani i njihovo korištenje znatno poboljšava iskustvo kodiranja. Usporedite: ```r ## Ovaj kod postiže isti cilj... mpg %>% filter(manufacturer=="audi") %>% group_by(model) %>% summarise(hwy_mean = mean(hwy)) ## kao ovaj: summarise(group_by(filter(mpg, manufacturer=="audi"), model), hwy_mean = mean(hwy)) ``` -- Prva linija koda se čita s ijeva na desno, baš kao što nalaže intuicija. - Uzmi objekt (`mpg`), napravi ovo (`filter`), nakon toga napravi (`group_by`), etc. Druga linija koda ima obrnutu intuiciju : zadnja operacija je logički na prvom mjestu! - Tko želi čitati stvari iznutra -> van!? --- # Dodatak o pipe-ovima: %>% <br> *Pipe verzija koda* je još čitljivija jer/kada se napiše kroz nekoliko redova: ```r mpg %>% filter(manufacturer=="audi") %>% group_by(model) %>% summarise(hwy_mean = mean(hwy)) ``` ``` ## # A tibble: 3 x 2 ## model hwy_mean ## <chr> <dbl> ## 1 a4 28.3 ## 2 a4 quattro 25.8 ## 3 a6 quattro 24 ``` **Hint**: Korištenje prostora ne košta ništa, a doprinosi čitljivosti koda. -- PS — Pipe orginalno potječe iz [**magrittr**](https://magrittr.tidyverse.org/) paketa ([geddit?](https://en.wikipedia.org/wiki/The_Treachery_of_Images)) i omogućava mnoštvo sjajnih stvari koje želite dodatno istražiti... --- class: inverse, center, middle name: dplyr # dplyr <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Ghost busters!) --- # Dodatno: dplyr 1.0.0 verzija <br> Neke od `dplyr` svojstava koja ćemo obraditi danas dolaze iz [verzije 1.0.0](https://www.tidyverse.org/blog/2020/06/dplyr-1-0-0/) paketa. - Verzija 1.0.0 je bitna jer donosi stabilnu verziju paketa. U trenutku pisanja, aktualna verzija je 1.0.7. - Provjerite da li imate barem **dplyr** 1.0.0. ```r packageVersion('dplyr') ``` ``` ## [1] '1.0.7' ``` ```r # install.packages('dplyr') ## instaliraj update verziju ako < 1.0.0 ``` -- *Note:* dplyr 1.0.0 javlja notifikaciju vezanu za grupirane varijable. Iako ta opcija može biti korisna, nekada ju želimo [isključiti](https://twitter.com/MattCowgill/status/1278463099272491008). ```r options(dplyr.summarise.inform = FALSE) ## dodaj .Rprofile za trajno isključenje ``` --- # Ključne dplyr funkcije <br> Postoji pet osnovnih dplyr funkcija koje je jako korisno naučiti. 1. `filter`: Filtriranje (i.e. *subset*) redova prema vrijednostima. 2. `arrange`: Uređivanje (i.e. *reorder*) redova prema vrijednostima. 3. `select`: Izaberi (i.e. *subset*) kolone prema nazivima: 4. `mutate`: Stvori nove kolone. 5. `summarise`: Sažmi više redova u deskriptivni pregled.<sup>1</sup> .footnote[ <sup>1</sup> `summarize` sa "z" također funkcionira. Nema diskriminacije u R! ] -- </br> Za pregled `dplyr` funkcionalnosti ćemo koristiti `starwars` podatkovni skup koji dolazi unutar `dplyr` paketa. Pregledajte `starwars` podatke sami. --- # 1) dplyr :: filter <br> Moguće je koristiti više filter naredbi sa pipe (`%>%`) operatorom ili ih odvojiti unutar zagrade zarezom. <br> ```r starwars %>% filter( species == "Human", height >= 190 ) ``` ``` ## # A tibble: 4 x 14 ## name height mass hair_color skin_color eye_color birth_year sex gender ## <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr> ## 1 Darth Va~ 202 136 none white yellow 41.9 male mascu~ ## 2 Qui-Gon ~ 193 89 brown fair blue 92 male mascu~ ## 3 Dooku 193 80 white fair brown 102 male mascu~ ## 4 Bail Pre~ 191 NA black tan brown 67 male mascu~ ## # ... with 5 more variables: homeworld <chr>, species <chr>, films <list>, ## # vehicles <list>, starships <list> ``` --- # 1) dplyr :: filter (*dalje*) <br> [Regex](https://en.wikipedia.org/wiki/Regular_expression) izrazi također funkcioniraju. <br> <br> ```r starwars %>% filter(grepl("Skywalker", name)) ``` ``` ## # A tibble: 3 x 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 Sk~ 172 77 blond fair blue 19 male mascu~ ## 2 Anakin ~ 188 84 blond fair blue 41.9 male mascu~ ## 3 Shmi Sk~ 163 NA black fair brown 72 female femin~ ## # ... with 5 more variables: homeworld <chr>, species <chr>, films <list>, ## # vehicles <list>, starships <list> ``` --- # 1) dplyr :: filter (*dalje*) <br> `Filter` se često koristi za (npr.) identifikaciju (ili uklanjanje) NA opservacija. ```r starwars %>% filter(is.na(height)) ``` ``` ## # A tibble: 6 x 14 ## name height mass hair_color skin_color eye_color birth_year sex gender ## <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr> ## 1 Arvel C~ NA NA brown fair brown NA male mascu~ ## 2 Finn NA NA black dark dark NA male mascu~ ## 3 Rey NA NA brown light hazel NA female femin~ ## 4 Poe Dam~ NA NA brown light brown NA male mascu~ ## 5 BB8 NA NA none none black NA none mascu~ ## 6 Captain~ NA NA unknown unknown unknown NA <NA> <NA> ## # ... with 5 more variables: homeworld <chr>, species <chr>, films <list>, ## # vehicles <list>, starships <list> ``` -- </br> Za uklanjanje NA opservacija je moguće koristiti negaciju: `filter(!is.na(height))`. Isprobajte! --- # 2) dplyr :: arrange <br> ```r starwars %>% arrange(birth_year) ``` ``` ## # A tibble: 87 x 14 ## name height mass hair_color skin_color eye_color birth_year sex gender ## <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr> ## 1 Wicket ~ 88 20 brown brown brown 8 male mascu~ ## 2 IG-88 200 140 none metal red 15 none mascu~ ## 3 Luke Sk~ 172 77 blond fair blue 19 male mascu~ ## 4 Leia Or~ 150 49 brown light brown 19 fema~ femin~ ## 5 Wedge A~ 170 77 brown fair hazel 21 male mascu~ ## 6 Plo Koon 188 80 none orange black 22 male mascu~ ## 7 Biggs D~ 183 84 black light brown 24 male mascu~ ## 8 Han Solo 180 80 brown fair brown 29 male mascu~ ## 9 Lando C~ 177 79 black dark brown 31 male mascu~ ## 10 Boba Fe~ 183 78.2 black fair brown 31.5 male mascu~ ## # ... with 77 more rows, and 5 more variables: homeworld <chr>, species <chr>, ## # films <list>, vehicles <list>, starships <list> ``` -- *Note:* Uređivanje na osnovi karakterne (i.e. string) varijable (kolone) će biti abecedno. --- # 2) dplyr :: arrange (*dalje*) Moguće je i uređivanje po padajućem redosljedu `arrange(desc())`. ```r starwars %>% arrange(desc(birth_year)) ``` ``` ## # A tibble: 87 x 14 ## name height mass hair_color skin_color eye_color birth_year sex gender ## <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr> ## 1 Yoda 66 17 white green brown 896 male mascu~ ## 2 Jabba ~ 175 1358 <NA> green-tan,~ orange 600 herm~ mascu~ ## 3 Chewba~ 228 112 brown unknown blue 200 male mascu~ ## 4 C-3PO 167 75 <NA> gold yellow 112 none mascu~ ## 5 Dooku 193 80 white fair brown 102 male mascu~ ## 6 Qui-Go~ 193 89 brown fair blue 92 male mascu~ ## 7 Ki-Adi~ 198 82 white pale yellow 92 male mascu~ ## 8 Finis ~ 170 NA blond fair blue 91 male mascu~ ## 9 Palpat~ 170 75 grey pale yellow 82 male mascu~ ## 10 Cliegg~ 183 NA brown fair blue 82 male mascu~ ## # ... with 77 more rows, and 5 more variables: homeworld <chr>, species <chr>, ## # films <list>, vehicles <list>, starships <list> ``` --- # 3) dplyr :: select Zarezi se mogu koristiti za izbor više kolona df-a. (Dozvoljena je i sintaksa `first : last` za sukcesivne kolone). Makni kolonu sa `-`. ```r starwars %>% select(name:skin_color, species, -height) ``` ``` ## # A tibble: 87 x 5 ## name mass hair_color skin_color species ## <chr> <dbl> <chr> <chr> <chr> ## 1 Luke Skywalker 77 blond fair Human ## 2 C-3PO 75 <NA> gold Droid ## 3 R2-D2 32 <NA> white, blue Droid ## 4 Darth Vader 136 none white Human ## 5 Leia Organa 49 brown light Human ## 6 Owen Lars 120 brown, grey light Human ## 7 Beru Whitesun lars 75 brown light Human ## 8 R5-D4 32 <NA> white, red Droid ## 9 Biggs Darklighter 84 black light Human ## 10 Obi-Wan Kenobi 77 auburn, white fair Human ## # ... with 77 more rows ``` --- # 3) dplyr :: select (*dalje*) Moguće je promijeniti naziv jedne ili više kolona. ```r starwars %>% select(alias=name, crib=homeworld, sex=gender) ``` ``` ## # A tibble: 87 x 3 ## alias crib sex ## <chr> <chr> <chr> ## 1 Luke Skywalker Tatooine masculine ## 2 C-3PO Tatooine masculine ## 3 R2-D2 Naboo masculine ## 4 Darth Vader Tatooine masculine ## 5 Leia Organa Alderaan feminine ## 6 Owen Lars Tatooine masculine ## 7 Beru Whitesun lars Tatooine feminine ## 8 R5-D4 Tatooine masculine ## 9 Biggs Darklighter Tatooine masculine ## 10 Obi-Wan Kenobi Stewjon masculine ## # ... with 77 more rows ``` -- Promjena naziva kolone bez subseting-a je moguće sa `rename` funkcijom. Probajte izvršiti gornji kod sa `rename(...)` funkcijom. --- # 3) dplyr :: select (*dalje*) <br> `select(contains(PATTERN))` opcija je jako korisna u nekim slučajevima. ```r starwars %>% select(name, contains("color")) ``` ``` ## # A tibble: 87 x 4 ## name hair_color skin_color eye_color ## <chr> <chr> <chr> <chr> ## 1 Luke Skywalker blond fair blue ## 2 C-3PO <NA> gold yellow ## 3 R2-D2 <NA> white, blue red ## 4 Darth Vader none white yellow ## 5 Leia Organa brown light brown ## 6 Owen Lars brown, grey light blue ## 7 Beru Whitesun lars brown light blue ## 8 R5-D4 <NA> white, red red ## 9 Biggs Darklighter black light brown ## 10 Obi-Wan Kenobi auburn, white fair blue-gray ## # ... with 77 more rows ``` --- # 3) dplyr :: select (*dalje*) `select(..., everything())` opcija je također korisna za sortiranje naziva kolona (i.e. stavi određenu kolonu na prvo mjesto). ```r starwars %>% select(species, homeworld, everything()) %>% head(5) ``` ``` ## # A tibble: 5 x 14 ## species homeworld name height mass hair_color skin_color eye_color ## <chr> <chr> <chr> <int> <dbl> <chr> <chr> <chr> ## 1 Human Tatooine Luke Skywalker 172 77 blond fair blue ## 2 Droid Tatooine C-3PO 167 75 <NA> gold yellow ## 3 Droid Naboo R2-D2 96 32 <NA> white, blue red ## 4 Human Tatooine Darth Vader 202 136 none white yellow ## 5 Human Alderaan Leia Organa 150 49 brown light brown ## # ... with 6 more variables: birth_year <dbl>, sex <chr>, gender <chr>, ## # films <list>, vehicles <list>, starships <list> ``` -- </br> *Note:* Nova `relocate` funkcija nudi još funkcionalnosti kod uređivanja redosljeda kolona. [Pogledaj detaljnije!](https://www.tidyverse.org/blog/2020/03/dplyr-1-0-0-select-rename-relocate/) --- # 4) dplyr :: mutate Nove kolone možete stvoriti ni iz čega ili (češće) kao transformaciju postojećih kolona. ```r starwars %>% select(name, birth_year) %>% mutate(dog_years = birth_year * 7) %>% mutate(comment = paste0(name, " is ", dog_years, " in dog years.")) ``` ``` ## # A tibble: 87 x 4 ## name birth_year dog_years comment ## <chr> <dbl> <dbl> <chr> ## 1 Luke Skywalker 19 133 Luke Skywalker is 133 in dog years. ## 2 C-3PO 112 784 C-3PO is 784 in dog years. ## 3 R2-D2 33 231 R2-D2 is 231 in dog years. ## 4 Darth Vader 41.9 293. Darth Vader is 293.3 in dog years. ## 5 Leia Organa 19 133 Leia Organa is 133 in dog years. ## 6 Owen Lars 52 364 Owen Lars is 364 in dog years. ## 7 Beru Whitesun lars 47 329 Beru Whitesun lars is 329 in dog yea~ ## 8 R5-D4 NA NA R5-D4 is NA in dog years. ## 9 Biggs Darklighter 24 168 Biggs Darklighter is 168 in dog year~ ## 10 Obi-Wan Kenobi 57 399 Obi-Wan Kenobi is 399 in dog years. ## # ... with 77 more rows ``` --- # 4) dplyr :: mutate (*dalje*) *Note:* `mutate` funkcija uvažava redosljed. Moguće je napraviti više lančanih funkcija u jednom pozivu. ```r starwars %>% select(name, birth_year) %>% mutate( dog_years = birth_year * 7, ## Separate with a comma comment = paste0(name, " is ", dog_years, " in dog years.") ) ``` ``` ## # A tibble: 87 x 4 ## name birth_year dog_years comment ## <chr> <dbl> <dbl> <chr> ## 1 Luke Skywalker 19 133 Luke Skywalker is 133 in dog years. ## 2 C-3PO 112 784 C-3PO is 784 in dog years. ## 3 R2-D2 33 231 R2-D2 is 231 in dog years. ## 4 Darth Vader 41.9 293. Darth Vader is 293.3 in dog years. ## 5 Leia Organa 19 133 Leia Organa is 133 in dog years. ## 6 Owen Lars 52 364 Owen Lars is 364 in dog years. ## 7 Beru Whitesun lars 47 329 Beru Whitesun lars is 329 in dog yea~ ## 8 R5-D4 NA NA R5-D4 is NA in dog years. ## 9 Biggs Darklighter 24 168 Biggs Darklighter is 168 in dog year~ ## 10 Obi-Wan Kenobi 57 399 Obi-Wan Kenobi is 399 in dog years. ## # ... with 77 more rows ``` --- # 4) dplyr :: mutate (*dalje*) <br> <br> Boolean, logički i kondicionalni operatori se mogu dobro kombinirati sa funkcijom `mutate`: ```r starwars %>% select(name, height) %>% filter(name %in% c("Luke Skywalker", "Anakin Skywalker")) %>% mutate(tall1 = height > 180) %>% mutate(tall2 = ifelse(height > 180, "Tall", "Short")) ## Isti rezultat;izaberi nazive ``` ``` ## # A tibble: 2 x 4 ## name height tall1 tall2 ## <chr> <int> <lgl> <chr> ## 1 Luke Skywalker 172 FALSE Short ## 2 Anakin Skywalker 188 TRUE Tall ``` --- # 4) dplyr :: mutate (*dalje*) Kombiniranje `mutate` sa `across` funkcijom omogućava jednostavan rad na selekciji varijabli. Primjerice: ```r starwars %>% select(name:eye_color) %>% * mutate(across(where(is.character), toupper)) %>% head(5) ``` ``` ## # A tibble: 5 x 6 ## name height mass hair_color skin_color eye_color ## <chr> <int> <dbl> <chr> <chr> <chr> ## 1 LUKE SKYWALKER 172 77 BLOND FAIR BLUE ## 2 C-3PO 167 75 <NA> GOLD YELLOW ## 3 R2-D2 96 32 <NA> WHITE, BLUE RED ## 4 DARTH VADER 202 136 NONE WHITE YELLOW ## 5 LEIA ORGANA 150 49 BROWN LIGHT BROWN ``` -- </br> *Note:* Ovaj workflow (i.e. kombinacija `mutate` i `across`) nadrasta stare verzije `mutate` koje ste možda koristili prije. Za više detalja pogledajte [ovdje](https://www.tidyverse.org/blog/2020/04/dplyr-1-0-0-colwise/) i [ovdje](https://dplyr.tidyverse.org/dev/articles/colwise.html). --- # 5) dplyr :: summarise Posebno korisno u kombinaciji sa `group_by` funkcijom. ```r starwars %>% group_by(species, gender) %>% summarise(mean_height = mean(height, na.rm = TRUE)) ``` ``` ## `summarise()` has grouped output by 'species'. You can override using the `.groups` argument. ``` ``` ## # A tibble: 42 x 3 ## # Groups: species [38] ## species gender mean_height ## <chr> <chr> <dbl> ## 1 Aleena masculine 79 ## 2 Besalisk masculine 198 ## 3 Cerean masculine 198 ## 4 Chagrian masculine 196 ## 5 Clawdite feminine 168 ## 6 Droid feminine 96 ## 7 Droid masculine 140 ## 8 Dug masculine 112 ## 9 Ewok masculine 88 ## 10 Geonosian masculine 183 ## # ... with 32 more rows ``` --- # 5) dplyr :: summarise (*dalje*) Uključite funkcijski argument **na.rm = TRUE*** (ili **na.rm = T**) kod `summarise` funkcije. U suprotnom će NA vrijednosti biti uključene u output :-/ ```r ## Vjerojatno nepoželjno starwars %>% summarise(mean_height = mean(height)) ``` ``` ## # A tibble: 1 x 1 ## mean_height ## <dbl> ## 1 NA ``` ```r ## Bolje starwars %>% summarise(mean_height = mean(height, na.rm = TRUE)) ``` ``` ## # A tibble: 1 x 1 ## mean_height ## <dbl> ## 1 174. ``` --- # 5) dplyr :: summarise (*dalje*) Kombinacija `across` sa `mutate` također funkcionira sa `summarise` funkcijom. Primjerice: ```r starwars %>% group_by(species) %>% * summarise(across(where(is.numeric), mean, na.rm=T)) %>% head(5) ``` ``` ## # A tibble: 5 x 4 ## species height mass birth_year ## <chr> <dbl> <dbl> <dbl> ## 1 Aleena 79 15 NaN ## 2 Besalisk 198 102 NaN ## 3 Cerean 198 82 92 ## 4 Chagrian 196 NaN NaN ## 5 Clawdite 168 55 NaN ``` -- </br> *Note:* Ova funkcionalnost nadrasta stare verzije `summarise` funkcije. Za detalje vidi [ovdje](https://www.tidyverse.org/blog/2020/04/dplyr-1-0-0-colwise/) i [ovdje](https://dplyr.tidyverse.org/dev/articles/colwise.html). --- # Ostale dplyr funkcionalnosti <br> `group_by` i `ungroup`: Za (un)grouping. - Posebno korisno sa `summarise` i `mutate` naredbama,kao što smo već vidjeli. -- `slice`: Izaberi redove prema poziciji reda. - E.g. `starwars %>% slice(c(1, 5))` -- `pull`: Izvadi kolonu iz podatkovnog skupa kao vektor ili skalar. - E.g. `starwars %>% filter(gender=="female") %>% pull(height)` -- `count` i `distinct`: Pobroji i izoliraj jedinstvene opservacije. - E.g. `starwars %>% count(species)`, ili `starwars %>% distinct(species)` - Također moguće koristiti kombinaciju `mutate`, `group_by`, i `n()`, e.g. `starwars %>% group_by(species) %>% mutate(num = n())`. --- # Ostale dplyr funkcionalnosti (dalje) <br> <br> <br> Postoji još i klasa [window funkcija](https://cran.r-project.org/web/packages/dplyr/vignettes/window-functions.html) za stvaranje lead-ova i lag-ova, rengiranje, stvaranje kumulativnih agregata, etc. - Vidi `vignette("window-functions")`. -- </br> Zadnja skupina dodatnih dplyr funkcionalnosti je familija `join` funkcija. Riječ je o jako bitnim funkcijama pa ćemo pogledati njihove mogućnosti... - Ove funkcije ćemo sretati često na kolegiju. --- # Joining operacije Jedna od glavnih funkcionalnosti `dplyr`-a je mogućnost spajanja podataka [join](https://cran.r-project.org/web/packages/dplyr/vignettes/two-table.html). - `inner_join(df1, df2)` - `left_join(df1, df2)` - `right_join(df1, df2)` - `full_join(df1, df2)` - `semi_join(df1, df2)` - `anti_join(df1, df2)` (Vizualni pregled operacija spajanja pogledajte [ovdje](https://r4ds.had.co.nz/relational-data.html).) -- Za sljedeće primjere su nam potrebni podatci iz [**nycflights13**](http://github.com/hadley/nycflights13) paketa. - Učitajte paket i pregledajte podatke. ```r library(nycflights13) flights planes ``` --- # Joining operacije (dalje) Izvedimo [left join](https://stat545.com/bit001_dplyr-cheatsheet.html#left_joinsuperheroes-publishers) na `flights` i `planes` podatkovnim sklupovima. - *Note*: Kolone ćemo subsetirati nakon spajanja, ali zadržavamo tekst sa strane. -- ```r left_join(flights, planes) %>% select(year, month, day, dep_time, arr_time, carrier, flight, tailnum, type, model) ``` ``` ## Joining, by = c("year", "tailnum") ``` ``` ## # A tibble: 336,776 x 10 ## year month day dep_time arr_time carrier flight tailnum type model ## <int> <int> <int> <int> <int> <chr> <int> <chr> <chr> <chr> ## 1 2013 1 1 517 830 UA 1545 N14228 <NA> <NA> ## 2 2013 1 1 533 850 UA 1714 N24211 <NA> <NA> ## 3 2013 1 1 542 923 AA 1141 N619AA <NA> <NA> ## 4 2013 1 1 544 1004 B6 725 N804JB <NA> <NA> ## 5 2013 1 1 554 812 DL 461 N668DN <NA> <NA> ## 6 2013 1 1 554 740 UA 1696 N39463 <NA> <NA> ## 7 2013 1 1 555 913 B6 507 N516JB <NA> <NA> ## 8 2013 1 1 557 709 EV 5708 N829AS <NA> <NA> ## 9 2013 1 1 557 838 B6 79 N593JB <NA> <NA> ## 10 2013 1 1 558 753 AA 301 N3ALAA <NA> <NA> ## # ... with 336,766 more rows ``` --- # Joining operacije (dalje) <br> `dplyr` je napravio razumnu pretpostavku na kojim kolonama će izvršiti spajanje (i.e. kolone sa istim nazivom). Također smo dobili obavjest: ``` *## Joining, by = c("year", "tailnum") ``` Ipak, ovdje se javlja očiti problem: varijabla `year` nema konzistentno značenje u skupovima podataka koje spajamo! - U jednom se odnosi na *year of flight*, a u drugom na *year of construction*. -- Postoji jednostavan način izbjegavanja ovog problema. - Probajte razmisliti koji!? <br> - Isprobajte `?dplyr::join`. --- # Joining operacije (dalje) Potrebna je eksplicitnost u funkcijskom pozivu sa `by = ` argumentom. - Promjena naziva kolona je drugo legitimno rješenje. ```r left_join( flights, planes %>% rename(year_built = year), ## Nije nužno ali pomaže by = "tailnum" ## Eksplicitnost ) %>% select(year, month, day, dep_time, arr_time, carrier, flight, tailnum, year_built, type, model) %>% head(3) ## Preglednost ``` ``` ## # A tibble: 3 x 11 ## year month day dep_time arr_time carrier flight tailnum year_built type ## <int> <int> <int> <int> <int> <chr> <int> <chr> <int> <chr> ## 1 2013 1 1 517 830 UA 1545 N14228 1999 Fixed w~ ## 2 2013 1 1 533 850 UA 1714 N24211 1998 Fixed w~ ## 3 2013 1 1 542 923 AA 1141 N619AA 1990 Fixed w~ ## # ... with 1 more variable: model <chr> ``` --- # Joining operacije (dalje) <br> Što ako specificiramo kolonu `by` argmentom bez prethodne promjene naziva kolone. ```r left_join( flights, planes, ## Bez promjene naziva by = "tailnum" ) %>% select(contains("year"), month, day, dep_time, arr_time, carrier, flight, tailnum, type, model) %>% head(3) ``` ``` ## # A tibble: 3 x 11 ## year.x year.y month day dep_time arr_time carrier flight tailnum type model ## <int> <int> <int> <int> <int> <int> <chr> <int> <chr> <chr> <chr> ## 1 2013 1999 1 1 517 830 UA 1545 N14228 Fixe~ 737-~ ## 2 2013 1998 1 1 533 850 UA 1714 N24211 Fixe~ 737-~ ## 3 2013 1990 1 1 542 923 AA 1141 N619AA Fixe~ 757-~ ``` -- Provjerite što su `year.x` i `year.y`. Eksplicitnost pomaže! --- class: inverse, center, middle name: tidyr # tidyr <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Nezaobilazne funkcionalnosti...) --- # Ključne tidyr riječi 1. `pivot_longer`: Pivot "wide" podatke u "long" format (i.e. "melt").<sup>1</sup> 2. `pivot_wider`: Pivot "long" podatke u "wide" format (i.e. "cast").<sup>2</sup> 3. `separate`: Razdvoji (i.e. split) jednu kolonu u više njih. 4. `unite`: Ujedini (i.e. combine) Više kolona u jednu. .footnote[ <sup>1</sup> Updated verzija `tidyr::gather`. <sup>2</sup> Updated verzija `tidyr::spread`. ] -- </br> Praktični primjeri... - Pitanje: Koja funkcija `pivot_longer` ili `pivot_wider` stvara *tidy* podatke? --- # 1) tidyr :: pivot_longer ```r stocks <- data.frame( ## Možete koristiti i "tibble" umjesto "data.frame" time = as.Date('2009-01-01') + 0:1, X = rnorm(2, 0, 1), Y = rnorm(2, 0, 2), Z = rnorm(2, 0, 4) ) stocks ``` ``` ## time X Y Z ## 1 2009-01-01 -2.113870 4.23257259 -3.125758 ## 2 2009-01-02 2.265361 -0.01647141 4.164161 ``` ```r stocks %>% pivot_longer(-time, names_to="stock", values_to="price") ``` ``` ## # A tibble: 6 x 3 ## time stock price ## <date> <chr> <dbl> ## 1 2009-01-01 X -2.11 ## 2 2009-01-01 Y 4.23 ## 3 2009-01-01 Z -3.13 ## 4 2009-01-02 X 2.27 ## 5 2009-01-02 Y -0.0165 ## 6 2009-01-02 Z 4.16 ``` --- # 1) tidyr :: pivot_longe (*dalje*) <br> <br> <br> <br> Spremi `tidy stocks` podatkovni okvir u *long* formatu za sljedeći slide. ```r ## Specificirajte nazive argumenata: i.e. "names_to=" i "values_to=" tidy_stocks <- stocks %>% pivot_longer(-time, names_to="stock", values_to="price") ``` --- # 2) tidyr :: pivot_wider ```r tidy_stocks %>% pivot_wider(names_from=stock, values_from=price) ``` ``` ## # A tibble: 2 x 4 ## time X Y Z ## <date> <dbl> <dbl> <dbl> ## 1 2009-01-01 -2.11 4.23 -3.13 ## 2 2009-01-02 2.27 -0.0165 4.16 ``` ```r tidy_stocks %>% pivot_wider(names_from=time, values_from=price) ``` ``` ## # A tibble: 3 x 3 ## stock `2009-01-01` `2009-01-02` ## <chr> <dbl> <dbl> ## 1 X -2.11 2.27 ## 2 Y 4.23 -0.0165 ## 3 Z -3.13 4.16 ``` -- </br> Drugi primjer — koji je iskombinirao različite pivoting argumente — je uspješno transponirao podatke. --- # Dodatno: Zapamtite pivot_* sintaksu <br> <br> <br> <br> Za one koji se (još) uvijek sjećaju *Stata*-ine "reshape" naredbe...([Exhibit A](https://twitter.com/scottimberman/status/1036801308785864704).) Ista situacija je lako zamisliva i sa `pivot_*` funkcijama. Prijedlog je zapamtiti redosljed funkcijskih argumenata: prvo *"names"*, potom *"values"*. --- # 3) tidyr :: separate ```r economists <- data.frame(name = c("Adam.Smith", "Paul.Samuelson", "Milton.Friedman")) economists ``` ``` ## name ## 1 Adam.Smith ## 2 Paul.Samuelson ## 3 Milton.Friedman ``` ```r economists %>% separate(name, c("first_name", "last_name")) ``` ``` ## first_name last_name ## 1 Adam Smith ## 2 Paul Samuelson ## 3 Milton Friedman ``` -- </br> Ovo je "pametna" funkcija. Da bi se izbjegla dvosmislenost, definirajte separator eskplicitno `separate(..., sep=".")`. --- # 3) tidyr::separate (*dalje*) Povezana funkcija je`separate_rows`i služi za razdvajanje ćelija koje sadrže više opservacija (frustrirajuća stvar kod npr. "survey" podataka). ```r jobs <- data.frame( name = c("Jack", "Jill"), occupation = c("Homemaker", "Philosopher, Philanthropist, Troublemaker") ) jobs ``` ``` ## name occupation ## 1 Jack Homemaker ## 2 Jill Philosopher, Philanthropist, Troublemaker ``` ```r ## Razdvoji Jill's različita zanimanja u više redova jobs %>% separate_rows(occupation) ``` ``` ## # A tibble: 4 x 2 ## name occupation ## <chr> <chr> ## 1 Jack Homemaker ## 2 Jill Philosopher ## 3 Jill Philanthropist ## 4 Jill Troublemaker ``` --- # 4) tidyr :: unite ```r gdp <- data.frame( yr = rep(2016, times = 4), mnth = rep(1, times = 4), dy = 1:4, gdp = rnorm(4, mean = 100, sd = 2) ) gdp ``` ``` ## yr mnth dy gdp ## 1 2016 1 1 98.79394 ## 2 2016 1 2 97.86655 ## 3 2016 1 3 101.85722 ## 4 2016 1 4 102.07900 ``` ```r ## Kombiniraj "yr", "mnth", and "dy" u jednu "date" kolonu gdp %>% unite(date, c("yr", "mnth", "dy"), sep = "-") ``` ``` ## date gdp ## 1 2016-1-1 98.79394 ## 2 2016-1-2 97.86655 ## 3 2016-1-3 101.85722 ## 4 2016-1-4 102.07900 ``` --- # 4) tidyr::unite (*dalje*) <br> <br> `unite` funkcija će automatski stvoriti karakternu varijablu. To jasnije dolazi do izražaja ako pretvorimo u objekt `tibble.` ```r gdp_u <- gdp %>% unite(date, c("yr", "mnth", "dy"), sep = "-") %>% as_tibble() gdp_u ``` ``` ## # A tibble: 4 x 2 ## date gdp ## <chr> <dbl> ## 1 2016-1-1 98.8 ## 2 2016-1-2 97.9 ## 3 2016-1-3 102. ## 4 2016-1-4 102. ``` -- Za modifikaciju u nešto drugo (e.g. date ili numeric) je moguće koristiti `mutate`. Vidi primjer sa [lubridate](https://lubridate.tidyverse.org/) paketom za rad sa datumima na sljedećem slide-u. --- # 4) tidyr::unite (*dalje*) <br> <br> <br> ```r library(lubridate) gdp_u %>% mutate(date = ymd(date)) ``` ``` ## # A tibble: 4 x 2 ## date gdp ## <date> <dbl> ## 1 2016-01-01 98.8 ## 2 2016-01-02 97.9 ## 3 2016-01-03 102. ## 4 2016-01-04 102. ``` --- # Ostale tidyr funkcionalnosti Koristite `crossing` za kombinaciju grupe varijabli.<sup>1</sup> ```r crossing(side=c("left", "right"), height=c("top", "bottom")) ``` ``` ## # A tibble: 4 x 2 ## side height ## <chr> <chr> ## 1 left bottom ## 2 left top ## 3 right bottom ## 4 right top ``` .footnote[ <sup>1</sup> Base Ralternativa: `expand.grid`. ] -- Pogledajte `?expand` i `?complete` za specijalizirane funkcije koje omogućuju (implicitno) rad sa nedostajućim podatcima ili kombiniranjem varijabli u podatkovnim okvirima. - Prije ili kasnije možete očekivati ovu potrebu za ovom funkcijom! --- class: inverse, center, middle name: summary # Sažetak <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Što smo naučili!?) --- # Ključne funkcije ### dplyr 1. `filter` 2. `arrange` 3. `select` 4. `mutate` 5. `summarise` ### tidyr 1. `pivot_longer` 2. `pivot_wider` 3. `separate` 4. `unite` -- Drugi bitni elementi: pipe-ovi (`%>%`), grupiranje (`group_by`),funkcije za spajanje (`left_join`, `inner_join`, etc.). --- class: inverse, center, middle # Hvala na pozornosti! <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Sljedeće predavanje: **data.table**)