R paket tidyr i njegove nove funkcije pivot_longer i pivot_wider

Paket tidyr uključeno u jezgro jedne od najpopularnijih biblioteka na R jeziku - tidyverse.
Glavna svrha paketa je da dovede podatke u tačan oblik.

Već dostupno na Habréu objavljivanje posvećen ovom paketu, ali datira iz 2015. godine. I želim da vam kažem o najaktuelnijim promenama koje je pre nekoliko dana najavio njen autor, Hedli Vikam.

R paket tidyr i njegove nove funkcije pivot_longer i pivot_wider

SJK: Hoće li gather() i spread() biti zastarjeli?

Hadley Wickham: Donekle. Više nećemo preporučivati ​​korištenje ovih funkcija i ispravljati greške u njima, ali će one i dalje biti prisutne u paketu u svom trenutnom stanju.

Sadržaj

Ako ste zainteresovani za analizu podataka, možda će vas zanimati moja telegram и youtube kanala. Većina sadržaja je posvećena R jeziku.

Koncept TidyData

Cilj tidyr — pomoći vam da dovedete podatke u takozvani uredan oblik. Uredni podaci su podaci gdje:

  • Svaka varijabla je u stupcu.
  • Svako zapažanje je niz.
  • Svaka vrijednost je ćelija.

Mnogo je lakše i praktičnije raditi sa podacima koji se prikazuju u urednim podacima prilikom provođenja analize.

Glavne funkcije uključene u tidyr paket

tidyr sadrži skup funkcija dizajniranih za transformaciju tablica:

  • fill() — popunjavanje nedostajućih vrijednosti u koloni prethodnim vrijednostima;
  • separate() — dijeli jedno polje na nekoliko pomoću separatora;
  • unite() — obavlja operaciju spajanja nekoliko polja u jedno, inverzno djelovanje funkcije separate();
  • pivot_longer() — funkcija koja pretvara podatke iz širokog formata u dugi format;
  • pivot_wider() - funkcija koja pretvara podatke iz dugog formata u široki format. Obrnuta operacija od one koju obavlja funkcija pivot_longer().
  • gather()zastarjelo — funkcija koja pretvara podatke iz širokog formata u dugi format;
  • spread()zastarjelo - funkcija koja pretvara podatke iz dugog formata u široki format. Obrnuta operacija od one koju obavlja funkcija gather().

Novi koncept za pretvaranje podataka iz širokog u dugi format i obrnuto

Ranije su se funkcije koristile za ovu vrstu transformacije gather() и spread(). Tokom godina postojanja ovih funkcija postalo je očigledno da za većinu korisnika, uključujući i autora paketa, nazivi ovih funkcija i njihovi argumenti nisu bili sasvim očigledni, što je izazvalo poteškoće u njihovom pronalaženju i razumijevanju koje od ovih funkcija pretvara okvir datuma od širokog do dugog formata, i obrnuto.

S tim u vezi, u tidyr Dodane su dvije nove, važne funkcije koje su dizajnirane za transformaciju okvira datuma.

Nove funkcije pivot_longer() и pivot_wider() inspirisani nekim karakteristikama u paketu cdata, koju su kreirali John Mount i Nina Zumel.

Instaliranje najnovije verzije tidyr 0.8.3.9000

Da instalirate novu, najnoviju verziju paketa tidyr 0.8.3.9000, gdje su dostupne nove funkcije, koristite sljedeći kod.

devtools::install_github("tidyverse/tidyr")

U vrijeme pisanja ove funkcije su dostupne samo u dev verziji paketa na GitHubu.

Prelazak na nove funkcije

Zapravo, nije teško prenijeti stare skripte za rad s novim funkcijama; radi boljeg razumijevanja, uzet ću primjer iz dokumentacije starih funkcija i pokazati kako se iste operacije izvode pomoću novih pivot_*() funkcije.

Pretvorite široki format u dugi format.

Primjer koda iz dokumentacije funkcije prikupljanja

# example
library(dplyr)
stocks <- data.frame(
  time = as.Date('2009-01-01') + 0:9,
  X = rnorm(10, 0, 1),
  Y = rnorm(10, 0, 2),
  Z = rnorm(10, 0, 4)
)

# old
stocks_gather <- stocks %>% gather(key   = stock, 
                                   value = price, 
                                   -time)

# new
stocks_long   <- stocks %>% pivot_longer(cols      = -time, 
                                       names_to  = "stock", 
                                       values_to = "price")

Pretvaranje dugog formata u široki format.

Primjer koda iz dokumentacije funkcije širenja

# old
stocks_spread <- stocks_gather %>% spread(key = stock, 
                                          value = price) 

# new 
stock_wide    <- stocks_long %>% pivot_wider(names_from  = "stock",
                                            values_from = "price")

