R-pakke tidyr og dens nye funktioner pivot_longer og pivot_wider

pakke ryddelige inkluderet i kernen af ​​et af de mest populære biblioteker i R-sproget - ryddelige.
Hovedformålet med pakken er at bringe dataene i en nøjagtig form.

Allerede tilgængelig på Habré publikation dedikeret til denne pakke, men den går tilbage til 2015. Og jeg vil gerne fortælle dig om de mest aktuelle ændringer, som blev annonceret for et par dage siden af ​​dens forfatter, Hedley Wickham.

R-pakke tidyr og dens nye funktioner pivot_longer og pivot_wider

SJK: Vil gather() og spread() blive forældet?

Hadley Wickham: Til en vis grad. Vi vil ikke længere anbefale brugen af ​​disse funktioner og rette fejl i dem, men de vil fortsat være til stede i pakken i deres nuværende tilstand.

Indhold

Hvis du er interesseret i dataanalyse, er du måske interesseret i min telegram и youtube kanaler. Det meste af indholdet er dedikeret til R-sproget.

TidyData koncept

mål ryddelige — hjælpe dig med at bringe dataene til en såkaldt pæn form. Pæne data er data, hvor:

  • Hver variabel er i en kolonne.
  • Hver observation er en streng.
  • Hver værdi er en celle.

Det er meget nemmere og mere bekvemt at arbejde med data, der præsenteres i ryddelige data, når man udfører analyser.

Hovedfunktioner inkluderet i tidyr-pakken

tidyr indeholder et sæt funktioner designet til at transformere tabeller:

  • fill() — udfyldning af manglende værdier i en kolonne med tidligere værdier;
  • separate() — opdeler et felt i flere ved hjælp af en separator;
  • unite() — udfører operationen med at kombinere flere felter til ét, den omvendte handling af funktionen separate();
  • pivot_longer() — en funktion, der konverterer data fra bredformat til langt format;
  • pivot_wider() - en funktion, der konverterer data fra langt format til bredformat. Den omvendte operation af den, der udføres af funktionen pivot_longer().
  • gather()forældet — en funktion, der konverterer data fra bredformat til langt format;
  • spread()forældet - en funktion, der konverterer data fra langt format til bredformat. Den omvendte operation af den, der udføres af funktionen gather().

Nyt koncept til konvertering af data fra bredt til langt format og omvendt

Tidligere blev funktioner brugt til denne form for transformation gather() и spread(). I løbet af årene, hvor disse funktioner eksisterede, blev det tydeligt, at for de fleste brugere, inklusive forfatteren af ​​pakken, var navnene på disse funktioner og deres argumenter ikke helt indlysende, og det forårsagede vanskeligheder med at finde dem og forstå, hvilke af disse funktioner der konverterer en datoramme fra bredt til langt format og omvendt.

I denne forbindelse, i ryddelige To nye, vigtige funktioner er blevet tilføjet, der er designet til at transformere datorammer.

Nye funktioner pivot_longer() и pivot_wider() var inspireret af nogle af funktionerne i pakken cdata, skabt af John Mount og Nina Zumel.

Installerer den nyeste version af tidyr 0.8.3.9000

For at installere den nye, mest aktuelle version af pakken ryddelige 0.8.3.9000, hvor nye funktioner er tilgængelige, skal du bruge følgende kode.

devtools::install_github("tidyverse/tidyr")

I skrivende stund er disse funktioner kun tilgængelige i dev-versionen af ​​pakken på GitHub.

Overgang til nye funktioner

Faktisk er det ikke svært at overføre gamle scripts til at arbejde med nye funktioner; for bedre forståelse vil jeg tage et eksempel fra dokumentationen af ​​gamle funktioner og vise, hvordan de samme operationer udføres med nye. pivot_*() funktioner.

Konverter bredformat til langt format.

Eksempelkode fra samlefunktionsdokumentationen

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

Konvertering af langt format til bredformat.

Eksempelkode fra spredningsfunktionsdokumentation

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

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

Fordi i ovenstående eksempler på at arbejde med pivot_longer() и pivot_wider(), i den originale tabel lagre ingen kolonner angivet i argumenter navne_til и værdier_til deres navne skal stå i anførselstegn.

