R balík tidyr a jeho nové funkcie pivot_longer a pivot_wider

balíček uprataný zahrnuté v jadre jednej z najpopulárnejších knižníc v jazyku R - poriadok.
Hlavným účelom balíka je uviesť údaje do presnej podoby.

Už dostupné na Habré zverejnenie venovaný tomuto balíku, ale pochádza z roku 2015. A chcem vám porozprávať o najaktuálnejších zmenách, ktoré pred pár dňami oznámila jeho autorka Hedley Wickham.

R balík tidyr a jeho nové funkcie pivot_longer a pivot_wider

SJK: Budú funkcie collect() a spread() zastarané?

Hadley Wickham: Do istej miery. Tieto funkcie už nebudeme odporúčať a opravovať v nich chyby, v balíku sa však budú nachádzať aj naďalej v aktuálnom stave.

Obsah

Ak máte záujem o analýzu údajov, mohla by vás zaujímať moja telegram и youtube kanálov. Väčšina obsahu je venovaná jazyku R.

Koncept TidyData

Cieľ uprataný — pomôže vám uviesť údaje do takzvanej prehľadnej formy. Čisté údaje sú údaje, kde:

  • Každá premenná je v stĺpci.
  • Každé pozorovanie je reťazec.
  • Každá hodnota je bunka.

Pri vykonávaní analýzy je oveľa jednoduchšie a pohodlnejšie pracovať s údajmi, ktoré sú prezentované v prehľadných údajoch.

Hlavné funkcie zahrnuté v balíku tidyr

tidyr obsahuje sadu funkcií určených na transformáciu tabuliek:

  • fill() — vyplnenie chýbajúcich hodnôt v stĺpci predchádzajúcimi hodnotami;
  • separate() — rozdelí jedno pole na niekoľko pomocou oddeľovača;
  • unite() — vykonáva operáciu spojenia viacerých polí do jedného, ​​inverznú akciu funkcie separate();
  • pivot_longer() — funkcia, ktorá konvertuje údaje zo širokého formátu na dlhý formát;
  • pivot_wider() - funkcia, ktorá konvertuje dáta z dlhého formátu na široký formát. Opačná činnosť funkcie, ktorú vykonáva pivot_longer().
  • gather()zastarané — funkcia, ktorá konvertuje údaje zo širokého formátu na dlhý formát;
  • spread()zastarané - funkcia, ktorá konvertuje dáta z dlhého formátu na široký formát. Opačná činnosť funkcie, ktorú vykonáva gather().

Nový koncept pre konverziu dát zo širokého na dlhý formát a naopak

Predtým sa na tento druh transformácie používali funkcie gather() и spread(). V priebehu rokov existencie týchto funkcií sa ukázalo, že pre väčšinu používateľov vrátane autora balíka neboli názvy týchto funkcií a ich argumenty celkom zrejmé a spôsobovali problémy pri ich hľadaní a pochopení, ktoré z týchto funkcií prevádza dátumový rámec zo širokého na dlhý formát a naopak.

V tejto súvislosti v uprataný Boli pridané dve nové dôležité funkcie, ktoré sú určené na transformáciu rámčekov dátumu.

Nové funkcie pivot_longer() и pivot_wider() boli inšpirované niektorými funkciami v balíku cdata, ktorú vytvorili John Mount a Nina Zumel.

Inštalácia najnovšej verzie tidyr 0.8.3.9000

Ak chcete nainštalovať novú, najaktuálnejšiu verziu balíka uprataný 0.8.3.9000, kde sú k dispozícii nové funkcie, použite nasledujúci kód.

devtools::install_github("tidyverse/tidyr")

V čase písania tohto článku sú tieto funkcie dostupné iba vo verzii balíka pre vývojárov na GitHub.

Prechod na nové funkcie

V skutočnosti nie je ťažké preniesť staré skripty do práce s novými funkciami, pre lepšie pochopenie vezmem príklad z dokumentácie starých funkcií a ukážem, ako sa rovnaké operácie vykonávajú pomocou nových pivot_*() funkcie.

Previesť široký formát na dlhý formát.

Príklad kódu z dokumentácie funkcie zhromažďovania

# 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")

Konverzia dlhého formátu na široký formát.

Príklad kódu z dokumentácie k funkcii šírenia

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

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

Pretože vo vyššie uvedených príkladoch práce s pivot_longer() и pivot_wider(), v pôvodnej tabuľke zásoby v argumentoch nie sú uvedené žiadne stĺpce mená_kom и hodnoty_k ich mená musia byť v úvodzovkách.