Jer u gornjim primjerima rada sa pivot_longer() и pivot_wider(), u originalnoj tabeli Akcije nema kolona navedenih u argumentima names_to и vrijednosti_za njihova imena moraju biti pod navodnicima.

Tabela koja će vam pomoći da najlakše shvatite kako se prebaciti na rad s novim konceptom tidyr.

R paket tidyr i njegove nove funkcije pivot_longer i pivot_wider

Napomena autora

Sav tekst ispod je adaptivan, čak bih rekao i besplatan prijevod vinjete sa službene web stranice biblioteke tidyverse.

Jednostavan primjer pretvaranja podataka iz širokog u dugi format

pivot_longer () — čini skupove podataka dužim smanjenjem broja kolona i povećanjem broja redova.

R paket tidyr i njegove nove funkcije pivot_longer i pivot_wider

Da biste pokrenuli primjere predstavljene u članku, prvo morate povezati potrebne pakete:

library(tidyr)
library(dplyr)
library(readr)

Recimo da imamo tabelu s rezultatima ankete koja je (između ostalog) pitala ljude o njihovoj vjeri i godišnjem prihodu:

#> # A tibble: 18 x 11
#>    religion `<$10k` `$10-20k` `$20-30k` `$30-40k` `$40-50k` `$50-75k`
#>    <chr>      <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
#>  1 Agnostic      27        34        60        81        76       137
#>  2 Atheist       12        27        37        52        35        70
#>  3 Buddhist      27        21        30        34        33        58
#>  4 Catholic     418       617       732       670       638      1116
#>  5 Don’t k…      15        14        15        11        10        35
#>  6 Evangel…     575       869      1064       982       881      1486
#>  7 Hindu          1         9         7         9        11        34
#>  8 Histori…     228       244       236       238       197       223
#>  9 Jehovah…      20        27        24        24        21        30
#> 10 Jewish        19        19        25        25        30        95
#> # … with 8 more rows, and 4 more variables: `$75-100k` <dbl>,
#> #   `$100-150k` <dbl>, `>150k` <dbl>, `Don't know/refused` <dbl>

Ova tabela sadrži podatke o religiji ispitanika u redovima, a nivoi prihoda su razbacani po nazivima kolona. Broj ispitanika iz svake kategorije pohranjen je u vrijednosti ćelije na sjecištu religije i nivoa prihoda. Da bi se tabela dovela u uredan, ispravan format, dovoljno je koristiti pivot_longer():

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")
#> # A tibble: 180 x 3
#>    religion income             count
#>    <chr>    <chr>              <dbl>
#>  1 Agnostic <$10k                 27
#>  2 Agnostic $10-20k               34
#>  3 Agnostic $20-30k               60
#>  4 Agnostic $30-40k               81
#>  5 Agnostic $40-50k               76
#>  6 Agnostic $50-75k              137
#>  7 Agnostic $75-100k             122
#>  8 Agnostic $100-150k            109
#>  9 Agnostic >150k                 84
#> 10 Agnostic Don't know/refused    96
#> # … with 170 more rows

Argumenti funkcije pivot_longer()

  • Prvi argument ovratnici, opisuje koje kolone treba spojiti. U ovom slučaju, sve kolone osim vrijeme.
  • Argument names_to daje ime varijable koja će biti kreirana iz imena kolona koje smo spojili.
  • vrijednosti_za daje naziv varijable koja će se kreirati iz podataka pohranjenih u vrijednostima ćelija spojenih kolona.

Спецификации

Ovo je nova funkcionalnost paketa tidyr, koji je ranije bio nedostupan pri radu sa naslijeđenim funkcijama.

Specifikacija je okvir podataka, čiji svaki red odgovara jednoj koloni u novom izlaznom datumskom okviru i dvije posebne kolone koje počinju sa:

  • .name sadrži originalno ime kolone.
  • .value sadrži naziv kolone koja će sadržavati vrijednosti ćelije.

Preostale kolone specifikacije odražavaju kako će nova kolona prikazati naziv komprimiranih stupaca iz .name.

Specifikacija opisuje metapodatke pohranjene u nazivu stupca, s jednim redom za svaki stupac i jednim stupcem za svaku varijablu, u kombinaciji s imenom stupca, ova definicija može izgledati zbunjujuće u ovom trenutku, ali nakon što pogledate nekoliko primjera, to će postati mnogo jasnije.

Poenta specifikacije je da možete dohvatiti, modificirati i definirati nove metapodatke za okvir podataka koji se pretvara.

Za rad sa specifikacijama pri pretvaranju tablice iz širokog formata u dugi format, koristite funkciju pivot_longer_spec().

Način na koji ova funkcija funkcionira je da uzima bilo koji okvir datuma i generiše svoje metapodatke na gore opisan način.

Kao primjer, uzmimo who dataset koji se isporučuje s paketom tidyr. Ovaj skup podataka sadrži informacije međunarodne zdravstvene organizacije o učestalosti tuberkuloze.