En tabel, der hjælper dig nemmest med at finde ud af, hvordan du skifter til at arbejde med et nyt koncept ryddelige.

R-pakke tidyr og dens nye funktioner pivot_longer og pivot_wider

Notat fra forfatteren

Al teksten nedenfor er adaptiv, jeg vil endda sige fri oversættelse vignetter fra det officielle tidyverse biblioteks websted.

Et simpelt eksempel på konvertering af data fra bredt til langt format

pivot_longer () — gør datasæt længere ved at reducere antallet af kolonner og øge antallet af rækker.

R-pakke tidyr og dens nye funktioner pivot_longer og pivot_wider

For at køre de eksempler, der præsenteres i artiklen, skal du først forbinde de nødvendige pakker:

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

Lad os sige, at vi har en tabel med resultaterne af en undersøgelse, der (blandt andet) spurgte folk om deres religion og årlige indkomst:

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

Denne tabel indeholder respondenternes religionsdata i rækker, og indkomstniveauer er spredt på tværs af kolonnenavne. Antallet af respondenter fra hver kategori er gemt i celleværdierne i skæringspunktet mellem religion og indkomstniveau. For at bringe bordet i et pænt, korrekt format, er det nok at bruge 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

Funktionsargumenter pivot_longer()

  • Første argument cols, beskriver hvilke kolonner der skal flettes. I dette tilfælde er alle kolonner undtagen tid.
  • argument navne_til giver navnet på den variabel, der vil blive oprettet ud fra navnene på de kolonner, vi sammenkædede.
  • værdier_til giver navnet på en variabel, der vil blive oprettet ud fra de data, der er gemt i værdierne af cellerne i de flettede kolonner.

specifikation

Dette er en ny funktionalitet i pakken ryddelige, som tidligere ikke var tilgængelig, når man arbejdede med ældre funktioner.

En specifikation er en dataramme, hvor hver række svarer til én kolonne i den nye outputdatoramme og to specielle kolonner, der begynder med:

  • . Navn indeholder det oprindelige kolonnenavn.
  • .værdi indeholder navnet på den kolonne, der skal indeholde celleværdierne.

De resterende kolonner i specifikationen afspejler, hvordan den nye kolonne vil vise navnet på de komprimerede kolonner fra . Navn.

Specifikationen beskriver de metadata, der er gemt i et kolonnenavn, med en række for hver kolonne og en kolonne for hver variabel, kombineret med kolonnenavnet, denne definition kan virke forvirrende i øjeblikket, men efter at have kigget på et par eksempler vil det blive meget klarere.

Pointen med specifikationen er, at du kan hente, ændre og definere nye metadata for den dataramme, der konverteres.

For at arbejde med specifikationer, når du konverterer en tabel fra et bredt format til et langt format, skal du bruge funktionen pivot_longer_spec().

Hvordan denne funktion fungerer er, at den tager en hvilken som helst datoramme og genererer dens metadata på den måde, der er beskrevet ovenfor.

Som et eksempel, lad os tage who-datasættet, der leveres med pakken ryddelige. Dette datasæt indeholder oplysninger leveret af den internationale sundhedsorganisation om forekomsten af ​​tuberkulose.

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

Lad os bygge dens specifikation.

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

felter land, isoxnumx, isoxnumx er allerede variable. Vores opgave er at vende kolonnerne med new_sp_m014newrel_f65.

Navnene på disse kolonner gemmer følgende oplysninger:

  • præfiks new_ angiver, at kolonnen indeholder data om nye tilfælde af tuberkulose, den aktuelle datoramme indeholder kun oplysninger om nye sygdomme, så dette præfiks i den aktuelle sammenhæng har ingen betydning.
  • sp/rel/sp/ep beskriver en metode til at diagnosticere en sygdom.
  • m/f patientens køn.
  • 014/1524/2535/3544/4554/65 patientens aldersgruppe.

Vi kan opdele disse kolonner ved hjælp af funktionen extract()ved hjælp af regulære udtryk.

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

Bemærk venligst kolonnen . Navn bør forblive uændret, da dette er vores indeks i kolonnenavnene på det originale datasæt.

