R balíček tidyr a jeho nové funkce pivot_longer a pivot_wider

Balíček pořádek součástí jádra jedné z nejpopulárnějších knihoven v jazyce R - pořádek.
Hlavním účelem balíčku je uvést data do přesné podoby.

Již k dispozici na Habré vydání věnované tomuto balíčku, ale pochází z roku 2015. A já vám chci říct o nejaktuálnějších změnách, které před pár dny oznámil její autor Hedley Wickham.

R balíček tidyr a jeho nové funkce pivot_longer a pivot_wider

SJK: Budou funkce collect() a spread() zastaralé?

Hadley Wickham: Do určité míry. Tyto funkce již nebudeme doporučovat a opravovat v nich chyby, ale v balíčku budou nadále přítomny v aktuálním stavu.

Obsah

Pokud vás zajímá analýza dat, mohla by vás zajímat moje telegram и Youtube kanály. Většina obsahu je věnována jazyku R.

Koncept TidyData

terč pořádek — pomůže vám převést data do takzvané úhledné podoby. Čistá data jsou data, kde:

  • Každá proměnná je ve sloupci.
  • Každé pozorování je řetězec.
  • Každá hodnota je buňka.

Při provádění analýzy je mnohem jednodušší a pohodlnější pracovat s daty, která jsou prezentována v čistých datech.

Hlavní funkce obsažené v balíčku tidyr

tidyr obsahuje sadu funkcí určených k transformaci tabulek:

  • fill() — doplnění chybějících hodnot ve sloupci předchozími hodnotami;
  • separate() — rozdělí jedno pole na několik pomocí oddělovače;
  • unite() — provádí operaci sloučení několika polí do jednoho, inverzní činnost funkce separate();
  • pivot_longer() — funkce, která převádí data ze širokého formátu na dlouhý;
  • pivot_wider() - funkce, která převádí data z dlouhého formátu na široký. Opačná činnost funkce, kterou provádí funkce pivot_longer().
  • gather()zastaralý — funkce, která převádí data ze širokého formátu na dlouhý;
  • spread()zastaralý - funkce, která převádí data z dlouhého formátu na široký. Opačná činnost funkce, kterou provádí funkce gather().

Nový koncept pro převod dat ze širokého na dlouhý formát a naopak

Dříve se pro tento druh transformace používaly funkce gather() и spread(). V průběhu let existence těchto funkcí se ukázalo, že pro většinu uživatelů, včetně autora balíčku, nebyly názvy těchto funkcí a jejich argumenty zcela zřejmé, což způsobilo potíže s jejich nalezením a pochopením, která z těchto funkcí převádí datumový rámeček ze širokého na dlouhý formát a naopak.

V tomto ohledu v pořádek Byly přidány dvě nové důležité funkce, které jsou určeny k transformaci rámců data.

Nové funkce pivot_longer() и pivot_wider() byly inspirovány některými funkcemi v balíčku cdata, kterou vytvořili John Mount a Nina Zumel.

Instalace nejnovější verze tidyr 0.8.3.9000

Chcete-li nainstalovat novou, nejaktuálnější verzi balíčku pořádek 0.8.3.9000, kde jsou k dispozici nové funkce, použijte následující kód.

devtools::install_github("tidyverse/tidyr")

V době psaní tohoto článku jsou tyto funkce dostupné pouze v dev verzi balíčku na GitHubu.

Přechod na nové funkce

Ve skutečnosti není těžké přenést staré skripty do práce s novými funkcemi, pro lepší pochopení vezmu příklad z dokumentace starých funkcí a ukážu, jak se stejné operace provádějí pomocí nových pivot_*() funkcí.

Převést široký formát na dlouhý formát.

Příklad kódu z dokumentace funkce shromažďování

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

Převod dlouhého formátu na široký.

Ukázkový kód z dokumentace rozprostřených funkcí

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

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

Protože ve výše uvedených příkladech práce s pivot_longer() и pivot_wider(), v původní tabulce zásoby v argumentech nejsou uvedeny žádné sloupce jmen_kom и hodnoty_k jejich jména musí být v uvozovkách.

