Leo Tolstoy: Sve srećne porodice liče jedna na drugu, svaka nesrećna porodica, nesrećna je na svoj način.
Hadley Wickham: Sve uredne baze podataka liče jedna na drugu, svaka neuredna baza, neuredna je na svoj način.
U ovom poglavlju ćemo se pozabaviti time kako da organizujemo podatke u R-u da budu “uredni”. Dobijanje podataka u ovom formatu zahteva dodatni posao, ali se dugoročno isplati. Jednom kada imamo uredne podatke i uredne alate koje obezbeđuju paketi iz tidyverse
, potrošićemo mnogo manje vremena prevodeći podatke iz jedne reprezentacije u drugu, što će nam omogućiti da potrošimo više vremena na analitička pitanja.
Ovo poglavlje će nam dati praktičan uvod u uređivanje podataka i paket tidyr
, paket koji pruža hrpu alata koji pomažu u uređivanju naših neurednih skupova podataka. Paket tidyr
je deo klase tidyverse
.
library(tidyverse)
library(tidyr)
Možemo predstaviti iste podatke na više različitih načina. Primer ispod pokazuje iste podatke organizovane na četiri različita načina. Svaka baza podataka prikazuje iste vrednosti četiri promenljive: country
, year
, population
i cases
, ali svaka baza organizuje vrednosti na drugačiji način.
table1
## # A tibble: 6 x 4
## country year cases population
## <chr> <int> <int> <int>
## 1 Afghanistan 1999 745 19987071
## 2 Afghanistan 2000 2666 20595360
## 3 Brazil 1999 37737 172006362
## 4 Brazil 2000 80488 174504898
## 5 China 1999 212258 1272915272
## 6 China 2000 213766 1280428583
table2
## # A tibble: 12 x 4
## country year type count
## <chr> <int> <chr> <int>
## 1 Afghanistan 1999 cases 745
## 2 Afghanistan 1999 population 19987071
## 3 Afghanistan 2000 cases 2666
## 4 Afghanistan 2000 population 20595360
## 5 Brazil 1999 cases 37737
## 6 Brazil 1999 population 172006362
## 7 Brazil 2000 cases 80488
## 8 Brazil 2000 population 174504898
## 9 China 1999 cases 212258
## 10 China 1999 population 1272915272
## 11 China 2000 cases 213766
## 12 China 2000 population 1280428583
table3
## # A tibble: 6 x 3
## country year rate
## * <chr> <int> <chr>
## 1 Afghanistan 1999 745/19987071
## 2 Afghanistan 2000 2666/20595360
## 3 Brazil 1999 37737/172006362
## 4 Brazil 2000 80488/174504898
## 5 China 1999 212258/1272915272
## 6 China 2000 213766/1280428583
# Razdvojimo na 2 tibla
# cases
table4a
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 745 2666
## 2 Brazil 37737 80488
## 3 China 212258 213766
#population
table4b
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 19987071 20595360
## 2 Brazil 172006362 174504898
## 3 China 1272915272 1280428583
Ovo su sve reprezentacije istih podataka, ali nisu sve jednako jednostavne za upotrebu. Jedna baza, uredna baza, biće mnogo lakša za rad u tidyverse
.
Postoje tri međusobno povezana pravila koja čine skup podataka urednim:
Svaka promenljiva mora da ima svoju kolonu.
Svaka opservacija mora da ima svoj red.
Svaka vrednost mora da ima svoju ćeliju.
Ova tri pravila su međusobno povezana jer je nemoguće zadovoljiti samo dva od tri. Taj međusobni odnos dovodi do jednostavnog niza praktičnih instrukcija:
Smestimo svaku bazu podataka u tibl.
Smestimo svaku promenljivu u kolonu.
U ovom primeru, samo table1
je uredna. To je jedina reprezentacija u kojoj svaka kolona predstavlja promenljivu.
Zašto želimo da osiguramo da su naši podaci uredni? Postoje dve glavne prednosti:
Postoji opšta prednost odabira jednog konzistentnog načina skladištenja podataka. Ako imamo konzistentnu strukturu podataka, lakše je naučiti alate koje rade sa njima, jer imaju istu uniformnost.
Postoji posebna prednost postavljanja promenljivih u kolone, jer dozvoljava vektorizovanoj prirodi R-a da zablista. Većina ugrađenih R funkcija radi sa vektorima vrednosti, pa to čini transformacije urednih podataka posebno prirodnim.
dplyr
, ggplot2
i svi drugi paketi u tidyverse
su dizajnirani da rade sa urednim podacima. Na primer, na table1
možemo primeniti dobro poznate funkcije:
table1 %>%
mutate(rate = cases / population)
## # A tibble: 6 x 5
## country year cases population rate
## <chr> <int> <int> <int> <dbl>
## 1 Afghanistan 1999 745 19987071 0.0000373
## 2 Afghanistan 2000 2666 20595360 0.000129
## 3 Brazil 1999 37737 172006362 0.000219
## 4 Brazil 2000 80488 174504898 0.000461
## 5 China 1999 212258 1272915272 0.000167
## 6 China 2000 213766 1280428583 0.000167
table1 %>%
count(year, wt = cases)
## # A tibble: 2 x 2
## year n
## <int> <int>
## 1 1999 250740
## 2 2000 296920
library(ggplot2)
ggplot(table1, aes(year, cases)) +
geom_line(aes(group = country), colour = "grey50") +
geom_point(aes(colour = country))
Principi urednih podataka izgledaju tako jednostavni da se možemo zapitati da li ćemo ikada naići na skup podataka koji nije uredan. Međutim, većina podataka na koje ćemo naići, nažalost, nije uredna. Postoje dva glavna razloga:
Većina ljudi nije upoznata sa principima urednih podataka.
Podaci se često organizuju kako bi se olakšala neka druga upotreba koja nije analiza. Na primer, podaci se često organizuju kako bi unos bio lakši.
To znači da ćemo za većinu realnih analiza, morati da uradimo malo uređivanja. Prvi korak je uvek utvrditi šta su promenljive i opservacije. Ponekad je to lako, a ponekad ćemo morati da se konsultujemo sa ljudima koji su izvorno generisali podatke. Drugi korak je rešavanje jednog od dva uobičajena problema:
Jedna promenljiva može biti raspoređena na više kolona.
Jedna opservacija može biti raštrkana na više redova.
Obično će baza patiti samo od jednog od ova dva problema, a patiće od oba ako zaista nemamo sreće. Da bismo rešili ove probleme, biće nam potrebne dve najvažnije funkcije u tidyr
: gather()
i spread()
.
Čest problem je baza podataka gde neka imena kolona nisu imena promenljivih, već vrednosti promenljive. Uzmimo table4a
: nazivi kolona 1999
i 2000
predstavljaju vrednosti promenljive year
, i svaki red predstavlja dve opservacije, ne jednu.
table4a
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 745 2666
## 2 Brazil 37737 80488
## 3 China 212258 213766
Da bismo uredili ovakav skup podataka, potrebno je da skupimo te kolone u novi par promenljivih. Da bismo opisali tu operaciju, trebaju nam tri parametra:
Skup kolona koje predstavljaju vrednosti, a ne promenljive. U ovom primeru, to su kolone 1999
i 2000
.
Ime promenljive čije vrednosti formiraju imena kolona. Zovemo je ključem (key
), a ovde je to year
.
Ime promenljive čije su vrednosti raspoređene po ćelijama. Zovemo je value
, a ovde je to cases
.
Zajedno, ovi parametri generišu poziv za gather()
:
table4a %>%
gather(`1999`, `2000`, key = "year", value = "cases")
## # A tibble: 6 x 3
## country year cases
## <chr> <chr> <int>
## 1 Afghanistan 1999 745
## 2 Brazil 1999 37737
## 3 China 1999 212258
## 4 Afghanistan 2000 2666
## 5 Brazil 2000 80488
## 6 China 2000 213766
Kolone za skupljanje se specifikuju dplyr::select()
stilom notacije. Ovde su samo dve kolone, tako da ih navodimo pojedinačno. Primetimo da su 1999
i 2000
nesintaksna imena (jer ne počinju slovom), pa ih moramo okružiti navodnicima (`
).
U konačnom rezultatu se ne nalaze skupljene kolone, ali dobijamo nove key
i value
kolone. Odnosi između originalnih promenljivih su sačuvani. Vizuelno, to je prikazano na sledećoj slici:
Koristimo gather()
da uredimo table4b
u sličnom maniru. Jedina razlika je promenljiva smeštena u value
ćelijama:
table4b %>%
gather(`1999`, `2000`, key = "year", value = "population")
## # A tibble: 6 x 3
## country year population
## <chr> <chr> <int>
## 1 Afghanistan 1999 19987071
## 2 Brazil 1999 172006362
## 3 China 1999 1272915272
## 4 Afghanistan 2000 20595360
## 5 Brazil 2000 174504898
## 6 China 2000 1280428583
Da bismo kombinovali uređene verzije table4a
i table4b
u jedan tibl, koristimo dplyr::left_join()
, o čemu ćemo malo više pričati kasnije.
tidy4a = table4a %>%
gather(`1999`, `2000`, key = "year", value = "cases")
tidy4b = table4b %>%
gather(`1999`, `2000`, key = "year", value = "population")
left_join(tidy4a, tidy4b)
## Joining, by = c("country", "year")
## # A tibble: 6 x 4
## country year cases population
## <chr> <chr> <int> <int>
## 1 Afghanistan 1999 745 19987071
## 2 Brazil 1999 37737 172006362
## 3 China 1999 212258 1272915272
## 4 Afghanistan 2000 2666 20595360
## 5 Brazil 2000 80488 174504898
## 6 China 2000 213766 1280428583
Širenje je suprotno od skupljanja - koristimo ga kada su opservacije razbacane na više redova. Na primer, uzmimo table2
: svaka opservacija se prostire na dva reda.
table2
## # A tibble: 12 x 4
## country year type count
## <chr> <int> <chr> <int>
## 1 Afghanistan 1999 cases 745
## 2 Afghanistan 1999 population 19987071
## 3 Afghanistan 2000 cases 2666
## 4 Afghanistan 2000 population 20595360
## 5 Brazil 1999 cases 37737
## 6 Brazil 1999 population 172006362
## 7 Brazil 2000 cases 80488
## 8 Brazil 2000 population 174504898
## 9 China 1999 cases 212258
## 10 China 1999 population 1272915272
## 11 China 2000 cases 213766
## 12 China 2000 population 1280428583
Da bismo ovo sredili, prvo analiziramo reprezentaciju na sličan način kao i za gather()
. Ovog puta, međutim, potrebna su nam samo dva parametra:
Kolona koja sadrži imena promenljivih - key
kolona. Ovde, to je type
.
Kolona koja sadrži vrednosti iz više promenljivih, kolona value
. Ovde je to count
.
Sada možemo koristiti spread()
, kao što je prikazano programski ispod, a vizuelno i na slici dole.
table2 %>%
spread(key = type, value = count)
## # A tibble: 6 x 4
## country year cases population
## <chr> <int> <int> <int>
## 1 Afghanistan 1999 745 19987071
## 2 Afghanistan 2000 2666 20595360
## 3 Brazil 1999 37737 172006362
## 4 Brazil 2000 80488 174504898
## 5 China 1999 212258 1272915272
## 6 China 2000 213766 1280428583
Kao što vidimo iz upotrebe key
i value
argumenata, spread()
i gather()
su komplementarne. gather()
pravi široke tabele užim i dužim, a spread()
pravi duge tabele kraćim i širim.