who
#> # A tibble: 7,240 x 60
#>    country iso2  iso3   year new_sp_m014 new_sp_m1524 new_sp_m2534
#>    <chr>   <chr> <chr> <int>       <int>        <int>        <int>
#>  1 Afghan… AF    AFG    1980          NA           NA           NA
#>  2 Afghan… AF    AFG    1981          NA           NA           NA
#>  3 Afghan… AF    AFG    1982          NA           NA           NA
#>  4 Afghan… AF    AFG    1983          NA           NA           NA
#>  5 Afghan… AF    AFG    1984          NA           NA           NA
#>  6 Afghan… AF    AFG    1985          NA           NA           NA
#>  7 Afghan… AF    AFG    1986          NA           NA           NA
#>  8 Afghan… AF    AFG    1987          NA           NA           NA
#>  9 Afghan… AF    AFG    1988          NA           NA           NA
#> 10 Afghan… AF    AFG    1989          NA           NA           NA
#> # … with 7,230 more rows, and 53 more variables

Hajde da napravimo njegovu specifikaciju.

spec <- who %>%
  pivot_longer_spec(new_sp_m014:newrel_f65, values_to = "count")

#> # A tibble: 56 x 3
#>    .name        .value name        
#>    <chr>        <chr>  <chr>       
#>  1 new_sp_m014  count  new_sp_m014 
#>  2 new_sp_m1524 count  new_sp_m1524
#>  3 new_sp_m2534 count  new_sp_m2534
#>  4 new_sp_m3544 count  new_sp_m3544
#>  5 new_sp_m4554 count  new_sp_m4554
#>  6 new_sp_m5564 count  new_sp_m5564
#>  7 new_sp_m65   count  new_sp_m65  
#>  8 new_sp_f014  count  new_sp_f014 
#>  9 new_sp_f1524 count  new_sp_f1524
#> 10 new_sp_f2534 count  new_sp_f2534
#> # … with 46 more rows

polja zemlja, iso2, iso3 su već varijable. Naš zadatak je da okrenemo kolone sa new_sp_m014 na newrel_f65.

Nazivi ovih kolona pohranjuju sljedeće informacije:

  • Prefiks new_ označava da kolona sadrži podatke o novim slučajevima tuberkuloze, trenutni datumski okvir sadrži podatke samo o novim bolestima, tako da ovaj prefiks u trenutnom kontekstu nema nikakvo značenje.
  • sp/rel/sp/ep opisuje metodu za dijagnosticiranje bolesti.
  • m/f spol pacijenta.
  • 014/1524/2535/3544/4554/65 dob pacijenata.

Ove kolone možemo podijeliti pomoću funkcije extract()koristeći regularni izraz.

spec <- spec %>%
        extract(name, c("diagnosis", "gender", "age"), "new_?(.*)_(.)(.*)")

#> # A tibble: 56 x 5
#>    .name        .value diagnosis gender age  
#>    <chr>        <chr>  <chr>     <chr>  <chr>
#>  1 new_sp_m014  count  sp        m      014  
#>  2 new_sp_m1524 count  sp        m      1524 
#>  3 new_sp_m2534 count  sp        m      2534 
#>  4 new_sp_m3544 count  sp        m      3544 
#>  5 new_sp_m4554 count  sp        m      4554 
#>  6 new_sp_m5564 count  sp        m      5564 
#>  7 new_sp_m65   count  sp        m      65   
#>  8 new_sp_f014  count  sp        f      014  
#>  9 new_sp_f1524 count  sp        f      1524 
#> 10 new_sp_f2534 count  sp        f      2534 
#> # … with 46 more rows

Obratite pažnju na kolonu .name treba ostati nepromijenjen jer je ovo naš indeks u nazivima stupaca originalnog skupa podataka.

Spol i starost (kolone pol и starost) imaju fiksne i poznate vrijednosti, pa se preporučuje da ove kolone pretvorite u faktore:

spec <-  spec %>%
            mutate(
              gender = factor(gender, levels = c("f", "m")),
              age = factor(age, levels = unique(age), ordered = TRUE)
            ) 

Konačno, kako bismo primijenili specifikaciju koju smo kreirali na originalni okvir datuma koji moramo koristiti argument spec u funkciji pivot_longer().

who %>% pivot_longer(spec = spec)