Tabuľka, ktorá vám pomôže najjednoduchšie prísť na to, ako prejsť na prácu s novým konceptom uprataný.

R balík tidyr a jeho nové funkcie pivot_longer a pivot_wider

Poznámka od autora

Všetok text nižšie je adaptívny, dokonca by som povedal, že voľný preklad vinety z oficiálnej webovej stránky knižnice Tidyverse.

Jednoduchý príklad prevodu údajov zo širokého na dlhý formát

pivot_longer () — predĺži množiny údajov znížením počtu stĺpcov a zvýšením počtu riadkov.

R balík tidyr a jeho nové funkcie pivot_longer a pivot_wider

Ak chcete spustiť príklady uvedené v článku, musíte najprv pripojiť potrebné balíky:

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

Povedzme, že máme tabuľku s výsledkami prieskumu, ktorý sa (okrem iného) pýtal ľudí na ich náboženstvo a ročný príjem:

#> # 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>

Táto tabuľka obsahuje údaje o náboženstve respondentov v riadkoch a úrovne príjmu sú roztrúsené v názvoch stĺpcov. Počet respondentov z každej kategórie je uložený v hodnotách buniek na priesečníku náboženstva a úrovne príjmu. Aby sa stôl dostal do úhľadného a správneho formátu, stačí ho použiť 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

Funkcia Argumenty pivot_longer()

  • Prvý argument cols, popisuje, ktoré stĺpce je potrebné zlúčiť. V tomto prípade všetky stĺpce okrem čas.
  • argument mená_kom dáva názov premennej, ktorá sa vytvorí z názvov stĺpcov, ktoré sme zreťazili.
  • hodnoty_k dáva názov premennej, ktorá sa vytvorí z údajov uložených v hodnotách buniek zlúčených stĺpcov.

Špecifikácie

Toto je nová funkcia balíka uprataný, ktorá bola predtým nedostupná pri práci so staršími funkciami.

Špecifikácia je dátový rámec, ktorého každý riadok zodpovedá jednému stĺpcu v novom výstupnom dátumovom rámci a dvom špeciálnym stĺpcom, ktoré začínajú:

  • . Názov obsahuje pôvodný názov stĺpca.
  • .hodnota obsahuje názov stĺpca, ktorý bude obsahovať hodnoty buniek.

Zostávajúce stĺpce špecifikácie odrážajú, ako bude nový stĺpec zobrazovať názov komprimovaných stĺpcov z . Názov.

Špecifikácia popisuje metaúdaje uložené v názve stĺpca s jedným riadkom pre každý stĺpec a jedným stĺpcom pre každú premennú, v kombinácii s názvom stĺpca sa táto definícia môže v súčasnosti zdať mätúca, ale po zhliadnutí niekoľkých príkladov bude oveľa jasnejšie.

Pointou špecifikácie je, že môžete získať, upraviť a definovať nové metadáta pre dátový rámec, ktorý sa konvertuje.

Na prácu so špecifikáciami pri prevode tabuľky zo širokého formátu na dlhý formát použite funkciu pivot_longer_spec().

Táto funkcia funguje tak, že berie ľubovoľný dátumový rámec a generuje svoje metadáta spôsobom opísaným vyššie.

Ako príklad si vezmime súbor údajov who, ktorý sa dodáva s balíkom uprataný. Tento súbor údajov obsahuje informácie poskytnuté medzinárodnou zdravotníckou organizáciou o výskyte tuberkulózy.

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

Poďme zostaviť jeho špecifikáciu.

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

poľa krajiny, isoxnumx, isoxnumx sú už premenné. Našou úlohou je preklápať stĺpce s new_sp_m014 na newrel_f65.

Názvy týchto stĺpcov obsahujú nasledujúce informácie:

  • prefix new_ označuje, že stĺpec obsahuje údaje o nových prípadoch tuberkulózy, aktuálny dátumový rámec obsahuje informácie iba o nových ochoreniach, takže táto predpona v aktuálnom kontexte nemá žiadny význam.
  • sp/rel/sp/ep opisuje spôsob diagnostiky ochorenia.
  • m/f pohlavie pacienta.
  • 014/1524/2535/3544/4554/65 vekové rozpätie pacienta.

Tieto stĺpce môžeme rozdeliť pomocou funkcie extract()pomocou regulárneho výrazu.

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

Všimnite si prosím stĺpec . Názov by mali zostať nezmenené, pretože toto je náš index do názvov stĺpcov pôvodnej množiny údajov.

