R-paketet tidyr och dess nya funktioner pivot_longer och pivot_wider

Paket tidyr ingĂ„r i kĂ€rnan av ett av de mest populĂ€ra biblioteken pĂ„ sprĂ„ket R — tidyverse.
Huvudsyftet med paketet Àr att ge data ett ordnat utseende.

Det finns redan en artikel pÄ Habré publicering dedikerad till detta paket, men den dateras till 2015. Jag vill berÀtta om de mest aktuella förÀndringarna som dess skapare Hadley Wickham meddelade för nÄgra dagar sedan.

R-paketet tidyr och dess nya funktioner pivot_longer och pivot_wider

SJK: Kommer funktionerna gather() och spread() att betraktas som förÄldrade?

Hadley Wickham: I viss mÄn. Vi kommer att sluta rekommendera anvÀndningen av dessa funktioner och rÀtta till fel i dem, men de kommer fortfarande att finnas kvar i paketet i nuvarande tillstÄnd.

InnehÄll

Om du Àr intresserad av dataanalys kan du vara intresserad av mina telegram och YouTube kanaler vara av intresse. Största delen av innehÄllet Àgnas Ät sprÄket R.

Konceptet TidyData

Syftet tidyr — hjĂ€lpa dig att ge data ett sĂ„ kallat ordnat utseende. Ordnade data Ă€r data dĂ€r:

  • Varje variabel finns i en kolumn.
  • Varje observation Ă€r en rad.
  • Varje vĂ€rde Ă€r en cell.

Med data som har anpassats till tidy data Àr det mycket enklare och bekvÀmare att arbeta med under analys.

Huvudfunktionerna i paketet tidyr

tidyr innehÄller ett set av funktioner avsedda för att transformera tabeller:

  • fill() — fylla i saknade vĂ€rden i en kolumn med föregĂ„ende vĂ€rden;
  • separate() — delar ett fĂ€lt i flera med en avgrĂ€nsare;
  • unite() — gör en operation som förenar flera fĂ€lt till ett, motsatsen till funktionen separate();
  • pivot_longer() — en funktion som omvandlar data frĂ„n brett format till lĂ„ngt;
  • pivot_wider() — en funktion som omvandlar data frĂ„n lĂ„ngt format till brett. Denna operation Ă€r motsatsen till den som utförs av funktionen pivot_longer().
  • gather()förĂ„ldrad — en funktion som omvandlar data frĂ„n brett format till lĂ„ngt;
  • spread()förĂ„ldrad — en funktion som omvandlar data frĂ„n lĂ„ngt format till brett. Denna operation Ă€r motsatsen till den som utförs av funktionen gather().

Ett nytt koncept för att omvandla data frÄn brett format till lÄngt och vice versa

Tidigare anvÀnde man funktioner för liknande transformationer gather() och spread(). Med Ären har det blivit uppenbart att namnen pÄ dessa funktioner och deras argument var otydliga för de flesta anvÀndare, inklusive paketets skapare, vilket ledde till svÄrigheter att hitta och förstÄ vilken av dessa funktioner som omvandlar en data ram frÄn brett till lÄngt format, och vice versa.

DÀrför tidyr har tvÄ nya, viktiga funktioner lagts till

De nya funktionerna pivot_longer() och pivot_wider() har skapats under intryck av vissa funktioner frÄn paketet cdata, skapad av John Mount och Nina Zumel.

Installera den mest aktuella versionen av tidyr 0.8.3.9000

För att installera den senaste versionen av paketet tidyr 0.8.3.9000, dÀr de nya funktionerna Àr tillgÀngliga, anvÀnd följande kod.

devtools::install_github("tidyverse/tidyr")

Vid tidpunkten för artikelskrivandet Àr dessa funktioner endast tillgÀngliga i dev-versionen av paketet pÄ GitHub.

ÖvergĂ„ng till nya funktioner

