R-pakket tidyr en sy nuwe funksies pivot_longer en pivot_wider

pakket netjies is ingesluit in die kern van een van die gewildste biblioteke in die R-taal - netjies.
Die hoofdoel van die pakket is om die data na 'n netjiese vorm te bring.

Habré het reeds publikasie aan hierdie pakket opgedra, maar dit dateer terug na 2015. En ek wil jou vertel van die mees relevante veranderinge, wat 'n paar dae gelede deur die skrywer Hedley Wickham aangekondig is.

R-pakket tidyr en sy nuwe funksies pivot_longer en pivot_wider

S.J.K.: Sal die versamel() en spread() funksies afgekeur word?

Hadley Wickham: Tot 'n mate. Ons sal nie meer die gebruik van hierdie funksies aanbeveel en foute daarin regstel nie, maar hulle sal steeds in hul huidige toestand in die pakket teenwoordig wees.

inhoud

As jy belangstel in data-analise, sal jy dalk belangstel in my telegram и YouTube kanale. Die meeste van die inhoud daarvan word aan die R-taal gewy.

TidyData-konsep

Doel netjies - om jou te help om die data na die sogenaamde netjiese vorm te bring. Netjiese data is data waar:

  • Elke veranderlike is in 'n kolom.
  • Elke waarneming is 'n lyn.
  • Elke waarde is 'n sel.

Dit is baie makliker en geriefliker om met data te werk wat tydens ontleding na data gebring word.

Die hooffunksies ingesluit in die tidyr-pakket

tidyr bevat 'n stel funksies vir die transformasie van tabelle:

  • fill() - vul die ontbrekende waardes in die kolom in met die vorige waardes;
  • separate() - verdeel een veld in verskeie deur 'n skeier;
  • unite() - voer die operasie uit om verskeie velde in een te kombineer, die aksie is die teenoorgestelde van die funksie separate();
  • pivot_longer() - 'n funksie wat data van 'n wye formaat na 'n lang een omskakel;
  • pivot_wider() - 'n funksie wat data van lang formaat na wye formaat omskakel. Die bewerking is die omgekeerde van dit wat die funksie verrig. pivot_longer().
  • gather()verouderd - 'n funksie wat data van 'n wye formaat na 'n lang een omskakel;
  • spread()verouderd - 'n funksie wat data van lang formaat na wye formaat omskakel. Die bewerking is die omgekeerde van dit wat die funksie verrig. gather().

Nuwe konsep vir die omskakeling van data van wye na lang formaat en omgekeerd

Voorheen, vir hierdie soort transformasie, die funksies gather() и spread(). Oor die jare van die bestaan ​​van hierdie funksies, het dit duidelik geword dat vir die meeste gebruikers, insluitend die outeur van die pakket, die name van hierdie funksies, en hul argumente, taamlik duister was, en probleme veroorsaak het om hulle te vind en te verstaan ​​watter van hierdie funksies skakel 'n datumraam om van wye na lang formaat en omgekeerd.

In verband hiermee, netjies twee nuwe, belangrike funksies is bygevoeg wat ontwerp is om datarame te transformeer.

Nuwe kenmerke pivot_longer() и pivot_wider() is geïnspireer deur sommige van die kenmerke in die pakket cdatageskep deur John Mount en Nina Zumel.

Die installering van die nuutste weergawe van tidyr 0.8.3.9000

Om 'n nuwe, mees opgedateerde pakketweergawe te installeer netjies 0.8.3.9000, waar nuwe kenmerke beskikbaar is, gebruik die volgende kode.

devtools::install_github("tidyverse/tidyr")

Ten tyde van die skryf hiervan is hierdie funksies slegs beskikbaar in die dev-weergawe van die pakket op GitHub.

Oorgang na nuwe funksies

Trouens, dit is nie moeilik om ou skrifte te vertaal om met nuwe funksies te werk nie, vir beter begrip, sal ek 'n voorbeeld uit die dokumentasie van ou funksies neem en wys hoe dieselfde bewerkings uitgevoer word deur nuwes te gebruik. pivot_*() funksies.

Skakel wye formaat na lang formaat.

Voorbeeldkode uit die dokumentasie van die versamelfunksie

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

Skakel lang formaat om na wye formaat.

Voorbeeldkode uit die dokumentasie van die verspreidingsfunksie

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

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