#> # A tibble: 405,440 x 8
#>    country     iso2  iso3   year diagnosis gender age   count
#>    <chr>       <chr> <chr> <int> <chr>     <fct>  <ord> <int>
#>  1 Afghanistan AF    AFG    1980 sp        m      014      NA
#>  2 Afghanistan AF    AFG    1980 sp        m      1524     NA
#>  3 Afghanistan AF    AFG    1980 sp        m      2534     NA
#>  4 Afghanistan AF    AFG    1980 sp        m      3544     NA
#>  5 Afghanistan AF    AFG    1980 sp        m      4554     NA
#>  6 Afghanistan AF    AFG    1980 sp        m      5564     NA
#>  7 Afghanistan AF    AFG    1980 sp        m      65       NA
#>  8 Afghanistan AF    AFG    1980 sp        f      014      NA
#>  9 Afghanistan AF    AFG    1980 sp        f      1524     NA
#> 10 Afghanistan AF    AFG    1980 sp        f      2534     NA
#> # … with 405,430 more rows

Sve što smo upravo uradili može se shematski prikazati na sljedeći način:

R paket tidyr i njegove nove funkcije pivot_longer i pivot_wider

Specifikacija koristeći više vrijednosti (.value)

U gornjem primjeru, kolona specifikacije .value sadrži samo jednu vrijednost, u većini slučajeva je to slučaj.

Ali povremeno se može pojaviti situacija kada trebate prikupiti podatke iz stupaca s različitim tipovima podataka u vrijednostima. Korištenje stare funkcije spread() ovo bi bilo prilično teško izvesti.

Primjer ispod je preuzet iz vinjete na paket data.table.

Kreirajmo okvir podataka za obuku.

family <- tibble::tribble(
  ~family,  ~dob_child1,  ~dob_child2, ~gender_child1, ~gender_child2,
       1L, "1998-11-26", "2000-01-29",             1L,             2L,
       2L, "1996-06-22",           NA,             2L,             NA,
       3L, "2002-07-11", "2004-04-05",             2L,             2L,
       4L, "2004-10-10", "2009-08-27",             1L,             1L,
       5L, "2000-12-05", "2005-02-28",             2L,             1L,
)
family <- family %>% mutate_at(vars(starts_with("dob")), parse_date)

#> # A tibble: 5 x 5
#>   family dob_child1 dob_child2 gender_child1 gender_child2
#>    <int> <date>     <date>             <int>         <int>
#> 1      1 1998-11-26 2000-01-29             1             2
#> 2      2 1996-06-22 NA                     2            NA
#> 3      3 2002-07-11 2004-04-05             2             2
#> 4      4 2004-10-10 2009-08-27             1             1
#> 5      5 2000-12-05 2005-02-28             2             1

Kreirani datumski okvir sadrži podatke o djeci jedne porodice u svakom redu. Porodice mogu imati jedno ili dvoje djece. Za svako dijete daju se podaci o datumu rođenja i spolu, a podaci za svako dijete su u posebnim kolonama, a naš zadatak je da te podatke dovedemo u ispravan format za analizu.

Napominjemo da imamo dvije varijable sa informacijama o svakom djetetu: njegov spol i datum rođenja (kolone s prefiksom dop sadrže datum rođenja, kolone sa prefiksom pol sadrže spol djeteta). Očekivani rezultat je da se pojavljuju u odvojenim kolonama. To možemo učiniti generiranjem specifikacije u kojoj stupac .value imaće dva različita značenja.

spec <- family %>%
  pivot_longer_spec(-family) %>%
  separate(col = name, into = c(".value", "child"))%>%
  mutate(child = parse_number(child))

#> # A tibble: 4 x 3
#>   .name         .value child
#>   <chr>         <chr>  <dbl>
#> 1 dob_child1    dob        1
#> 2 dob_child2    dob        2
#> 3 gender_child1 gender     1
#> 4 gender_child2 gender     2

Dakle, pogledajmo korak po korak radnje koje izvodi gornji kod.

  • pivot_longer_spec(-family) — kreirajte specifikaciju koja komprimira sve postojeće kolone osim kolone porodice.
  • separate(col = name, into = c(".value", "child")) - podeli kolonu .name, koji sadrži nazive izvornih polja, koristeći donju crtu i unoseći rezultirajuće vrijednosti u stupce .value и Dete.
  • mutate(child = parse_number(child)) — transformirajte vrijednosti polja Dete od tekstualnog do numeričkog tipa podataka.

Sada možemo primijeniti rezultirajuću specifikaciju na originalni okvir podataka i dovesti tablicu u željeni oblik.

family %>% 
    pivot_longer(spec = spec, na.rm = T)

#> # A tibble: 9 x 4
#>   family child dob        gender
#>    <int> <dbl> <date>      <int>
#> 1      1     1 1998-11-26      1
#> 2      1     2 2000-01-29      2
#> 3      2     1 1996-06-22      2
#> 4      3     1 2002-07-11      2
#> 5      3     2 2004-04-05      2
#> 6      4     1 2004-10-10      1
#> 7      4     2 2009-08-27      1
#> 8      5     1 2000-12-05      2
#> 9      5     2 2005-02-28      1

Koristimo argument na.rm = TRUE, jer trenutni oblik podataka prisiljava stvaranje dodatnih redova za nepostojeća opažanja. Jer porodica 2 ima samo jedno dijete, na.rm = TRUE garantuje da će porodica 2 imati jedan red na izlazu.