Att faktiskt översÀtta gamla skript till att anvÀnda de nya funktionerna Àr inte svÄrt; för att förstÄ bÀttre tar jag ett exempel frÄn dokumentationen av de gamla funktionerna och visar hur dessa operationer utförs med hjÀlp av de nya pivot_*() funktionerna.

Omvandling frÄn brett format till lÄngt.

Kodexempel frÄn dokumentationen för funktionen gather

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

Omvandling frÄn lÄngt format till brett.

Kodexempel frÄn dokumentationen för funktionen spread

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

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

Eftersom i de ovan nÀmnda exemplen med pivot_longer() och pivot_wider(), i den ursprungliga tabellen stocks finns det inga kolumner som nÀmns i argumenten names_to och values_to mÄste deras namn anges inom citationstecken.

Tabellen som hjÀlper dig att enklast förstÄ hur man gÄr över till att arbeta med det nya konceptet tidyr.

R-paketet tidyr och dess nya funktioner pivot_longer och pivot_wider

Anteckning frÄn författaren

All vidare text Àr en anpassad, jag skulle till och med sÀga fri översÀttning av vignetterna frÄn den officiella webbplatsen för biblioteket tidyverse.

Ett enkelt exempel pÄ att omvandla data frÄn brett format till lÄngt

pivot_longer () gör datamÀngder lÀngre, minskar antalet kolumner och ökar antalet rader.

R-paketet tidyr och dess nya funktioner pivot_longer och pivot_wider

För att utföra exemplen i artikeln mÄste de nödvÀndiga paketen initially laddas:

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

Anta att vi har en tabell med resultaten frÄn en undersökning dÀr (bland annat) mÀnniskor tillfrÄgades om sin religion och sin Ärliga inkomst:

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

Den hÀr tabellen innehÄller data om respondenternas religioner i raderna, medan inkomstnivÄn sprids över kolumnnamnen. Antalet respondenter frÄn varje kategori lagras i vÀrdena i cellerna vid skÀrningspunkten mellan religion och inkomstnivÄ. För att fÄ tabellen i ett snyggt, korrekt format rÀcker det att anvÀnda pivot_longer():

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

pew %>% 
  pivot_longer(cols = -religion, names_to = "income", values_to = "count")
#> # En tibble: 180 x 3
#>    religion income             count
#>                      
#>  1 Agnostiker   2 Agnostiker $10-20k               34
#>  3 Agnostiker $20-30k               60
#>  4 Agnostiker $30-40k               81
#>  5 Agnostiker $40-50k               76
#>  6 Agnostiker $50-75k              137
#>  7 Agnostiker $75-100k             122
#>  8 Agnostiker $100-150k            109
#>  9 Agnostiker >150k                 84
#> 10 Agnostiker Vet inte/avstÄtt    96
#> # 
 med 170 fler rader

Argumenten för funktionen pivot_longer()

  • Det första argumentet cols, beskriver vilka kolumner som ska slĂ„s samman. I detta fall alla kolumner förutom time.
  • Argumentet names_to namnger variabeln som kommer att skapas frĂ„n kolumnnamnen vi har slagit samman.
  • values_to namnger variabeln som kommer att skapas frĂ„n de vĂ€rden som finns i cellerna i de sammanfogade kolumnerna.

Specifikationer

Detta Àr en ny funktionalitet i paketet tidyr, som tidigare var otillgÀnglig nÀr man anvÀnde de förÄldrade funktionerna.

Specifikation Àr ett dataram, dÀr varje rad motsvarar en kolumn i den nya utdata-dataramen och tvÄ specialkolumner som börjar med:

  • .*.namn innehĂ„ller det ursprungliga kolumnnamnet.
  • .value innehĂ„ller namnet pĂ„ kolumnen som vĂ€rdena i cellerna kommer att gĂ„ in i.

De övriga kolumnerna i specifikationen Äterspeglar hur titeln pÄ de komprimerade kolumnerna kommer att presenteras i den nya kolumnen. .*.namn.

