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 1. [Set-up](#prologue) 2. [Tidyverse osnove](#basics) 3. [Manipulacija podatcima sa dplyr](#dplyr) 4. [Manipulacija podatcima sa tidyr](#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? Resursi: - [Vignette](https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html) (iz **tidyr** paketa) - [Č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 ☑ Instaliran [**tidyverse**](https://www.tidyverse.org/) paket. ☑ 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 (ili barem rano). - Dokumentacija i podrška su izvrsni. - Konzistentna filozofija i sintaksa što 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 nemogu napraviti u tidyverse-u. - Kombinacija tidyverse i base R je često rješenje. --- # Tidyverse vs. base R (dalje) Često postoje ekvivalenti izmedju base R i tidyverse. Ovo se generalno odražava u pravili `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 često nude neka poboljšanja ili druge korisne opcije (ponekad i restrikcije) u odnosu na base R. - Zapamtite: Uvijek postoji mnoštvo načina da se nešto izvede u R. --- # Tidyverse paketi Učitajte tidyverse meta-package i provjerite output. ```r library(tidyverse) ``` ``` ## -- Attaching packages ---------------------------------------------- tidyverse 1.3.0 -- ``` ``` ## <U+221A> ggplot2 3.3.2 <U+221A> purrr 0.3.4 ## <U+221A> tibble 3.0.3 <U+221A> dplyr 1.0.2 ## <U+221A> tidyr 1.1.2 <U+221A> stringr 1.4.0 ## <U+221A> readr 1.3.1 <U+221A> forcats 0.5.0 ``` ``` ## -- 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 vezrijama 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 sa više paketa nego što se automatski učitava.<sup>1</sup> ```r tidyverse_packages() ``` ``` ## [1] "broom" "cli" "crayon" "dbplyr" "dplyr" ## [6] "forcats" "ggplot2" "haven" "hms" "httr" ## [11] "jsonlite" "lubridate" "magrittr" "modelr" "pillar" ## [16] "purrr" "readr" "readxl" "reprex" "rlang" ## [21] "rstudioapi" "rvest" "stringr" "tibble" "tidyr" ## [26] "xml2" "tidyverse" ``` Neke od tih dodatnih paketa ćemo koristiti u okviru kolegija. — Npr. **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) Cilj je izložiti 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 (uz **ggplot2**). - Na čišćenje i manipulaciju podatcima odlazi jako puno vremena u radu sa podatcima. --- # Dodatak o pipe-ovima: %>% U R-u, pipe operator se označava `%>%` i automatski se učitava 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)) 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 ovo (group by), etc. Druga linija koda ima inverznu intuiciju (zadnja operacija dolazi prva!) - Tko želi čitati stvari iznutra-van? --- # Dodatak o pipe-ovima: %>% Pipe verzija koda je još čitljivija ako se napiše kroz nekoliko redova: ```r mpg %>% filter(manufacturer=="audi") %>% group_by(model) %>% summarise(hwy_mean = mean(hwy)) ``` ``` ## `summarise()` ungrouping output (override with `.groups` argument) ``` ``` ## # A tibble: 3 x 2 ## model hwy_mean ## <chr> <dbl> ## 1 a4 28.3 ## 2 a4 quattro 25.8 ## 3 a6 quattro 24 ``` Zapamtite: 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 ako ž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> (Workhorse!) --- # Dodatno: dplyr 1.0.0 verzija 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. Utrenutku pisanja ovih, aktualna verzija je 1.0.2. - Provjerite da li imate barem **dplyr** 1.0.0. ```r packageVersion('dplyr') ``` ``` ## [1] '1.0.2' ``` ```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 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 sa dplyr paketom. --- # 1) dplyr::filter Moguće je koristiti više filter naredbi sa pipe (`%>%`) operatorom ili ih odvojiti unutar zagrade zarezom. ```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 Dart~ 202 136 none white yellow 41.9 male mascu~ ## 2 Qui-~ 193 89 brown fair blue 92 male mascu~ ## 3 Dooku 193 80 white fair brown 102 male mascu~ ## 4 Bail~ 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*) Regularni izrazi također funkcioniraju. ```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~ 172 77 blond fair blue 19 male mascu~ ## 2 Anak~ 188 84 blond fair blue 41.9 male mascu~ ## 3 Shmi~ 163 NA black fair brown 72 fema~ femin~ ## # ... with 5 more variables: homeworld <chr>, species <chr>, films <list>, ## # vehicles <list>, starships <list> ``` --- # 1) dplyr::filter (*dalje*) `Filter` se često koristi za identifikaciju (ili midanje) nedostajećih 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 Arve~ 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 fema~ femin~ ## 4 Poe ~ NA NA brown light brown NA male mascu~ ## 5 BB8 NA NA none none black NA none mascu~ ## 6 Capt~ NA NA unknown unknown unknown NA <NA> <NA> ## # ... with 5 more variables: homeworld <chr>, species <chr>, films <list>, ## # vehicles <list>, starships <list> ``` -- </br> Za micanje nedostajećih opservacija je moguće koristiti negaciju: `filter(!is.na(height))`. Isprobajte! --- # 2) dplyr::arrange ```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 Wick~ 88 20 brown brown brown 8 male mascu~ ## 2 IG-88 200 140 none metal red 15 none mascu~ ## 3 Luke~ 172 77 blond fair blue 19 male mascu~ ## 4 Leia~ 150 49 brown light brown 19 fema~ femin~ ## 5 Wedg~ 170 77 brown fair hazel 21 male mascu~ ## 6 Plo ~ 188 80 none orange black 22 male mascu~ ## 7 Bigg~ 183 84 black light brown 24 male mascu~ ## 8 Han ~ 180 80 brown fair brown 29 male mascu~ ## 9 Land~ 177 79 black dark brown 31 male mascu~ ## 10 Boba~ 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 pdajuć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 Jabb~ 175 1358 <NA> green-tan~ orange 600 herm~ mascu~ ## 3 Chew~ 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-~ 193 89 brown fair blue 92 male mascu~ ## 7 Ki-A~ 198 82 white pale yellow 92 male mascu~ ## 8 Fini~ 170 NA blond fair blue 91 male mascu~ ## 9 Palp~ 170 75 grey pale yellow 82 male mascu~ ## 10 Clie~ 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*) `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 ukoliko želite sortirati nazive kolona (i.e. staviti neke 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~ 172 77 blond fair blue ## 2 Droid Tatooine C-3PO 167 75 <NA> gold yellow ## 3 Droid Naboo R2-D2 96 32 <NA> white, bl~ red ## 4 Human Tatooine Dart~ 202 136 none white yellow ## 5 Human Alderaan Leia~ 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 je dostupna u dplyr 1.0.0 i 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*) Boolean, logički i kondicionalni operatori se mogu dobro kombinirati sa `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 novom `across` funkcijom u dplyr 1.0.0+ 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 "scoped" 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()` regrouping output by 'species' (override with `.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` funkcija. U suprotnom će nedostajeće 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*) `across` pristup koji smo vidjeli sa `mutate` maloprije također funkcionira sa `summarise` funkcijom. Primjerice: ```r starwars %>% group_by(species) %>% * summarise(across(where(is.numeric), mean, na.rm=T)) %>% head(5) ``` ``` ## `summarise()` ungrouping output (override with `.groups` argument) ``` ``` ## # 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 "scoped" verzije `summarise` funkcije koje prethode dplyr 1.0.0. 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 `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) 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 do kraja kolegija. --- # Joining operacije Jedna od glavnih funkcionalnosti dplyr-a je mogućnost spajanja podataka [(join operacija)](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. ``` ## Warning: package 'nycflights13' was built under R version 4.0.3 ``` ```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) 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 konzitentno 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 sami! - 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 Fixe~ ## 2 2013 1 1 533 850 UA 1714 N24211 1998 Fixe~ ## 3 2013 1 1 542 923 AA 1141 N619AA 1990 Fixe~ ## # ... with 1 more variable: model <chr> ``` --- # Joining operacije (dalje) Š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 0.4589863 0.3873062 -1.488758 ## 2 2009-01-02 -1.0788836 0.9977688 -5.923353 ``` ```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 0.459 ## 2 2009-01-01 Y 0.387 ## 3 2009-01-01 Z -1.49 ## 4 2009-01-02 X -1.08 ## 5 2009-01-02 Y 0.998 ## 6 2009-01-02 Z -5.92 ``` --- # 1) tidyr::pivot_longe (*dalje*) Spremi "tidy" (i.e. long) stocks podatkovni okvir 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 0.459 0.387 -1.49 ## 2 2009-01-02 -1.08 0.998 -5.92 ``` ```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 0.459 -1.08 ## 2 Y 0.387 0.998 ## 3 Z -1.49 -5.92 ``` -- </br> Drugi primjer — koji je iskombinirao različite pivoting argumente — je uspješno transponirao podatke. --- # Dodatno: Zapamtite pivot_* sintaksu Za one koji se (još) uvijek sijeć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`, 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 99.45964 ## 2 2016 1 2 98.82410 ## 3 2016 1 3 102.29727 ## 4 2016 1 4 101.60354 ``` ```r ## Kombiniraj "yr", "mnth", and "dy" u jednu "date" kolonu gdp %>% unite(date, c("yr", "mnth", "dy"), sep = "-") ``` ``` ## date gdp ## 1 2016-1-1 99.45964 ## 2 2016-1-2 98.82410 ## 3 2016-1-3 102.29727 ## 4 2016-1-4 101.60354 ``` --- # 4) tidyr::unite (*dalje*) `unite` će automatski stvoriti karakternu varijablu. To jasnije dolazi do izražaja ako pretvorimo u 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 99.5 ## 2 2016-1-2 98.8 ## 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*) ```r library(lubridate) gdp_u %>% mutate(date = ymd(date)) ``` ``` ## # A tibble: 4 x 2 ## date gdp ## <date> <dbl> ## 1 2016-01-01 99.5 ## 2 2016-01-02 98.8 ## 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 (imlicitno) 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 # Sljedeće predavanje: Web Scraping <html><div style='float:left'></div><hr color='#EB811B' size=1px width=796px></html> (Prije toga također pogledajte **data.table**)