Pretvaranje okvira datuma iz dugog u široki format

pivot_wider() - je inverzna transformacija, i obrnuto povećava broj kolona okvira datuma smanjenjem broja redova.

R paket tidyr i njegove nove funkcije pivot_longer i pivot_wider

Ova vrsta transformacije se izuzetno rijetko koristi za dovođenje podataka u tačan oblik, međutim, ova tehnika može biti korisna za kreiranje pivot tablica koje se koriste u prezentacijama ili za integraciju s nekim drugim alatima.

Zapravo funkcije pivot_longer() и pivot_wider() su simetrične i proizvode akcije inverzne jedna drugoj, tj.: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) će vratiti originalni df.

Najjednostavniji primjer pretvaranja tablice u široki format

Da demonstrira kako funkcija radi pivot_wider() koristićemo skup podataka fish_encounters, koji pohranjuje informacije o tome kako različite stanice bilježe kretanje ribe duž rijeke.

#> # A tibble: 114 x 3
#>    fish  station  seen
#>    <fct> <fct>   <int>
#>  1 4842  Release     1
#>  2 4842  I80_1       1
#>  3 4842  Lisbon      1
#>  4 4842  Rstr        1
#>  5 4842  Base_TD     1
#>  6 4842  BCE         1
#>  7 4842  BCW         1
#>  8 4842  BCE2        1
#>  9 4842  BCW2        1
#> 10 4842  MAE         1
#> # … with 104 more rows

U većini slučajeva, ova tabela će biti informativnija i lakša za korištenje ako predstavite informacije za svaku stanicu u posebnoj koloni.

fish_encounters %>% pivot_wider(names_from = station, values_from = seen)

fish_encounters %>% pivot_wider(names_from = station, values_from = seen)
#> # A tibble: 19 x 12
#>    fish  Release I80_1 Lisbon  Rstr Base_TD   BCE   BCW  BCE2  BCW2   MAE
#>    <fct>   <int> <int>  <int> <int>   <int> <int> <int> <int> <int> <int>
#>  1 4842        1     1      1     1       1     1     1     1     1     1
#>  2 4843        1     1      1     1       1     1     1     1     1     1
#>  3 4844        1     1      1     1       1     1     1     1     1     1
#>  4 4845        1     1      1     1       1    NA    NA    NA    NA    NA
#>  5 4847        1     1      1    NA      NA    NA    NA    NA    NA    NA
#>  6 4848        1     1      1     1      NA    NA    NA    NA    NA    NA
#>  7 4849        1     1     NA    NA      NA    NA    NA    NA    NA    NA
#>  8 4850        1     1     NA     1       1     1     1    NA    NA    NA
#>  9 4851        1     1     NA    NA      NA    NA    NA    NA    NA    NA
#> 10 4854        1     1     NA    NA      NA    NA    NA    NA    NA    NA
#> # … with 9 more rows, and 1 more variable: MAW <int>

Ovaj skup podataka bilježi samo informacije kada stanica detektuje ribu, tj. ako neku ribu nije snimila neka stanica, onda ti podaci neće biti u tabeli. To znači da će izlaz biti popunjen sa NA.

Međutim, u ovom slučaju znamo da izostanak zapisa znači da riba nije viđena, pa možemo koristiti argument values_fill u funkciji pivot_wider() i popunite ove nedostajuće vrijednosti nulama:

fish_encounters %>% pivot_wider(
  names_from = station, 
  values_from = seen,
  values_fill = list(seen = 0)
)

#> # A tibble: 19 x 12
#>    fish  Release I80_1 Lisbon  Rstr Base_TD   BCE   BCW  BCE2  BCW2   MAE
#>    <fct>   <int> <int>  <int> <int>   <int> <int> <int> <int> <int> <int>
#>  1 4842        1     1      1     1       1     1     1     1     1     1
#>  2 4843        1     1      1     1       1     1     1     1     1     1
#>  3 4844        1     1      1     1       1     1     1     1     1     1
#>  4 4845        1     1      1     1       1     0     0     0     0     0
#>  5 4847        1     1      1     0       0     0     0     0     0     0
#>  6 4848        1     1      1     1       0     0     0     0     0     0
#>  7 4849        1     1      0     0       0     0     0     0     0     0
#>  8 4850        1     1      0     1       1     1     1     0     0     0
#>  9 4851        1     1      0     0       0     0     0     0     0     0
#> 10 4854        1     1      0     0       0     0     0     0     0     0
#> # … with 9 more rows, and 1 more variable: MAW <int>

Generiranje naziva stupca iz više izvornih varijabli

Zamislite da imamo tabelu koja sadrži kombinaciju proizvoda, zemlje i godine. Za generiranje testnog datumskog okvira, možete pokrenuti sljedeći kod:

