R csomag tidyr és új funkciói pivot_longer és pivot_wider

csomag tidyr az egyik legnépszerűbb R nyelvű könyvtár magjában található - rendezett változat.
A csomag fő célja az adatok pontos formába hozása.

Már elérhető a Habrén kiadvány ennek a csomagnak szentelték, de 2015-ig nyúlik vissza. És a legfrissebb változásokról szeretnék mesélni, amelyeket néhány napja jelentett be szerzője, Hedley Wickham.

R csomag tidyr és új funkciói pivot_longer és pivot_wider

SJK: A collect() and spread() elavult lesz?

Hadley Wickham: Bizonyos mértékig. A továbbiakban nem javasoljuk ezeknek a funkcióknak a használatát és a bennük lévő hibák javítását, de a jelenlegi állapotukban továbbra is jelen lesznek a csomagban.

Tartalom

Ha érdekel az adatelemzés, akkor az én oldalam is érdekelheti távirat и youtube csatornák. A tartalom nagy része az R nyelvnek szól.

TidyData koncepció

Gól tidyr — segít az adatok úgynevezett tiszta formába hozásában. A tiszta adat olyan adat, ahol:

  • Minden változó egy oszlopban van.
  • Minden megfigyelés egy karakterlánc.
  • Minden érték egy cella.

Az elemzés során sokkal könnyebb és kényelmesebb azokkal az adatokkal dolgozni, amelyek rendezett adatokban jelennek meg.

A tidyr csomagban található fő funkciók

A tidyr a táblázatok átalakítására tervezett függvénykészletet tartalmaz:

  • fill() - hiányzó értékek kitöltése egy oszlopban korábbi értékekkel;
  • separate() — egy mezőt több részre oszt fel elválasztó segítségével;
  • unite() — végrehajtja a több mező egyesítésének műveletét, a függvény fordított műveletét separate();
  • pivot_longer() — egy funkció, amely az adatokat széles formátumról hosszú formátumra konvertálja;
  • pivot_wider() - olyan funkció, amely az adatokat hosszú formátumról széles formátumra konvertálja. A függvény által végrehajtott fordított művelete pivot_longer().
  • gather()elavult — egy funkció, amely az adatokat széles formátumról hosszú formátumra konvertálja;
  • spread()elavult - olyan funkció, amely az adatokat hosszú formátumról széles formátumra konvertálja. A függvény által végrehajtott fordított művelete gather().

Új koncepció az adatok széles formátumról hosszú formátumba konvertálására és fordítva

Korábban függvényeket használtak az ilyen típusú átalakításokhoz gather() и spread(). E függvények fennállásának évei során nyilvánvalóvá vált, hogy a legtöbb felhasználó számára, beleértve a csomag szerzőjét is, ezeknek a függvényeknek a neve és az érveik nem voltak egészen nyilvánvalóak, és nehézségeket okoztak megtalálásukban és annak megértésében, hogy ezek közül melyik függvény konvertál dátumkeret széles formátumtól hosszú formátumig, és fordítva.

Ebben a tekintetben ben tidyr Két új, fontos funkció került hozzáadásra, amelyek a dátumkeretek átalakítására szolgálnak.

Új funkciók pivot_longer() и pivot_wider() a csomag egyes funkciói ihlették cdata, amelyet John Mount és Nina Zumel készített.

A tidyr 0.8.3.9000 legújabb verziójának telepítése

A csomag új, legfrissebb verziójának telepítéséhez tidyr 0.8.3.9000, ahol új funkciók állnak rendelkezésre, használja a következő kódot.

devtools::install_github("tidyverse/tidyr")

A cikk írásakor ezek a funkciók csak a csomag fejlesztői verziójában érhetők el a GitHubon.

Áttérés új funkciókra

Valójában nem nehéz átvinni a régi szkripteket, hogy új funkciókkal dolgozzanak, a jobb megértés érdekében példát veszek a régi függvények dokumentációjából, és megmutatom, hogyan hajtják végre ugyanazokat a műveleteket új funkciókkal pivot_*() funkciókat.

Konvertálja a széles formátumot hosszú formátumba.

Példakód a gyűjtési függvény dokumentációjából

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

Hosszú formátum konvertálása széles formátumba.

Példakód a spread függvény dokumentációjából

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

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

Mert a fenti példákban pivot_longer() и pivot_wider(), az eredeti táblázatban készletek nincsenek oszlopok az argumentumokban names_to и értékek_hoz a nevüket idézőjelbe kell tenni.