Pohlavie a vek (stĺpce rod и vek) majú pevné a známe hodnoty, preto sa odporúča previesť tieto stĺpce na faktory:

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

Nakoniec, aby sme mohli použiť špecifikáciu, ktorú sme vytvorili, na pôvodný dátumový rámec ktorý musíme použiť argument spec vo funkcii 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

Všetko, čo sme práve urobili, možno schematicky znázorniť takto:

R balík tidyr a jeho nové funkcie pivot_longer a pivot_wider

Špecifikácia pomocou viacerých hodnôt (.value)

Vo vyššie uvedenom príklade stĺpec špecifikácie .hodnota obsahoval iba jednu hodnotu, vo väčšine prípadov je to tak.

Občas však môže nastať situácia, keď potrebujete zhromaždiť údaje zo stĺpcov s rôznymi typmi údajov v hodnotách. Použitie staršej funkcie spread() to by bolo dosť ťažké urobiť.

Príklad nižšie je prevzatý z vinety do balíka údajová tabuľka.

Vytvorme tréningový dátový rámec.

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

Vytvorený dátumový rámec obsahuje v každom riadku údaje o deťoch jednej rodiny. Rodiny môžu mať jedno alebo dve deti. Pre každé dieťa sú uvedené údaje o dátume narodenia a pohlaví a údaje pre každé dieťa sú v samostatných stĺpcoch, našou úlohou je uviesť tieto údaje do správneho formátu na analýzu.

Upozorňujeme, že máme dve premenné s informáciami o každom dieťati: jeho pohlavie a dátum narodenia (stĺpce s predponou Krst obsahujú dátum narodenia, stĺpce s predponou rod obsahujú pohlavie dieťaťa). Očakávaným výsledkom je, že by sa mali objaviť v samostatných stĺpcoch. Môžeme to urobiť vygenerovaním špecifikácie, v ktorej je stĺpec .value bude mať dva rôzne významy.

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

Poďme sa teda krok za krokom pozrieť na akcie vykonávané vyššie uvedeným kódom.

  • pivot_longer_spec(-family) — vytvorte špecifikáciu, ktorá skomprimuje všetky existujúce stĺpce okrem stĺpca rodiny.
  • separate(col = name, into = c(".value", "child")) - rozdeliť stĺpec . Názov, ktorý obsahuje názvy zdrojových polí, pomocou podčiarkovníka a zadaním výsledných hodnôt do stĺpcov .hodnota и dieťa.
  • mutate(child = parse_number(child)) — transformovať hodnoty poľa dieťa z textového na číselný dátový typ.

Teraz môžeme výslednú špecifikáciu aplikovať na pôvodný dataframe a preniesť tabuľku do požadovanej podoby.

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

Používame argumentáciu na.rm = TRUE, pretože aktuálna forma údajov si vynucuje vytváranie ďalších riadkov pre neexistujúce pozorovania. Pretože rodina 2 má len jedno dieťa, na.rm = TRUE zaručuje, že rodina 2 bude mať na výstupe jeden riadok.

Konverzia dátumových snímok z dlhého na široký formát

pivot_wider() - je inverzná transformácia a naopak zvyšuje počet stĺpcov rámca dátumu znížením počtu riadkov.

R balík tidyr a jeho nové funkcie pivot_longer a pivot_wider

Tento druh transformácie sa veľmi zriedka používa na prenesenie údajov do presnej formy, avšak táto technika môže byť užitočná na vytváranie kontingenčných tabuliek používaných v prezentáciách alebo na integráciu s niektorými inými nástrojmi.

Vlastne funkcie pivot_longer() и pivot_wider() sú symetrické a vytvárajú navzájom inverzné akcie, t.j.: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) vráti pôvodný df.

Najjednoduchší príklad prevodu tabuľky na široký formát

Na ukážku, ako funkcia funguje pivot_wider() použijeme súbor údajov rybie_stretnutia, ktorý uchováva informácie o tom, ako rôzne stanice zaznamenávajú pohyb rýb po rieke.

#> # 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

Vo väčšine prípadov bude táto tabuľka informatívnejšia a ľahšie použiteľná, ak uvediete informácie pre každú stanicu v samostatnom stĺpci.

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>

Tento súbor údajov zaznamenáva informácie iba vtedy, keď boli ryby detekované stanicou, t.j. ak niektorá stanica nezaznamenala nejakú rybu, tak tento údaj nebude v tabuľke. To znamená, že výstup bude naplnený NA.