df <- expand_grid(
  product = c("A", "B"), 
  country = c("AI", "EI"), 
  year = 2000:2014
) %>%
  filter((product == "A" & country == "AI") | product == "B") %>% 
  mutate(value = rnorm(nrow(.)))

#> # A tibble: 45 x 4
#>    product country  year    value
#>    <chr>   <chr>   <int>    <dbl>
#>  1 A       AI       2000 -2.05   
#>  2 A       AI       2001 -0.676  
#>  3 A       AI       2002  1.60   
#>  4 A       AI       2003 -0.353  
#>  5 A       AI       2004 -0.00530
#>  6 A       AI       2005  0.442  
#>  7 A       AI       2006 -0.610  
#>  8 A       AI       2007 -2.77   
#>  9 A       AI       2008  0.899  
#> 10 A       AI       2009 -0.106  
#> # … with 35 more rows

Naš zadatak je proširiti okvir podataka tako da jedna kolona sadrži podatke za svaku kombinaciju proizvoda i zemlje. Da biste to učinili, samo unesite argument imena_od vektor koji sadrži imena polja koja se spajaju.

df %>% pivot_wider(names_from = c(product, country),
                 values_from = "value")

#> # A tibble: 15 x 4
#>     year     A_AI    B_AI    B_EI
#>    <int>    <dbl>   <dbl>   <dbl>
#>  1  2000 -2.05     0.607   1.20  
#>  2  2001 -0.676    1.65   -0.114 
#>  3  2002  1.60    -0.0245  0.501 
#>  4  2003 -0.353    1.30   -0.459 
#>  5  2004 -0.00530  0.921  -0.0589
#>  6  2005  0.442   -1.55    0.594 
#>  7  2006 -0.610    0.380  -1.28  
#>  8  2007 -2.77     0.830   0.637 
#>  9  2008  0.899    0.0175 -1.30  
#> 10  2009 -0.106   -0.195   1.03  
#> # … with 5 more rows

Također možete primijeniti specifikacije na funkciju pivot_wider(). Ali kada se podnese pivot_wider() specifikacija radi suprotnu konverziju pivot_longer(): Kolone navedene u .name, koristeći vrijednosti iz .value i druge kolone.

Za ovaj skup podataka možete generirati prilagođenu specifikaciju ako želite da svaka moguća kombinacija zemlje i proizvoda ima svoj stupac, a ne samo one prisutne u podacima:

spec <- df %>% 
  expand(product, country, .value = "value") %>% 
  unite(".name", product, country, remove = FALSE)

#> # A tibble: 4 x 4
#>   .name product country .value
#>   <chr> <chr>   <chr>   <chr> 
#> 1 A_AI  A       AI      value 
#> 2 A_EI  A       EI      value 
#> 3 B_AI  B       AI      value 
#> 4 B_EI  B       EI      value

df %>% pivot_wider(spec = spec) %>% head()

#> # A tibble: 6 x 5
#>    year     A_AI  A_EI    B_AI    B_EI
#>   <int>    <dbl> <dbl>   <dbl>   <dbl>
#> 1  2000 -2.05       NA  0.607   1.20  
#> 2  2001 -0.676      NA  1.65   -0.114 
#> 3  2002  1.60       NA -0.0245  0.501 
#> 4  2003 -0.353      NA  1.30   -0.459 
#> 5  2004 -0.00530    NA  0.921  -0.0589
#> 6  2005  0.442      NA -1.55    0.594

Nekoliko naprednih primjera rada s novim tidyr konceptom

Čišćenje podataka koristeći skup podataka o prihodima i stanarini u SAD kao primjer.

Skup podataka us_rent_income sadrži informacije o srednjem prihodu i stanarini za svaku državu u SAD-u za 2017. (skup podataka dostupan u paketu tidycensus).

us_rent_income
#> # A tibble: 104 x 5
#>    GEOID NAME       variable estimate   moe
#>    <chr> <chr>      <chr>       <dbl> <dbl>
#>  1 01    Alabama    income      24476   136
#>  2 01    Alabama    rent          747     3
#>  3 02    Alaska     income      32940   508
#>  4 02    Alaska     rent         1200    13
#>  5 04    Arizona    income      27517   148
#>  6 04    Arizona    rent          972     4
#>  7 05    Arkansas   income      23789   165
#>  8 05    Arkansas   rent          709     5
#>  9 06    California income      29454   109
#> 10 06    California rent         1358     3
#> # … with 94 more rows

U obliku u kojem su podaci pohranjeni u skupu podataka us_rent_income rad sa njima je izuzetno nezgodan, pa bismo želeli da kreiramo skup podataka sa kolonama: najam, rent_moe, doći, prihod_moe. Postoji mnogo načina za kreiranje ove specifikacije, ali glavna stvar je da moramo generirati svaku kombinaciju varijabilnih vrijednosti i procjena/moea zatim generirajte naziv stupca.

  spec <- us_rent_income %>% 
    expand(variable, .value = c("estimate", "moe")) %>% 
    mutate(
      .name = paste0(variable, ifelse(.value == "moe", "_moe", ""))
    )

#> # A tibble: 4 x 3
#>   variable .value   .name     
#>   <chr>    <chr>    <chr>     
#> 1 income   estimate income    
#> 2 income   moe      income_moe
#> 3 rent     estimate rent      
#> 4 rent     moe      rent_moe

Pružanje ove specifikacije pivot_wider() daje rezultat koji tražimo:

us_rent_income %>% pivot_wider(spec = spec)

#> # A tibble: 52 x 6
#>    GEOID NAME                 income income_moe  rent rent_moe
#>    <chr> <chr>                 <dbl>      <dbl> <dbl>    <dbl>
#>  1 01    Alabama               24476        136   747        3
#>  2 02    Alaska                32940        508  1200       13
#>  3 04    Arizona               27517        148   972        4
#>  4 05    Arkansas              23789        165   709        5
#>  5 06    California            29454        109  1358        3
#>  6 08    Colorado              32401        109  1125        5
#>  7 09    Connecticut           35326        195  1123        5
#>  8 10    Delaware              31560        247  1076       10
#>  9 11    District of Columbia  43198        681  1424       17
#> 10 12    Florida               25952         70  1077        3
#> # … with 42 more rows

Svjetska banka

Ponekad je za dovođenje skupa podataka u željeni oblik potrebno nekoliko koraka.
Skup podataka world_bank_pop sadrži podatke Svjetske banke o stanovništvu svake zemlje između 2000. i 2018. godine.

#> # A tibble: 1,056 x 20
#>    country indicator `2000` `2001` `2002` `2003`  `2004`  `2005`   `2006`
#>    <chr>   <chr>      <dbl>  <dbl>  <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
#>  1 ABW     SP.URB.T… 4.24e4 4.30e4 4.37e4 4.42e4 4.47e+4 4.49e+4  4.49e+4
#>  2 ABW     SP.URB.G… 1.18e0 1.41e0 1.43e0 1.31e0 9.51e-1 4.91e-1 -1.78e-2
#>  3 ABW     SP.POP.T… 9.09e4 9.29e4 9.50e4 9.70e4 9.87e+4 1.00e+5  1.01e+5
#>  4 ABW     SP.POP.G… 2.06e0 2.23e0 2.23e0 2.11e0 1.76e+0 1.30e+0  7.98e-1
#>  5 AFG     SP.URB.T… 4.44e6 4.65e6 4.89e6 5.16e6 5.43e+6 5.69e+6  5.93e+6
#>  6 AFG     SP.URB.G… 3.91e0 4.66e0 5.13e0 5.23e0 5.12e+0 4.77e+0  4.12e+0
#>  7 AFG     SP.POP.T… 2.01e7 2.10e7 2.20e7 2.31e7 2.41e+7 2.51e+7  2.59e+7
#>  8 AFG     SP.POP.G… 3.49e0 4.25e0 4.72e0 4.82e0 4.47e+0 3.87e+0  3.23e+0
#>  9 AGO     SP.URB.T… 8.23e6 8.71e6 9.22e6 9.77e6 1.03e+7 1.09e+7  1.15e+7
#> 10 AGO     SP.URB.G… 5.44e0 5.59e0 5.70e0 5.76e0 5.75e+0 5.69e+0  4.92e+0
#> # … with 1,046 more rows, and 11 more variables: `2007` <dbl>,
#> #   `2008` <dbl>, `2009` <dbl>, `2010` <dbl>, `2011` <dbl>, `2012` <dbl>,
#> #   `2013` <dbl>, `2014` <dbl>, `2015` <dbl>, `2016` <dbl>, `2017` <dbl>

Naš cilj je da kreiramo uredan skup podataka sa svakom promenljivom u sopstvenoj koloni. Nije jasno koji su tačno koraci potrebni, ali počećemo s najočiglednijim problemom: godina je raspoređena u više kolona.

Da biste to popravili, morate koristiti funkciju pivot_longer().

pop2 <- world_bank_pop %>% 
  pivot_longer(`2000`:`2017`, names_to = "year")

#> # A tibble: 19,008 x 4
#>    country indicator   year  value
#>    <chr>   <chr>       <chr> <dbl>
#>  1 ABW     SP.URB.TOTL 2000  42444
#>  2 ABW     SP.URB.TOTL 2001  43048
#>  3 ABW     SP.URB.TOTL 2002  43670
#>  4 ABW     SP.URB.TOTL 2003  44246
#>  5 ABW     SP.URB.TOTL 2004  44669
#>  6 ABW     SP.URB.TOTL 2005  44889
#>  7 ABW     SP.URB.TOTL 2006  44881
#>  8 ABW     SP.URB.TOTL 2007  44686
#>  9 ABW     SP.URB.TOTL 2008  44375
#> 10 ABW     SP.URB.TOTL 2009  44052
#> # … with 18,998 more rows