Tabulka, která vám pomůže nejsnáze přijít na to, jak přejít na práci s novým konceptem pořádek.

R balíček tidyr a jeho nové funkce pivot_longer a pivot_wider

Poznámka od autora

Veškerý text níže je adaptivní, řekl bych dokonce volný překlad viněty z oficiálních stránek knihovny Tidyverse.

Jednoduchý příklad převodu dat z širokého na dlouhý formát

pivot_longer () — prodlužuje datové sady snížením počtu sloupců a zvýšením počtu řádků.

R balíček tidyr a jeho nové funkce pivot_longer a pivot_wider

Chcete-li spustit příklady uvedené v článku, musíte nejprve připojit potřebné balíčky:

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

Řekněme, že máme tabulku s výsledky průzkumu, který se (mimo jiné) ptal lidí na jejich náboženství a roční pří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>

Tato tabulka obsahuje údaje o náboženském vyznání respondentů v řádcích a úrovně příjmů jsou rozptýleny v názvech sloupců. Počet respondentů z každé kategorie je uložen v hodnotách buněk na křižovatce náboženství a úrovně příjmu. K uvedení tabulky do úhledného a správného formátu stačí použít 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

Funkční argumenty pivot_longer()

  • První argument sloupců, popisuje, které sloupce je třeba sloučit. V tomto případě všechny sloupce kromě čas.
  • argument jmen_kom udává název proměnné, která bude vytvořena z názvů sloupců, které jsme zřetězili.
  • hodnoty_k udává název proměnné, která bude vytvořena z dat uložených v hodnotách buněk sloučených sloupců.

Specifikace

Toto je nová funkce balíčku pořádek, který byl dříve při práci se staršími funkcemi nedostupný.

Specifikace je datový rámec, jehož každý řádek odpovídá jednomu sloupci v novém datovém rámci výstupu a dvěma speciálním sloupcům, které začínají:

  • . Název obsahuje původní název sloupce.
  • .hodnota obsahuje název sloupce, který bude obsahovat hodnoty buněk.

Zbývající sloupce specifikace odrážejí, jak bude nový sloupec zobrazovat název komprimovaných sloupců . Název.

Specifikace popisuje metadata uložená v názvu sloupce, s jedním řádkem pro každý sloupec a jedním sloupcem pro každou proměnnou, v kombinaci s názvem sloupce se tato definice může v tuto chvíli zdát matoucí, ale po zhlédnutí několika příkladů bude mnohem jasnější.

Smyslem specifikace je, že můžete načíst, upravit a definovat nová metadata pro převáděný datový rámec.

Chcete-li pracovat se specifikacemi při převodu tabulky ze širokého formátu na dlouhý formát, použijte funkci pivot_longer_spec().

Tato funkce funguje tak, že přebírá libovolný datový rámec a generuje svá metadata výše popsaným způsobem.

Jako příklad si vezměme datovou sadu who, která je součástí balíčku pořádek. Tento soubor údajů obsahuje informace poskytnuté mezinárodní zdravotnickou organizací o výskytu 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

Pojďme sestavit jeho specifikaci.

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

pole země, iso2, iso3 jsou již proměnné. Naším úkolem je obracet sloupce pomocí new_sp_m014 na newrel_f65.

Názvy těchto sloupců ukládají následující informace:

  • Předpona new_ označuje, že sloupec obsahuje údaje o nových případech tuberkulózy, aktuální datový rámec obsahuje informace pouze o nových onemocněních, takže tato předpona v aktuálním kontextu nemá žádný význam.
  • sp/rel/sp/ep popisuje způsob diagnostiky onemocnění.
  • m/f pohlaví pacienta.
  • 014/1524/2535/3544/4554/65 věkové rozmezí pacientů.

Tyto sloupce můžeme rozdělit pomocí funkce extract()pomocí regulárního 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šimněte si prosím sloupce . Název by měl zůstat nezměněn, protože toto je náš index do názvů sloupců původní datové sady.