V tomto prípade však vieme, že absencia záznamu znamená, že ryba nebola videná, takže môžeme použiť argument value_fill vo funkcii pivot_wider() a doplňte tieto chýbajúce hodnoty nulami:

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>

Generovanie názvu stĺpca z viacerých zdrojových premenných

Predstavte si, že máme tabuľku obsahujúcu kombináciu produktu, krajiny a roku. Ak chcete vygenerovať testovací dátumový rámec, môžete spustiť nasledujúci kód:

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šou úlohou je rozšíriť dátový rámec tak, aby jeden stĺpec obsahoval údaje pre každú kombináciu produktu a krajiny. Ak to chcete urobiť, jednoducho odovzdajte argument mená_od vektor obsahujúci názvy polí, ktoré sa majú zlúčiť.

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

Na funkciu môžete použiť aj špecifikácie pivot_wider(). Ale keď sa podrobí pivot_wider() špecifikácia robí opačnú konverziu pivot_longer(): Stĺpce uvedené v . Názovpomocou hodnôt z .hodnota a ďalšie stĺpce.

Pre túto množinu údajov môžete vygenerovať vlastnú špecifikáciu, ak chcete, aby každá možná kombinácia krajín a produktov mala svoj vlastný stĺpec, nielen tie, ktoré sa nachádzajú v údajoch:

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

Niekoľko pokročilých príkladov práce s novým konceptom tidyr

Vyčistenie údajov pomocou súboru údajov o príjmoch a nájomnom v USA ako príklad.

Súbor údajov príjem_z_nájmu obsahuje informácie o mediánom príjme a nájomnom pre každý štát v USA za rok 2017 (súbor údajov je dostupný v balíku poriadok).

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

Vo forme, v akej sú údaje uložené v súbore údajov príjem_z_nájmu práca s nimi je mimoriadne nepohodlná, preto by sme chceli vytvoriť množinu údajov so stĺpcami: prenajať, rent_moe, Prísť, príjem_moe. Existuje mnoho spôsobov, ako vytvoriť túto špecifikáciu, ale hlavným bodom je, že musíme vygenerovať každú kombináciu premenných hodnôt a odhad/moea potom vygenerujte názov stĺpca.

  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

Poskytnutie tejto špecifikácie pivot_wider() nám dáva výsledok, ktorý hľadáme:

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

Svetová banka

Prenesenie súboru údajov do požadovanej formy niekedy vyžaduje niekoľko krokov.
Súbor údajov world_bank_pop obsahuje údaje Svetovej banky o počte obyvateľov jednotlivých krajín v rokoch 2000 až 2018.

#> # 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ším cieľom je vytvoriť prehľadný súbor údajov s každou premennou vo vlastnom stĺpci. Nie je presne jasné, aké kroky sú potrebné, ale začneme najzjavnejším problémom: rok je rozdelený do viacerých stĺpcov.

Ak to chcete opraviť, musíte použiť funkciu 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

Ďalším krokom je pozrieť sa na premennú indikátora.
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

Kde SP.POP.GROW je rast populácie, SP.POP.TOTL je celkový počet obyvateľov a SP.URB. * to isté, ale len pre mestské oblasti. Rozdeľme tieto hodnoty na dve premenné: plocha - plocha (celková alebo mestská) a premenná obsahujúca skutočné údaje (počet obyvateľov alebo 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

Teraz všetko, čo musíme urobiť, je rozdeliť premennú do dvoch stĺpcov:

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

Zoznam kontaktov

Posledný príklad, predstavte si, že máte zoznam kontaktov, ktorý ste skopírovali a prilepili z webovej lokality:

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

Zostavenie tohto zoznamu je pomerne náročné, pretože neexistuje žiadna premenná, ktorá by identifikovala, ktoré údaje patria ku ktorému kontaktu. Môžeme to opraviť tak, že si všimneme, že údaje každého nového kontaktu začínajú „meno“, takže môžeme vytvoriť jedinečný identifikátor a zvýšiť ho o jeden vždy, keď stĺpec poľa obsahuje hodnotu „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

Teraz, keď máme jedinečné ID pre každý kontakt, môžeme pole a hodnotu zmeniť na stĺpce:

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>

Záver

Môj osobný názor je, že nový koncept uprataný skutočne intuitívnejšie a vo funkčnosti výrazne lepšie ako staršie funkcie spread() и gather(). Dúfam, že vám tento článok pomohol vyrovnať sa pivot_longer() и pivot_wider().

Zdroj: hab.com

Pridať komentár