Sljedeći korak je da pogledate varijablu indikatora.
pop2 %>% count(indicator)

#> # A tibble: 4 x 2
#>   indicator       n
#>   <chr>       <int>
#> 1 SP.POP.GROW  4752
#> 2 SP.POP.TOTL  4752
#> 3 SP.URB.GROW  4752
#> 4 SP.URB.TOTL  4752

Gdje je SP.POP.GROW rast populacije, SP.POP.TOTL je ukupna populacija, a SP.URB. * ista stvar, ali samo za urbana područja. Podijelimo ove vrijednosti na dvije varijable: područje - područje (ukupno ili urbano) i varijablu koja sadrži stvarne podatke (stanovništvo ili rast):

pop3 <- pop2 %>% 
  separate(indicator, c(NA, "area", "variable"))

#> # A tibble: 19,008 x 5
#>    country area  variable year  value
#>    <chr>   <chr> <chr>    <chr> <dbl>
#>  1 ABW     URB   TOTL     2000  42444
#>  2 ABW     URB   TOTL     2001  43048
#>  3 ABW     URB   TOTL     2002  43670
#>  4 ABW     URB   TOTL     2003  44246
#>  5 ABW     URB   TOTL     2004  44669
#>  6 ABW     URB   TOTL     2005  44889
#>  7 ABW     URB   TOTL     2006  44881
#>  8 ABW     URB   TOTL     2007  44686
#>  9 ABW     URB   TOTL     2008  44375
#> 10 ABW     URB   TOTL     2009  44052
#> # … with 18,998 more rows

Sada sve što treba da uradimo je da podelimo promenljivu u dve kolone:

pop3 %>% 
  pivot_wider(names_from = variable, values_from = value)

#> # A tibble: 9,504 x 5
#>    country area  year   TOTL    GROW
#>    <chr>   <chr> <chr> <dbl>   <dbl>
#>  1 ABW     URB   2000  42444  1.18  
#>  2 ABW     URB   2001  43048  1.41  
#>  3 ABW     URB   2002  43670  1.43  
#>  4 ABW     URB   2003  44246  1.31  
#>  5 ABW     URB   2004  44669  0.951 
#>  6 ABW     URB   2005  44889  0.491 
#>  7 ABW     URB   2006  44881 -0.0178
#>  8 ABW     URB   2007  44686 -0.435 
#>  9 ABW     URB   2008  44375 -0.698 
#> 10 ABW     URB   2009  44052 -0.731 
#> # … with 9,494 more rows

Lista kontakata

Zadnji primjer, zamislite da imate listu kontakata koju ste kopirali i zalijepili sa web stranice:

contacts <- tribble(
  ~field, ~value,
  "name", "Jiena McLellan",
  "company", "Toyota", 
  "name", "John Smith", 
  "company", "google", 
  "email", "[email protected]",
  "name", "Huxley Ratcliffe"
)

Tabelarno sastavljanje ove liste je prilično teško jer ne postoji varijabla koja identifikuje koji podaci pripadaju kom kontaktu. To možemo popraviti tako što ćemo primijetiti da podaci svakog novog kontakta počinju s "name", tako da možemo kreirati jedinstveni identifikator i povećati ga za jedan svaki put kada stupac polja sadrži vrijednost "name":

contacts <- contacts %>% 
  mutate(
    person_id = cumsum(field == "name")
  )
contacts

#> # A tibble: 6 x 3
#>   field   value            person_id
#>   <chr>   <chr>                <int>
#> 1 name    Jiena McLellan           1
#> 2 company Toyota                   1
#> 3 name    John Smith               2
#> 4 company google                   2
#> 5 email   [email protected]          2
#> 6 name    Huxley Ratcliffe         3

Sada kada imamo jedinstven ID za svaki kontakt, možemo pretvoriti polje i vrijednost u stupce:

contacts %>% 
  pivot_wider(names_from = field, values_from = value)

#> # A tibble: 3 x 4
#>   person_id name             company email          
#>       <int> <chr>            <chr>   <chr>          
#> 1         1 Jiena McLellan   Toyota  <NA>           
#> 2         2 John Smith       google  [email protected]
#> 3         3 Huxley Ratcliffe <NA>    <NA>

zaključak

Moje lično mišljenje je da je novi koncept tidyr zaista intuitivniji i značajno superiorniji u funkcionalnosti u odnosu na stare funkcije spread() и gather(). Nadam se da vam je ovaj članak pomogao da se nosite pivot_longer() и pivot_wider().

izvor: www.habr.com

Dodajte komentar