Specifikationen beskriver metadata lagrad i kolumnnamnet, med en rad för varje kolumn och en kolumn för varje variabel som har sammanfogats med kolumnnamnet. Just nu kanske den definitionen verkar förvirrande, men efter att ha granskat ett par exempel kommer det bli mycket tydligare.

Syftet med specifikationen Àr att du kan extrahera, Àndra och sÀtta nya metadata till den transformerade dataram.

För att arbeta med specifikationerna vid omvandlingen av en tabell frÄn brett format till lÄngt format anvÀnds funktionen pivot_longer_spec().

Hur denna funktion fungerar Àr att den tar vilken dataram som helst och formar dess metadata pÄ det sÀtt som beskrivits ovan.

För att ge ett exempel kan vi ta datasetet who, som tillhandahÄlls med paketet tidyr. Denna dataset innehÄller information frÄn VÀrldshÀlsoorganisationen om tuberkulosfall.

who
#># A tibble: 7,240 x 60
#>#    country iso2  iso3   year new_sp_m014 new_sp_m1524 new_sp_m2534
#>#        &                        
#>#  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
#># # 
 med 7,230 fler rader och 53 fler variabler

Vi bygger dess specifikation.

spec %
  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

FÀlt land, iso2, iso3 Àr redan variabler. VÄr uppgift Àr att vÀnda kolumnerna med new_sp_m014 per newrel_f65.

I namnen pÄ dessa kolumner lagras följande information:

  • Prefix new_ indikerar att kolumnen innehĂ„ller data om nya tuberkulosfall; den aktuella dataframen innehĂ„ller information endast om nya fall, sĂ„ detta prefix har ingen meningsfull betydelse i nuvarande sammanhang.
  • sp/rel/sp/ep beskriver diagnosmetoden.
  • m/f patientens kön.
  • 014/1524/2535/3544/4554/65 patientens Ă„ldersintervall.

Vi kan dela dessa kolumner med funktionen extract(), med hjÀlp av reguljÀra uttryck.

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

Observera att kolumnen .*.namn ska förbli oförÀndrad, eftersom det Àr vÄr index i kolumnnamnen i den ursprungliga datasetet.

Kön och Älder (kolumnerna gender och age) har fasta och kÀnda vÀrden, sÄ det rekommenderas att omvandla dessa kolumner till faktorer:

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

Slutligen, för att tillÀmpa den specifikation vi har skapat pÄ den ursprungliga dataframen who mÄste vi anvÀnda argumentet spec i funktionen 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

Allt vi just gjort kan schematiskt representeras sÄ hÀr:

R-paketet tidyr och dess nya funktioner pivot_longer och pivot_wider

Specifikation med flera vÀrden (.value)

I det ovanstÄende exemplet representeras specifikationskolumnen .value innehöll bara ett vÀrde, vilket oftast Àr fallet.

Men ibland kan det uppstÄ en situation dÀr du behöver samla in data frÄn kolumner med olika datatyper. Med hjÀlp av den förÄldrade funktionen spread() skulle det vara ganska svÄrt att göra.

Exemplet nedan Àr hÀmtat frÄn vignetterna paketet data.table.

LÄt oss skapa en trÀningsdataframe.

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

Den skapade dataframet innehÄller pÄ varje rad uppgifter om barnen i en familj. Familjer kan ha ett eller tvÄ barn. För varje barn tillhandahÄlls data om födelsedatum och kön, dÀr uppgifterna för varje barn kommer i separata kolumner. VÄr uppgift Àr att fÄ dessa data i rÀtt format för analys.

Observera att vi har tvÄ variabler med information om varje barn: deras kön och födelsedatum (kolumner med prefixet dob innehÄller födelsedatum, kolumner med prefixet gender innehÄller barnets kön). I det förvÀntade resultatet ska de komma i separata kolumner. Vi kan göra detta genom att generera en specifikation dÀr kolumnen .value kommer att ha tvÄ olika vÀrden.

spec %
  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