Køn og alder (spalter køn и alder) har faste og kendte værdier, så det anbefales at konvertere disse kolonner til faktorer:

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

Til sidst, for at anvende specifikationen, vi oprettede til den originale datoramme der vi skal bruge et argument spec i funktion 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

Alt, hvad vi lige har lavet, kan skematisk afbildes som følger:

R-pakke tidyr og dens nye funktioner pivot_longer og pivot_wider

Specifikation ved hjælp af flere værdier (.value)

I eksemplet ovenfor, specifikationskolonnen .værdi indeholdt kun én værdi, i de fleste tilfælde er dette tilfældet.

Men af ​​og til kan der opstå en situation, hvor du skal indsamle data fra kolonner med forskellige datatyper i værdier. Brug af en ældre funktion spread() dette ville være ret svært at gøre.

Eksemplet nedenfor er taget fra vignetter til pakken data.tabel.

Lad os skabe en træningsdataramme.

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

Den oprettede datoramme indeholder data om børn i én familie i hver række. Familier kan have et eller to børn. For hvert barn oplyses data om fødselsdato og køn, og dataene for hvert barn er i separate kolonner; vores opgave er at bringe disse data til det korrekte format til analyse.

Bemærk venligst, at vi har to variabler med oplysninger om hvert barn: deres køn og fødselsdato (kolonner med præfikset dåb indeholder fødselsdato, kolonner med præfiks køn indeholde barnets køn). Det forventede resultat er, at de skal vises i separate kolonner. Det kan vi gøre ved at generere en specifikation, hvori kolonnen .value vil have to forskellige betydninger.

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

Så lad os tage et trin-for-trin-kig på de handlinger, der udføres af ovenstående kode.

  • pivot_longer_spec(-family) — opret en specifikation, der komprimerer alle eksisterende kolonner undtagen familiekolonnen.
  • separate(col = name, into = c(".value", "child")) - opdele kolonnen . Navn, som indeholder navnene på kildefelterne, ved at bruge understregningen og indtaste de resulterende værdier i kolonnerne .værdi и barn.
  • mutate(child = parse_number(child)) — transformere feltværdierne barn fra tekst til numerisk datatype.

Nu kan vi anvende den resulterende specifikation på den originale dataramme og bringe tabellen til den ønskede form.

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 bruger argumenter na.rm = TRUE, fordi den nuværende form for dataene tvinger oprettelsen af ​​ekstra rækker til ikke-eksisterende observationer. Fordi familie 2 har kun ét barn, na.rm = TRUE garanterer, at familie 2 vil have én række i outputtet.

Konvertering af datorammer fra langt til bredt format

pivot_wider() - er den omvendte transformation, og vice versa øger antallet af kolonner i datorammen ved at reducere antallet af rækker.

R-pakke tidyr og dens nye funktioner pivot_longer og pivot_wider

Denne form for transformation bruges ekstremt sjældent til at bringe data i en nøjagtig form, men denne teknik kan være nyttig til at skabe pivottabeller, der bruges i præsentationer, eller til integration med nogle andre værktøjer.

Faktisk funktionerne pivot_longer() и pivot_wider() er symmetriske og frembringer handlinger i forhold til hinanden, dvs. df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) vil returnere den originale df.

Det enkleste eksempel på at konvertere en tabel til et bredt format

For at demonstrere, hvordan funktionen fungerer pivot_wider() vi vil bruge datasættet fiske_møder, som gemmer information om, hvordan forskellige stationer registrerer bevægelsen af ​​fisk langs 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 fleste tilfælde vil denne tabel være mere informativ og lettere at bruge, hvis du præsenterer oplysninger for hver station i en separat kolonne.

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>

Dette datasæt registrerer kun information, når der er opdaget fisk af stationen, dvs. hvis nogen fisk ikke blev registreret af en station, vil disse data ikke være i tabellen. Det betyder, at outputtet vil være fyldt med NA.

Men i dette tilfælde ved vi, at fraværet af en registrering betyder, at fisken ikke blev set, så vi kan bruge argumentet værdier_fyld i funktion pivot_wider() og udfyld disse manglende værdier med nuller:

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 af et kolonnenavn fra flere kildevariabler