Omdat in die bogenoemde voorbeelde van werk met pivot_longer() и pivot_wider(), in die oorspronklike tabel aandele geen kolomme in argumente gelys nie name_aan и waardes_aan hulle name moet tussen aanhalingstekens ingesluit word.

'n Tabel met behulp waarvan dit vir jou die maklikste sal wees om uit te vind hoe om oor te skakel na werk met 'n nuwe konsep netjies.

R-pakket tidyr en sy nuwe funksies pivot_longer en pivot_wider

Nota van die skrywer

Al die teks hieronder is aanpasbaar, ek sou selfs sê vrye vertaling vignette vanaf die amptelike webwerf van die tidyverse-biblioteek.

'n Eenvoudige voorbeeld van die omskakeling van data van wyd na lank

pivot_longer () - maak datastelle langer deur die aantal kolomme te verminder en die aantal rye te verhoog.

R-pakket tidyr en sy nuwe funksies pivot_longer en pivot_wider

Om die voorbeelde wat in die artikel aangebied word uit te voer, moet u eers die nodige pakkette koppel:

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

Kom ons sê ons het 'n tabel met die resultate van 'n opname wat mense (onder andere) oor hul godsdiens en jaarlikse inkomste gevra het:

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

Hierdie tabel bevat die godsdiensdata van die respondente in rye, en die inkomstevlak is oor die kolomname versprei. Die aantal respondente van elke kategorie word in selwaardes gestoor by die kruising van godsdiens en inkomstevlak. Om die tabel in 'n netjiese, korrekte formaat te bring, is dit genoeg om te gebruik 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

Funksie Argumente pivot_longer()

  • Eerste argument krae, beskryf watter kolomme saamgevoeg moet word. In hierdie geval, alle kolomme behalwe tyd.
  • argument name_aan gee die naam van die veranderlike wat geskep sal word uit die kolomname wat ons aaneengeskakel het.
  • waardes_aan gee die naam van die veranderlike wat geskep sal word uit die data wat in die selwaardes van die saamgevoegde kolomme gestoor is.

Spesifikasies

Dit is 'n nuwe pakketfunksie. netjies, wat voorheen nie beskikbaar was wanneer daar met verouderde kenmerke gewerk word nie.

'n Spesifikasie is 'n dataraam, waarvan elke ry ooreenstem met een kolom in die nuwe uitvoerdataraam, en twee spesiale kolomme wat begin met:

  • . Naam bevat die oorspronklike kolomnaam.
  • .waarde bevat die naam van die kolom wat die selwaardes sal bevat.

Die oorblywende kolomme van die spesifikasie weerspieël hoe die naam van die saamgeperste kolomme in die nuwe kolom vertoon sal word. . Naam.

Die spesifikasie beskryf die metadata wat in 'n kolomnaam gestoor word, met een ry vir elke kolom en een kolom vir elke veranderlike saamgevoeg met die kolomnaam, wat dalk op die oomblik verwarrend kan lyk, maar na 'n paar voorbeelde sal dit baie duideliker word.

Die punt van die spesifikasie is dat jy nuwe metadata vir die omgeskakelde dataraam kan ophaal, wysig en stel.

Om met spesifikasies te werk wanneer 'n tabel van wye formaat na lang formaat omgeskakel word, gebruik die funksie pivot_longer_spec().

Die manier waarop hierdie funksie werk, is dat dit enige dataraamwerk neem en sy metadata genereer op die wyse hierbo beskryf.

Kom ons neem byvoorbeeld die who-datastel wat saam met die pakket kom netjies. Hierdie datastel bevat inligting verskaf deur die Internasionale Gesondheidsorganisasie oor tuberkulosevoorkoms.

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

Kom ons bou sy spesifikasie.

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

velde land, iso2, iso3 is reeds veranderlikes. Ons taak is om die kolomme om te draai nuwe_sp_m014 op newrel_f65.

Die volgende inligting word in die name van hierdie kolomme gestoor:

  • voorvoegsel new_ dui aan dat die kolom data bevat oor nuwe gevalle van tuberkulose, die huidige datumraam bevat slegs inligting oor nuwe siektes, so hierdie voorvoegsel in die huidige konteks dra geen semantiese las nie.
  • sp/rel/sp/ep beskryf 'n metode om 'n siekte te diagnoseer.
  • m/f geslag van die pasiënt.
  • 014/1524/2535/3544/4554/65 pasiënt ouderdomsgroep.

Ons kan hierdie kolomme verdeel met die funksie extract(), deur 'n gewone uitdrukking te gebruik.

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