Egy táblázat, amely segít a legkönnyebben kitalálni, hogyan válthat át egy új koncepcióval való munkavégzésre tidyr.

R csomag tidyr és új funkciói pivot_longer és pivot_wider

Megjegyzés a szerzőtől

Az összes alábbi szöveg adaptív, akár szabad fordításnak is mondanám matricák a tidyverse könyvtár hivatalos weboldaláról.

Egy egyszerű példa az adatok széles formátumból hosszú formátumba konvertálására

pivot_longer () — meghosszabbítja az adatkészleteket az oszlopok számának csökkentésével és a sorok számának növelésével.

R csomag tidyr és új funkciói pivot_longer és pivot_wider

A cikkben bemutatott példák futtatásához először csatlakoztatnia kell a szükséges csomagokat:

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

Tegyük fel, hogy van egy táblázatunk egy felmérés eredményeivel, amelyben (többek között) megkérdezték az embereket a vallásukról és az éves jövedelmükről:

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

Ez a táblázat sorokban tartalmazza a válaszadók vallási adatait, a jövedelmi szintek pedig az oszlopnevek között vannak elszórva. Az egyes kategóriák válaszadóinak számát a cellaértékek tárolják a vallás és a jövedelmi szint metszéspontjában. Ahhoz, hogy a táblázatot szép, helyes formátumba hozzuk, elegendő használni 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

A függvény argumentumai pivot_longer()

  • Első érv nyakörvek, leírja, hogy mely oszlopokat kell egyesíteni. Ebben az esetben az összes oszlop, kivéve idő.
  • Érv names_to megadja annak a változónak a nevét, amely az általunk összefűzött oszlopok nevéből jön létre.
  • értékek_hoz annak a változónak a nevét adja meg, amely az egyesített oszlopok celláinak értékeiben tárolt adatokból jön létre.

Műszaki adatok

Ez a csomag új funkciója tidyr, amely korábban nem volt elérhető, ha örökölt funkciókkal dolgozott.

A specifikáció egy adatkeret, amelynek minden sora az új kimeneti dátumkeret egy oszlopának, valamint két speciális oszlopnak felel meg, amelyek a következőkkel kezdődnek:

  • . Név tartalmazza az eredeti oszlopnevet.
  • .érték tartalmazza a cellaértékeket tartalmazó oszlop nevét.

A specifikáció többi oszlopa azt tükrözi, hogy az új oszlop hogyan jeleníti meg a tömörített oszlopok nevét . Név.

A specifikáció leírja az oszlopnévben tárolt metaadatokat, oszloponként egy sorral és változónként egy oszloppal, az oszlopnévvel kombinálva, ez a meghatározás pillanatnyilag zavarónak tűnhet, de néhány példa után sok lesz. világosabb.

A specifikáció lényege, hogy lekérheti, módosíthatja és új metaadatokat határozhat meg a konvertálandó adatkerethez.

Ha egy táblázatot széles formátumról hosszú formátumra konvertál, használja a függvényt a specifikációk használatához pivot_longer_spec().

Ez a függvény az, hogy bármilyen dátumkeretet felvesz, és a fent leírt módon generálja a metaadatait.

Példaként vegyük a csomaghoz mellékelt who adatkészletet tidyr. Ez az adatkészlet a Nemzetközi Egészségügyi Szervezet által szolgáltatott információkat tartalmaz a tuberkulózis előfordulásáról.

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

Építsük fel a specifikációját.

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

mezők ország, isoxnumx, isoxnumx már változók. A mi feladatunk az oszlopok lapozása new_sp_m014 on newrel_f65.

Ezen oszlopok nevei a következő információkat tárolják:

  • Előtag new_ azt jelzi, hogy az oszlop az új tuberkulózisos esetek adatait tartalmazza, az aktuális dátumkeret csak az új betegségekről tartalmaz információkat, így ennek az előtagnak a jelenlegi kontextusban nincs jelentősége.
  • sp/rel/sp/ep egy betegség diagnosztizálásának módszerét írja le.
  • m/f a beteg neme.
  • 014/1524/2535/3544/4554/65 beteg életkora.

Ezeket az oszlopokat a függvény segítségével feloszthatjuk extract()reguláris kifejezés használatával.

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

Kérjük, vegye figyelembe az oszlopot . Név változatlannak kell maradnia, mivel ez az indexünk az eredeti adatkészlet oszlopneveiben.