Forestil dig, at vi har en tabel, der indeholder en kombination af produkt, land og år. For at generere en testdatoramme kan du køre følgende kode:

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

Vores opgave er at udvide datarammen, så en kolonne indeholder data for hver kombination af produkt og land. For at gøre dette skal du bare sende argumentet navne_fra en vektor, der indeholder navnene på de felter, der skal flettes.

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 også anvende specifikationer til en funktion pivot_wider(). Men når indsendt til pivot_wider() specifikationen udfører den modsatte konvertering pivot_longer(): De kolonner, der er angivet i . Navn, ved hjælp af værdier fra .værdi og andre kolonner.

For dette datasæt kan du generere en brugerdefineret specifikation, hvis du ønsker, at alle mulige lande og produktkombinationer skal have sin egen kolonne, ikke kun dem, der findes i dataene:

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

Flere avancerede eksempler på at arbejde med det nye tidyr koncept

Oprydning af data ved hjælp af US Census Income and Rent-datasættet som eksempel.

Datasæt us_leje_indkomst indeholder medianindkomst og lejeoplysninger for hver stat i USA for 2017 (datasæt tilgængeligt i pakken tidycensus).

us_rent_income
#> # A tibble: 104 x 5
#>    GEOID NAME       variable estimate   moe
#>    <chr> <chr>      <chr>       <dbl> <dbl>
#>  1 01    Alabama    income      24476   136
#>  2 01    Alabama    rent          747     3
#>  3 02    Alaska     income      32940   508
#>  4 02    Alaska     rent         1200    13
#>  5 04    Arizona    income      27517   148
#>  6 04    Arizona    rent          972     4
#>  7 05    Arkansas   income      23789   165
#>  8 05    Arkansas   rent          709     5
#>  9 06    California income      29454   109
#> 10 06    California rent         1358     3
#> # … with 94 more rows

I den form, som dataene er gemt i datasættet us_leje_indkomst at arbejde med dem er ekstremt ubelejligt, så vi vil gerne oprette et datasæt med kolonner: leje, leje_moe, Kom, indkomst_moe. Der er mange måder at oprette denne specifikation på, men hovedpointen er, at vi skal generere hver kombination af variable værdier og skøn/moeog generer derefter kolonnenavnet.

  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

Levering af denne specifikation pivot_wider() giver os det resultat, vi leder efter:

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

Verdensbanken

Nogle gange kræver det flere trin at bringe et datasæt i den ønskede form.
Datasæt verdensbankpop indeholder Verdensbankens data om befolkningen i hvert land mellem 2000 og 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>

Vores mål er at skabe et pænt datasæt med hver variabel i sin egen kolonne. Det er uklart, præcis hvilke trin der er nødvendige, men vi starter med det mest åbenlyse problem: året er spredt over flere kolonner.

For at løse dette skal du bruge funktionen 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

Det næste trin er at se på indikatorvariablen.
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

Hvor SP.POP.GROW er befolkningstilvækst, er SP.POP.TOTL den samlede befolkning og SP.URB. * det samme, men kun for byområder. Lad os opdele disse værdier i to variable: areal - areal (totalt eller bymæssigt) og en variabel, der indeholder faktiske data (befolkning eller vækst):

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

Nu skal vi bare opdele variablen i to kolonner:

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

Список:

Et sidste eksempel, forestil dig, at du har en kontaktliste, som du kopierede og indsatte fra et websted:

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

Det er ret vanskeligt at opstille denne liste, fordi der ikke er nogen variabel, der identificerer, hvilke data der hører til hvilken kontaktperson. Vi kan rette dette ved at bemærke, at dataene for hver ny kontakt starter med "navn", så vi kan oprette en unik identifikator og øge den med én, hver gang feltkolonnen indeholder værdien "navn":

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

Nu hvor vi har et unikt ID for hver kontakt, kan vi omdanne feltet og værdien til kolonner:

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>

Konklusion

Min personlige mening er, at det nye koncept ryddelige virkelig mere intuitiv og væsentligt overlegen i funktionalitet i forhold til ældre funktioner spread() и gather(). Jeg håber, at denne artikel hjalp dig med at håndtere pivot_longer() и pivot_wider().

Kilde: www.habr.com

Tilføj en kommentar