Let asseblief op die kolom . Naam moet onveranderd bly, aangesien dit ons indeks in die oorspronklike datastel se kolomname is.

Geslag en ouderdom (kolomme geslag и ouderdom) vaste en bekende waardes het, daarom word dit aanbeveel om hierdie kolomme na faktore om te skakel:

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

Ten slotte, om die spesifikasie wat ons geskep het op die oorspronklike dataraam toe te pas wat ons moet die argument gebruik spec in funksie 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

Alles wat ons sopas gedoen het kan skematies soos volg uitgebeeld word:

R-pakket tidyr en sy nuwe funksies pivot_longer en pivot_wider

Spesifikasie wat veelvuldige waardes (.value) gebruik

In die voorbeeld hierbo, die spesifikasiekolom .waarde slegs een waarde bevat het, in die meeste gevalle is dit die geval.

Maar soms kan 'n situasie ontstaan ​​wanneer jy data van kolomme met verskillende datatipes in waardes moet insamel. Met 'n afgekeurde funksie spread() dit sal nogal moeilik wees om te doen.

Die voorbeeld hieronder is geneem uit vignette na die pakkie data.tabel.

Kom ons skep 'n opleidingsdataraam.

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

Die geskepde datumraam in elke reël bevat data oor die kinders van een gesin. Gesinne kan een of twee kinders hê. Vir elke kind word data oor die geboortedatum en geslag verskaf, en die data vir elke kind gaan in aparte kolomme, ons taak is om hierdie data in die korrekte formaat te bring vir ontleding.

Let daarop dat ons twee veranderlikes het met inligting oor elke kind: hul geslag en geboortedatum (kolomme met voorvoegsel dop bevat geboortedatum, voorafgevoegde kolomme geslag die geslag van die kind bevat). In die verwagte resultaat moet hulle in aparte kolomme gaan. Ons kan dit doen deur 'n spesifikasie te genereer waar die kolom .value twee verskillende betekenisse sal hê.

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

Dus, kom ons kyk na die stappe van die aksies wat deur die bogenoemde kode uitgevoer word.

  • pivot_longer_spec(-family) - skep 'n spesifikasie wat alle beskikbare kolomme saamdruk, behalwe vir die familiekolom.
  • separate(col = name, into = c(".value", "child")) - verdeel die kolom . Naam, wat die name van die oorspronklike velde bevat, deur onderstreep en die resulterende waardes in kolomme te plaas .waarde и kind.
  • mutate(child = parse_number(child)) - transformeer die veldwaardes kind van teks tot numeriese datatipe.

Nou kan ons die gevolglike spesifikasie op die oorspronklike dataraam toepas, en die tabel na die verlangde vorm bring.

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

Ons gebruik die argument na.rm = TRUE, want die huidige vorm van die data dwing die skepping van ekstra rye vir nie-bestaande waarnemings af. Omdat gesin 2 het net een kind, na.rm = TRUE waarborg dat gesin 2 een ry in die uitvoer sal hê.

Omskakeling van datarame van lang formaat na wye formaat

pivot_wider() - is die omgekeerde transformasie, en omgekeerd verhoog die aantal kolomme van die datumraam deur die aantal rye te verminder.

R-pakket tidyr en sy nuwe funksies pivot_longer en pivot_wider

Hierdie soort transformasie word uiters selde gebruik om data in 'n netjiese vorm te bring, maar hierdie tegniek kan nuttig wees vir die skep van spilpunttabelle wat in aanbiedings gebruik word, of vir integrasie met ander instrumente.

Eintlik die funksies pivot_longer() и pivot_wider() is simmetries en voer die teenoorgestelde aksies as mekaar uit, d.w.s.: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) sal die oorspronklike df terugstuur.

Die eenvoudigste voorbeeld van die omskakeling van 'n tabel na 'n wye formaat

Om te demonstreer hoe die funksie werk pivot_wider() ons sal die datastel gebruik vis_ontmoetings, wat inligting stoor oor hoe verskeie stasies die beweging van visse langs die rivier aanteken.

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

In die meeste gevalle sal hierdie tabel meer insiggewend en makliker wees om te gebruik as die inligting vir elke stasie in 'n aparte kolom aangebied word.

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>

Hierdie datastel teken inligting slegs aan wanneer visse deur die stasie opgespoor is, m.a.w. as enige vis nie deur een of ander stasie aangeteken is nie, sal hierdie data nie in die tabel wees nie. Dit beteken dat die uitset met NA gevul sal word.

In hierdie geval weet ons egter dat die afwesigheid van die inskrywing beteken dat die vis nie gesien is nie, dus kan ons die argument gebruik waardes_vul in funksie pivot_wider() en vul daardie ontbrekende waardes met nulle in:

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>

Genereer 'n kolomnaam uit verskeie bronveranderlikes

Stel jou voor ons het 'n tabel wat 'n kombinasie van produk, land en jaar bevat. Om 'n toetsdatum raam te genereer, kan jy die volgende kode hardloop:

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

Ons taak is om die dataraam uit te brei sodat een kolom data vir elke kombinasie van produk en land bevat. Om dit te doen, is dit genoeg om die argument deur te gee name_van 'n vektor wat die name bevat van die velde wat saamgevoeg moet word.

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

Jy kan ook spesifikasies op 'n funksie toepas pivot_wider(). Maar wanneer voorgelê word aan pivot_wider() die spesifikasie voer die teenoorgestelde omskakeling uit pivot_longer(): skep die kolomme gespesifiseer in . Naam, met behulp van waardes van .waarde en ander kolomme.

Vir hierdie datastel kan jy 'n pasgemaakte spesifikasie genereer as jy wil hê dat elke moontlike kombinasie van land en produk sy eie kolom moet hê, nie net dié wat in die data teenwoordig is nie:

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

Enkele gevorderde voorbeelde van werk met die nuwe tidyr-konsep

Ruim die data op deur die Amerikaanse sensus van inkomste en huurdatastel te gebruik

Datastel ons_huurinkomste bevat inligting oor mediaan inkomste en huur vir elke staat in die VSA vir 2017 (datastel beskikbaar in pakket netjiese sensus).

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

In die vorm waarin die data in die datastel gestoor word ons_huurinkomste om met hulle te werk is uiters ongerieflik, daarom wil ons graag 'n datastel met kolomme skep: huur, huur_moe, hoe, inkomste_moe. Daar is baie maniere om hierdie spesifikasie te skep, maar die belangrikste ding is dat ons elke kombinasie van veranderlike waardes en skat/moeen genereer dan die kolomnaam.

  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

Die verskaffing van hierdie spesifikasie pivot_wider() gee ons die resultaat waarna ons soek:

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

Die Wêreldbank

Soms neem dit verskeie stappe om 'n datastel in die regte vorm te kry.
Datastel wêreld_bank_pop bevat Wêreldbankdata oor die bevolking van elke land tussen 2000 en 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>

Ons doel is om 'n netjiese datastel te skep waar elke veranderlike in sy eie kolom is. Dit is nog nie duidelik presies watter stappe nodig is nie, maar ons begin met die mees ooglopende probleem: die jaar is oor verskeie kolomme versprei.

Om dit reg te stel, moet jy die funksie gebruik 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

Die volgende stap is om die aanwyser veranderlike te oorweeg.
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

Waar SP.POP.GROW bevolkingsgroei is, is SP.POP.TOTL totale bevolking, en SP.URB. * dieselfde, maar slegs vir stedelike gebiede. Kom ons verdeel hierdie waardes in twee veranderlikes: oppervlakte - die oppervlakte (totaal of stedelik) en 'n veranderlike wat die werklike data (bevolking of groei) bevat:

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

Nou moet ons net die veranderlike veranderlike in twee kolomme verdeel:

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

Kontaklys

Laaste voorbeeld, stel jou voor dat jy 'n lys kontakte het wat jy van 'n webwerf gekopieer en geplak het:

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

Om hierdie lys te tabelle is moeilik omdat daar geen veranderlike is om te identifiseer watter data aan watter kontak behoort nie. Ons kan dit regmaak deur op te let dat die data vir elke nuwe kontak met 'n naam ("naam") begin, sodat ons 'n unieke ID kan skep, en dit met een verhoog elke keer as die waarde "naam" in die veldkolom teëgekom word:

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

Noudat ons 'n unieke ID vir elke kontak het, kan ons die veld en waarde in kolomme verander:

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>

Gevolgtrekking

My persoonlike mening is dat die nuwe konsep netjies is regtig meer intuïtief, en vaar aansienlik beter as verouderde funksies in terme van funksionaliteit spread() и gather(). Ek hoop hierdie artikel het jou gehelp om te verstaan pivot_longer() и pivot_wider().

Bron: will.com

Voeg 'n opmerking