Nem és életkor (oszlopok nemek и kor) rögzített és ismert értékei vannak, ezért ajánlatos ezeket az oszlopokat tényezőkké alakítani:

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

Végül annak érdekében, hogy az általunk létrehozott specifikációt az eredeti dátumkeretre alkalmazzuk akik érvet kell használnunk spec funkcióban 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

Mindaz, amit az imént tettünk, sematikusan a következőképpen ábrázolható:

R csomag tidyr és új funkciói pivot_longer és pivot_wider

Több értéket használó specifikáció (.value)

A fenti példában a specifikáció oszlop .érték csak egy értéket tartalmazott, a legtöbb esetben ez a helyzet.

Időnként azonban olyan helyzet adódhat, amikor adatokat kell gyűjtenie olyan oszlopokból, amelyekben különböző adattípusok vannak. Egy örökölt függvény használata spread() ezt elég nehéz lenne megtenni.

Az alábbi példa innen származik matricák a csomaghoz adattábla.

Hozzunk létre egy képzési adatkeretet.

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

A létrehozott dátumkeret soronként egy család gyermekeinek adatait tartalmazza. A családoknak lehet egy vagy két gyermeke. Gyermekenként megadjuk a születési dátumot és a nemet, az adatok külön oszlopban szerepelnek, a mi feladatunk, hogy ezeket az adatokat a megfelelő formátumba hozzuk elemzésre.

Felhívjuk figyelmét, hogy két változónk van minden gyermekről információval: a nemük és a születési dátumuk (az oszlopok az előtaggal Keresztség születési dátumot, előtaggal ellátott oszlopokat tartalmaznak nemek tartalmazza a gyermek nemét). A várható eredmény az, hogy külön oszlopokban jelenjenek meg. Ezt megtehetjük egy olyan specifikáció generálásával, amelyben az oszlop .value két különböző jelentése lesz.

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

Tehát nézzük meg lépésről lépésre a fenti kód által végrehajtott műveleteket.

  • pivot_longer_spec(-family) — hozzon létre egy olyan specifikációt, amely a család oszlop kivételével az összes létező oszlopot tömöríti.
  • separate(col = name, into = c(".value", "child")) - osztja szét az oszlopot . Név, amely tartalmazza a forrásmezők nevét, aláhúzásjellel és a kapott értékeket az oszlopokba beírva .érték и gyermek.
  • mutate(child = parse_number(child)) — átalakítja a mezőértékeket gyermek szövegtől numerikus adattípusig.

Most alkalmazhatjuk a kapott specifikációt az eredeti adatkeretre, és a táblázatot a kívánt formába hozhatjuk.

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

Érveket használunk na.rm = TRUE, mert az adatok jelenlegi formája extra sorok létrehozását kényszeríti a nem létező megfigyelésekhez. Mert a 2-es családnak csak egy gyermeke van, na.rm = TRUE garantálja, hogy a 2. családnak egy sora lesz a kimenetben.

Dátumkeretek átalakítása hosszúról széles formátumra

pivot_wider() - az inverz transzformáció, és fordítva a sorok számának csökkentésével növeli a dátumkeret oszlopainak számát.

R csomag tidyr és új funkciói pivot_longer és pivot_wider

Ezt a fajta átalakítást rendkívül ritkán alkalmazzák az adatok pontos formába hozására, azonban ez a technika hasznos lehet prezentációkban használt pivot táblák létrehozásához, vagy más eszközökkel való integrációhoz.

Valójában a funkciókat pivot_longer() и pivot_wider() szimmetrikusak, és egymáshoz képest fordított cselekvéseket hoznak létre, azaz: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) visszaadja az eredeti df-et.

A legegyszerűbb példa egy táblázat széles formátumba konvertálására

A funkció működésének bemutatása pivot_wider() az adatkészletet fogjuk használni hal_találkozások, amely információkat tárol arról, hogy a különböző állomások hogyan rögzítik a halak folyó menti mozgását.

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

A legtöbb esetben ez a táblázat informatívabb és könnyebben használható, ha az egyes állomásokra vonatkozó információkat külön oszlopban jeleníti meg.

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>

Ez az adatkészlet csak akkor rögzít információkat, ha az állomás halat észlelt, pl. Ha valamelyik állomás nem rögzített egy halat, akkor ezek az adatok nem fognak szerepelni a táblázatban. Ez azt jelenti, hogy a kimenet tele lesz NA-val.