SÄ lÄt oss gÄ igenom stegen som utförs av ovanstÄende kod.

  • pivot_longer_spec(-family) — vi skapar en specifikation som komprimerar alla existerande kolumner förutom kolumnen family.
  • separate(col = name, into = c(".value", "child")) — vi separerar kolumnen .*.namn, som innehĂ„ller namnen pĂ„ de ursprungliga fĂ€lten, baserat pĂ„ understreck och placerar de erhĂ„llna vĂ€rdena i kolumnerna .value och child.
  • mutate(child = parse_number(child)) — vi omvandlar vĂ€rdena i fĂ€ltet child frĂ„n textuell till numerisk datatyp.

Nu kan vi applicera den erhÄllna specifikationen pÄ den ursprungliga dataframen för att fÄ tabellen i önskat format.

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

Vi anvÀnder argumentet na.rm = TRUE, eftersom den nuvarande datan tvingar oss att skapa överflödiga rader för saknade observationer. Eftersom familj 2 har endast ett barn, na.rm = TRUE garanterar att familj 2 kommer att ha en rad i utdata.

Omvandla dataframes frÄn lÄngt format till brett

pivot_wider() – Ă€r en omvĂ€nd transformation och ökar antalet kolumner i dataframen genom att minska antalet rader.

R-paketet tidyr och dess nya funktioner pivot_longer och pivot_wider

Denna typ av transformation anvÀnds sÀllan för att strukturera data, men detta tillvÀgagÄngssÀtt kan vara anvÀndbart för att skapa sammanfattningstabeller som anvÀnds i presentationer, eller för integration med andra verktyg.

I sjÀlva verket Àr funktionerna pivot_longer() och pivot_wider() symmetriska och utför motsatta ÄtgÀrder, dvs: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) och df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) ÄterstÀller den ursprungliga df.

Det enklaste exemplet pÄ att omvandla en tabell till brett format

För att demonstrera funktionen pivot_wider() kommer vi att anvÀnda datasetet fish_encounters, som innehÄller information om hur olika stationer registrerar fiskars rörelser i floden.

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

I de flesta fall kommer denna tabell att vara mer informativ och anvÀndbar om informationen presenteras per station i separata kolumner.

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

fish_encounters %>% pivot_wider(names_from = station, values_from = seen)
#> # En tibble: 19 x 12
#>    fisk  Frigivning I80_1 Lissabon  Rstr Bas_TD   BCE   BCW  BCE2  BCW2   MAE
#>        &;            
#>  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
#> # 
 med 9 fler rader och 1 fler variabel: MAW

Detta dataset registrerar information endast i de fall dÀr fisken har upptÀckts av stationen, dvs. om nÄgon fisk inte har registrerats av nÄgon station, sÄ kommer denna data inte att finnas i tabellen. Detta innebÀr att utdata kommer att fyllas med NA.

Men i detta fall vet vi att frÄnvaron av en post betyder att fisken inte har setts, sÄ vi kan anvÀnda argumentet values_fill i funktionen pivot_wider() och fylla dessa saknade vÀrden med nollor:

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>

Generering av kolumnnamn frÄn flera ursprungliga variabler

TÀnk dig att vi har en tabell som innehÄller en kombination av produkter, lÀnder och Är. För att generera ett testdataframe kan vi köra följande kod:

df %
  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

VÄr uppgift Àr att utvidga dataframe sÄ att en kolumn innehÄller data för varje kombination av produkt och land. För detta rÀcker det med att ange i argumentet names_from en vektor som innehÄller namnen pÄ de sammanfogade fÀlten.

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

Du kan ocksÄ tillÀmpa specifikationer pÄ funktionen pivot_wider(). Men nÀr den skickas till pivot_wider() specifikationen utför en omvandling som Àr motsatt pivot_longer(): kolumner skapas enligt dem som anges i .*.namn, med vÀrden frÄn .value och andra kolumner.