Pohlaví a věk (sloupce rod и stáří) mají pevné a známé hodnoty, proto se doporučuje převést tyto sloupce na faktory:

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

Nakonec, abychom mohli použít specifikaci, kterou jsme vytvořili, na původní datum který musíme použít argument spec ve funkci 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še, co jsme právě udělali, lze schematicky znázornit takto:

R balíček tidyr a jeho nové funkce pivot_longer a pivot_wider

Specifikace pomocí více hodnot (.value)

Ve výše uvedeném příkladu sloupec specifikace .hodnota obsahoval pouze jednu hodnotu, ve většině případů tomu tak je.

Občas ale může nastat situace, kdy potřebujete shromáždit data ze sloupců s různými datovými typy v hodnotách. Použití starší funkce spread() to by bylo docela těžké udělat.

Níže uvedený příklad je převzat z viněty do balíčku datová tabulka.

Vytvořme tréninkový datový 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

Vytvořený datový rámec obsahuje v každém řádku údaje o dětech jedné rodiny. Rodiny mohou mít jedno nebo dvě děti. U každého dítěte jsou uvedeny údaje o datu narození a pohlaví a údaje pro každé dítě jsou v samostatných sloupcích, naším úkolem je uvést tato data do správného formátu pro analýzu.

Upozorňujeme, že máme dvě proměnné s informacemi o každém dítěti: jeho pohlaví a datum narození (sloupce s předponou Křest obsahují datum narození, sloupce s předponou rod obsahovat pohlaví dítěte). Očekávaným výsledkem je, že by se měly objevit v samostatných sloupcích. Můžeme to udělat vygenerováním specifikace, ve které je sloupec .value bude mít dva různé 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

Pojďme se tedy krok za krokem podívat na akce prováděné výše uvedeným kódem.

  • pivot_longer_spec(-family) — vytvořit specifikaci, která komprimuje všechny existující sloupce kromě sloupce rodiny.
  • separate(col = name, into = c(".value", "child")) - rozdělit sloupec . Název, který obsahuje názvy zdrojových polí, pomocí podtržítka a zadáním výsledných hodnot do sloupců .hodnota и dítě.
  • mutate(child = parse_number(child)) — transformovat hodnoty pole dítě z textového na číselný datový typ.

Nyní můžeme výslednou specifikaci aplikovat na původní dataframe a převést tabulku do požadované 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žíváme argument na.rm = TRUE, protože současná podoba dat si vynucuje vytváření dalších řádků pro neexistující pozorování. Protože rodina 2 má pouze jedno dítě, na.rm = TRUE zaručuje, že rodina 2 bude mít na výstupu jeden řádek.

Převod datových snímků z dlouhého na široký formát

pivot_wider() - je inverzní transformace a naopak zvyšuje počet sloupců rámce data snížením počtu řádků.

R balíček tidyr a jeho nové funkce pivot_longer a pivot_wider

Tento druh transformace se k převedení dat do přesné podoby používá velmi zřídka, nicméně tato technika může být užitečná pro vytváření kontingenčních tabulek používaných v prezentacích nebo pro integraci s některými dalšími nástroji.

Vlastně funkce pivot_longer() и pivot_wider() jsou symetrické a vytvářejí vzájemně inverzní akce, tj. df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) vrátí původní df.

Nejjednodušší příklad převodu tabulky do širokého formátu

Ukázat, jak funkce funguje pivot_wider() použijeme datovou sadu rybí_setkání, která uchovává informace o tom, jak různé stanice zaznamenávají pohyb ryb po řece.

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

Ve většině případů bude tato tabulka informativnější a snáze použitelná, pokud uvedete informace pro každou stanici v samostatném sloupci.

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>

Tato datová sada zaznamenává informace pouze tehdy, když byly ryby detekovány stanicí, tzn. pokud některá stanice nezaznamenala nějakou rybu, tak tento údaj v tabulce nebude. To znamená, že výstup bude naplněn NA.

V tomto případě však víme, že absence záznamu znamená, že ryba nebyla viděna, takže můžeme použít argument value_fill ve funkci pivot_wider() a doplňte tyto chybějící 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>

Generování názvu sloupce z více zdrojových proměnných

Představte si, že máme tabulku obsahující kombinaci produktu, země a roku. Chcete-li vygenerovat testovací datový rámec, můžete spustit následující 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ším úkolem je rozšířit datový rámec tak, aby jeden sloupec obsahoval data pro každou kombinaci produktu a země. Chcete-li to provést, stačí předat argument jména_od vektor obsahující názvy polí, která mají být sloučena.

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 funkci můžete také použít specifikace pivot_wider(). Ale když se podrobí pivot_wider() specifikace provádí opačnou konverzi pivot_longer(): Sloupce uvedené v . Názevpomocí hodnot z .hodnota a další sloupce.

Pro tuto datovou sadu můžete vygenerovat vlastní specifikaci, pokud chcete, aby každá možná kombinace zemí a produktů měla svůj vlastní sloupec, nejen ty, které jsou v datech:

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

Několik pokročilých příkladů práce s novým konceptem tidyr

Vyčištění dat pomocí datové sady US Census Income and Rent jako příkladu.

Soubor dat příjem_z_nájmu obsahuje informace o středních příjmech a nájemném pro každý stát v USA za rok 2017 (soubor dat je k dispozici v balíčku pořádek).

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

Ve formě, ve které jsou data uložena v datové sadě příjem_z_nájmu práce s nimi je extrémně nepohodlná, proto bychom chtěli vytvořit datovou sadu se sloupci: pronajmout, rent_moe, Přijít, příjem_moe. Existuje mnoho způsobů, jak vytvořit tuto specifikaci, ale hlavním bodem je, že musíme vygenerovat každou kombinaci hodnot proměnných a odhad/moea poté vygenerujte název sloupce.

  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

Poskytnutí této specifikace pivot_wider() nám dává výsledek, který hledá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

Světová banka

Převedení datové sady do požadované podoby někdy vyžaduje několik kroků.
Dataset world_bank_pop obsahuje údaje Světové banky o počtu obyvatel jednotlivých zemí v letech 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 cílem je vytvořit úhlednou sadu dat s každou proměnnou ve vlastním sloupci. Není přesně jasné, jaké kroky jsou vyžadovány, ale začneme nejzjevnějším problémem: rok je rozložen do několika sloupců.

Chcete-li to opravit, musíte použít funkci 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

Dalším krokem je podívat se na proměnnou indikátoru.
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 populační růst, SP.POP.TOTL je celkový počet obyvatel a SP.URB. * totéž, ale pouze pro městské oblasti. Rozdělme tyto hodnoty do dvou proměnných: plocha - plocha (celková nebo městská) a proměnná obsahující skutečná data (počet obyvatel nebo růst):

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

Nyní vše, co musíme udělat, je rozdělit proměnnou do dvou sloupců:

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

Seznam kontaktů

Jeden poslední příklad, představte si, že máte seznam kontaktů, který jste zkopírovali a vložili z webové stránky:

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

Tabulování tohoto seznamu je poměrně obtížné, protože neexistuje žádná proměnná, která by identifikovala, která data patří ke kterému kontaktu. Můžeme to opravit tím, že si všimneme, že data každého nového kontaktu začínají „jménem“, takže můžeme vytvořit jedinečný identifikátor a zvýšit jej o jednu pokaždé, když sloupec pole 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

Nyní, když máme pro každý kontakt jedinečné ID, můžeme pole a hodnotu převést na sloupce:

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ávěr

Můj osobní názor je, že nový koncept pořádek skutečně intuitivnější a ve funkčnosti výrazně lepší než starší funkce spread() и gather(). Doufám, že vám tento článek pomohl se s tím vypořádat pivot_longer() и pivot_wider().

Zdroj: www.habr.com

Přidat komentář