Ebben az esetben azonban tudjuk, hogy a rekord hiánya azt jelenti, hogy a halat nem látták, így használhatjuk az érvelést értékek_kitöltése funkcióban pivot_wider() és töltse ki a hiányzó értékeket nullákkal:

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>

Oszlopnév generálása több forrásváltozóból

Képzelje el, hogy van egy táblázatunk, amely a termék, ország és év kombinációját tartalmazza. Tesztdátumkeret létrehozásához futtassa a következő kódot:

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

Feladatunk az adatkeret kibővítése úgy, hogy egy-egy oszlop tartalmazza a termék- és országkombinációra vonatkozó adatokat. Ehhez csak adja át az érvet nevek_tól az összevonandó mezők nevét tartalmazó vektor.

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

Specifikációkat is alkalmazhat egy függvényre pivot_wider(). De amikor alávetik pivot_wider() a specifikáció az ellenkező átalakítást hajtja végre pivot_longer(): A megadott oszlopok . Név, innen származó értékeket használva .érték és egyéb oszlopok.

Ehhez az adatkészlethez egyéni specifikációt hozhat létre, ha azt szeretné, hogy minden lehetséges ország- és termékkombinációnak legyen saját oszlopa, ne csak az adatokban szereplőknek:

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

Számos fejlett példa az új tidyr koncepcióval való munkavégzésre

Adatok törlése az Egyesült Államok népszámlálási bevételei és bérleti díjai adatkészletének példáján.

Adatkészlet us_bérleti_jövedelem mediánjövedelemre és bérleti díjra vonatkozó információkat tartalmaz az Egyesült Államok minden államára vonatkozóan 2017-ben (az adatkészlet a csomagban elérhető 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

Abban a formában, ahogyan az adatokat az adatkészletben tárolják us_bérleti_jövedelem a velük való munka rendkívül kényelmetlen, ezért szeretnénk létrehozni egy oszlopos adathalmazt: bérlés, rent_moe, hogyan, jövedelem_pénz. Számos módja van ennek a specifikációnak a létrehozására, de a lényeg az, hogy létre kell hoznunk a változóértékek és a változóértékek minden kombinációját. becslés/moemajd generálja az oszlop nevét.

  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

Ennek a specifikációnak a megadása pivot_wider() a keresett eredményt adja:

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

A Világbank

Néha egy adathalmaz kívánt formába hozása több lépést igényel.
Adatkészlet world_bank_pop Világbanki adatokat tartalmaz az egyes országok 2000 és 2018 közötti népességéről.

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

Célunk egy tiszta adathalmaz létrehozása, amelyben minden változó a saját oszlopában található. Nem világos, hogy pontosan milyen lépésekre van szükség, de kezdjük a legnyilvánvalóbb problémával: az évszám több oszlopra oszlik.

Ennek kijavításához a funkciót kell használni 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

A következő lépés az indikátorváltozó megtekintése.
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

Ahol SP.POP.GROW a népességnövekedés, SP.POP.TOTL a teljes népesség, és SP.URB. * ugyanaz, de csak városi területekre. Osszuk ezeket az értékeket két változóra: terület - terület (teljes vagy városi) és egy tényleges adatokat tartalmazó változó (népesség vagy növekedés):

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

Most már csak annyit kell tennünk, hogy a változót két oszlopra osztjuk:

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

Névjegyzék

Egy utolsó példa, képzeljük el, hogy van egy névjegyzéke, amelyet egy webhelyről másolt és illeszt be:

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

Ennek a listának a táblázatba foglalása meglehetősen nehéz, mert nincs olyan változó, amely azonosítaná, hogy melyik kapcsolathoz melyik adat tartozik. Ezt úgy javíthatjuk, hogy megjegyezzük, hogy minden új kapcsolattartó adata "névvel" kezdődik, így létrehozhatunk egy egyedi azonosítót, és minden alkalommal növelhetjük azt eggyel, amikor a mezőoszlop a "name" értéket tartalmazza:

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

Most, hogy minden kapcsolathoz egyedi azonosítóval rendelkezünk, a mezőt és az értéket oszlopokká alakíthatjuk:

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>

Következtetés

Személyes véleményem az, hogy az új koncepció tidyr valóban intuitívabb, és funkcionalitásában jelentősen felülmúlja a régi funkciókat spread() и gather(). Remélem, ez a cikk segített megbirkózni pivot_longer() и pivot_wider().

Forrás: will.com

Hozzászólás