För denna datamÀngd kan du generera en anpassad specifikation om du vill att varje möjlig kombination av land och produkt ska ha sin egen kolumn, inte bara de som finns i data:

spec % 
  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

Flera avancerade exempel pÄ att arbeta med det nya konceptet tidyr

Att ge data ett ordnat utseende, med hjÀlp av ett dataset om inkomst och hyra i USA

DatamÀngden us_rent_income innehÄller information om genomsnittsinkomst och hyra för varje delstat i USA för 2017 (datamÀngden finns tillgÀnglig i paketet tidycensus).

us_rent_income
#> # A tibble: 104 x 5
#>    GEOID NAME       variable estimate   moe
#>                   
#>  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
#> # 
 med 94 fler rader

I den form som data lagras i datasetet us_rent_income Àr det mycket opraktiskt att arbeta med dem, sÄ vi skulle vilja skapa en datamÀngd med kolumner: rent, rent_moe, come, income_moe. Det finns mÄnga sÀtt att skapa denna specifikation, men det viktiga Àr att vi behöver generera varje kombination av vÀrden för variabeln och estimate/moe, och dÀrefter generera namnet pÄ kolumnen.

  spec % 
    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

Att tillhandahÄlla denna specifikation pivot_wider() ger oss det resultat vi söker:

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

VĂ€rldsbanken

Ibland krÀver det flera steg att fÄ en datamÀngd i rÀtt form.
DatamÀngd world_bank_pop innehÄller data frÄn vÀrldsbanksbefolkningen för varje land under perioden 2000 till 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>

VÄrt mÄl Àr att skapa en ren datamÀngd dÀr varje variabel finns i en separat kolumn. Det Àr fortfarande oklart vilka steg som behövs, men vi börjar med det mest uppenbara problemet: Äret Àr uppdelat i flera kolumner.

För att ÄtgÀrda detta behöver vi anvÀnda funktionen pivot_longer().

pop2 % 
  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

NÀsta steg Àr att övervÀga variabeln indicator.
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

DĂ€r SP.POP.GROW Ă€r befolkningstillvĂ€xt, SP.POP.TOTL Ă€r den totala befolkningen, och SP.URB. * Ă€r detsamma men enbart för stadsomrĂ„den. LĂ„t oss dela upp dessa vĂ€rden i tvĂ„ variabler: area — omrĂ„de (total eller urban) och en variabel som innehĂ„ller faktiska data (population eller growth):

pop3 % 
  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

Nu ÄterstÄr det bara att dela variabeln variable i tvÄ kolumner:

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

Kontaklista

Det sista exemplet, förestÀll dig att du har en kontaktlista som du har kopierat och klistrat in frÄn en webbplats:

contacts <- tribble(
  ~field, ~value,
  "name", "Jiena McLellan",
  "company", "Toyota", 
  "name", "John Smith", 
  "company", "google", 
  "email", "john@google.com",
  "name", "Huxley Ratcliffe"
)

Att fĂ„ denna lista till tabellformat Ă€r ganska svĂ„rt, eftersom det inte finns nĂ„gon variabel som identifierar vilka data som tillhör vilken kontakt. Vi kan Ă„tgĂ€rda detta genom att notera att data för varje ny kontakt börjar med namnet ("name"), sĂ„ vi kan skapa en unik identifierare och öka den med ett för varje gĂ„ng vĂ€rdet “name” förekommer i kolumnen field:

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   john@google.com          2
#> 6 name    Huxley Ratcliffe         3

Nu nÀr vi har en unik identifierare för varje kontakt kan vi vÀnda fÀlt och vÀrde till kolumner:

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  john@google.com
#> 3         3 Huxley Ratcliffe <NA>    <NA>

Slutsats

Enligt min Äsikt Àr den nya konceptet tidyr verkligen mer intuitivt och betydligt överlÀgset de förÄldrade funktionerna. spread() och gather()Hoppas att den hÀr artikeln har hjÀlpt dig att förstÄ. pivot_longer() och pivot_wider().

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster