R-pakket Tidr en zijn nieuwe functies pivot_longer en pivot_wider

Verpakking opgeruimder opgenomen in de kern van een van de meest populaire bibliotheken in de R-taal - opruimen.
Het belangrijkste doel van het pakket is om de gegevens in een nauwkeurige vorm te brengen.

Al beschikbaar op Habré publicatie gewijd aan dit pakket, maar dateert uit 2015. En ik wil je vertellen over de meest recente veranderingen, die een paar dagen geleden zijn aangekondigd door de auteur ervan, Hedley Wickham.

R-pakket Tidr en zijn nieuwe functies pivot_longer en pivot_wider

SJK: Worden collect() en spread() verouderd?

Hadley Wickham: Tot op zekere hoogte. We zullen het gebruik van deze functies niet langer aanbevelen en er bugs in oplossen, maar ze zullen in hun huidige staat nog steeds in het pakket aanwezig zijn.

Inhoud

Als u geïnteresseerd bent in data-analyse, bent u wellicht geïnteresseerd in mijn telegram и youtube kanalen. Het grootste deel van de inhoud is gewijd aan de R-taal.

TidyData-concept

doelwit opgeruimder — u helpen de gegevens in een zogenaamde nette vorm te brengen. Nette gegevens zijn gegevens waarbij:

  • Elke variabele staat in een kolom.
  • Elke waarneming is een string.
  • Elke waarde is een cel.

Het is veel eenvoudiger en handiger om bij het uitvoeren van analyses te werken met gegevens die in overzichtelijke gegevens worden gepresenteerd.

Belangrijkste functies inbegrepen in het Tidr-pakket

opgeruimdr bevat een reeks functies die zijn ontworpen om tabellen te transformeren:

  • fill() — ontbrekende waarden in een kolom vullen met eerdere waarden;
  • separate() — splitst een veld in meerdere met behulp van een scheidingsteken;
  • unite() — voert de bewerking uit waarbij verschillende velden in één worden gecombineerd, de omgekeerde actie van de functie separate();
  • pivot_longer() — een functie die gegevens converteert van breedformaat naar langformaat;
  • pivot_wider() - een functie die gegevens converteert van lang formaat naar breed formaat. De omgekeerde werking van degene die door de functie wordt uitgevoerd pivot_longer().
  • gather()verouderd — een functie die gegevens converteert van breedformaat naar langformaat;
  • spread()verouderd - een functie die gegevens converteert van lang formaat naar breed formaat. De omgekeerde werking van degene die door de functie wordt uitgevoerd gather().

Nieuw concept voor het converteren van gegevens van breed naar lang formaat en omgekeerd

Voorheen werden functies gebruikt voor dit soort transformaties gather() и spread(). Gedurende de jaren dat deze functies bestonden, werd het duidelijk dat voor de meeste gebruikers, inclusief de auteur van het pakket, de namen van deze functies en hun argumenten niet helemaal duidelijk waren, en problemen veroorzaakten bij het vinden ervan en bij het begrijpen welke van deze functies converteert een datumframe van breed naar lang formaat, en omgekeerd.

In dit verband is in opgeruimder Er zijn twee nieuwe, belangrijke functies toegevoegd die zijn ontworpen om datumframes te transformeren.

Nieuwe functies pivot_longer() и pivot_wider() zijn geïnspireerd door enkele functies in het pakket cdata, gemaakt door John Mount en Nina Zumel.

Installatie van de meest recente versie van Tidr 0.8.3.9000

Om de nieuwe, meest recente versie van het pakket te installeren opgeruimder 0.8.3.9000, waar nieuwe functies beschikbaar zijn, gebruikt u de volgende code.

devtools::install_github("tidyverse/tidyr")

Op het moment van schrijven zijn deze functies alleen beschikbaar in de dev-versie van het pakket op GitHub.

Overgang naar nieuwe functies

In feite is het niet moeilijk om oude scripts over te zetten om met nieuwe functies te werken; voor een beter begrip zal ik een voorbeeld nemen uit de documentatie van oude functies en laten zien hoe dezelfde bewerkingen worden uitgevoerd met nieuwe functies pivot_*() functies.

Converteer breedformaat naar langformaat.

Voorbeeldcode uit de documentatie van de verzamelfunctie

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

Lang formaat naar breed formaat converteren.

Voorbeeldcode uit de documentatie van de spreadfunctie

# 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 de bovenstaande voorbeelden van werken met pivot_longer() и pivot_wider(), in de oorspronkelijke tabel voorraden geen kolommen vermeld in argumenten namen_naar и waarden_to hun namen moeten tussen aanhalingstekens staan.

Een tabel waarmee u het gemakkelijkst kunt bepalen hoe u kunt overstappen op het werken met een nieuw concept opgeruimder.

R-pakket Tidr en zijn nieuwe functies pivot_longer en pivot_wider

Opmerking van de auteur

Alle onderstaande tekst is adaptief, ik zou zelfs zeggen: gratis vertaling vignetten van de officiële riddverse-bibliotheekwebsite.

Een eenvoudig voorbeeld van het converteren van gegevens van breed naar lang formaat

pivot_longer () — maakt datasets langer door het aantal kolommen te verminderen en het aantal rijen te vergroten.

R-pakket Tidr en zijn nieuwe functies pivot_longer en pivot_wider

Om de voorbeelden in het artikel uit te voeren, moet u eerst de benodigde pakketten verbinden:

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

Laten we zeggen dat we een tabel hebben met de resultaten van een onderzoek waarin mensen (onder andere) werden gevraagd naar hun religie en jaarinkomen:

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

Deze tabel bevat de religiegegevens van de respondenten in rijen, en de inkomensniveaus zijn verspreid over de kolomnamen. Het aantal respondenten uit elke categorie wordt opgeslagen in de celwaarden op het snijvlak van religie en inkomensniveau. Om de tafel in een netjes, correct formaat te brengen, is het voldoende om te gebruiken 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

Functieargumenten pivot_longer()

  • Eerste argument cols, beschrijft welke kolommen moeten worden samengevoegd. In dit geval zijn alle kolommen behalve niet de tijd of.
  • argument namen_naar geeft de naam van de variabele die wordt gemaakt op basis van de namen van de kolommen die we hebben samengevoegd.
  • waarden_to geeft de naam van een variabele die zal worden gemaakt op basis van de gegevens die zijn opgeslagen in de waarden van de cellen van de samengevoegde kolommen.

Specificaties

Dit is een nieuwe functionaliteit van het pakket opgeruimder, dat voorheen niet beschikbaar was bij het werken met oudere functies.

Een specificatie is een dataframe, waarvan elke rij overeenkomt met één kolom in het nieuwe uitvoerdatumframe, en twee speciale kolommen die beginnen met:

  • . Naam bevat de oorspronkelijke kolomnaam.
  • .waarde bevat de naam van de kolom die de celwaarden zal bevatten.

De overige kolommen van de specificatie geven weer hoe de nieuwe kolom de naam van de gecomprimeerde kolommen weergeeft . Naam.

De specificatie beschrijft de metagegevens die zijn opgeslagen in een kolomnaam, met één rij voor elke kolom en één kolom voor elke variabele, gecombineerd met de kolomnaam. Deze definitie lijkt op dit moment misschien verwarrend, maar na het bekijken van een paar voorbeelden zal het veel worden. duidelijker.

Het punt van de specificatie is dat u nieuwe metagegevens kunt ophalen, wijzigen en definiëren voor het dataframe dat wordt geconverteerd.

Gebruik de functie om met specificaties te werken bij het converteren van een tabel van een breed formaat naar een lang formaat pivot_longer_spec().

Hoe deze functie werkt, is dat het elk datumframe gebruikt en de metagegevens genereert op de hierboven beschreven manier.

Laten we als voorbeeld de who-gegevensset nemen die bij het pakket wordt geleverd opgeruimder. Deze dataset bevat informatie van de internationale gezondheidsorganisatie over de incidentie van tuberculose.

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

Laten we de specificatie ervan opstellen.

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

velden Land, iso2, iso3 zijn al variabelen. Onze taak is om de kolommen om te draaien nieuwe_sp_m014 op newrel_f65.

De namen van deze kolommen bevatten de volgende informatie:

  • voorvoegsel new_ geeft aan dat de kolom gegevens bevat over nieuwe gevallen van tuberculose, het huidige datumframe bevat alleen informatie over nieuwe ziekten, dus dit voorvoegsel heeft in de huidige context geen enkele betekenis.
  • sp/rel/sp/ep beschrijft een methode voor het diagnosticeren van een ziekte.
  • m/f het geslacht van de patiënt.
  • 014/1524/2535/3544/4554/65 leeftijdscategorie van de patiënt.

We kunnen deze kolommen splitsen met behulp van de functie extract()met behulp van reguliere expressie.

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 op de kolom . Naam zou ongewijzigd moeten blijven, aangezien dit onze index is van de kolomnamen van de oorspronkelijke gegevensset.

Geslacht en leeftijd (kolommen geslacht и leeftijd) hebben vaste en bekende waarden, dus het wordt aanbevolen om deze kolommen naar factoren te converteren:

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

Ten slotte, om de specificatie die we hebben gemaakt toe te passen op het oorspronkelijke datumframe die we moeten een argument gebruiken spec in functie 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 we zojuist hebben gedaan, kan als volgt schematisch worden weergegeven:

R-pakket Tidr en zijn nieuwe functies pivot_longer en pivot_wider

Specificatie met behulp van meerdere waarden (.value)

In het bovenstaande voorbeeld de specificatiekolom .waarde slechts één waarde bevatte, is dit in de meeste gevallen het geval.

Maar af en toe kan er een situatie ontstaan ​​waarin u gegevens moet verzamelen uit kolommen met verschillende gegevenstypen in waarden. Een verouderde functie gebruiken spread() dit zou heel moeilijk zijn om te doen.

Het onderstaande voorbeeld is afkomstig uit vignetten naar het pakket data tafel.

Laten we een trainingsdataframe maken.

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

Het gemaakte datumframe bevat gegevens over kinderen van één gezin op elke regel. Gezinnen kunnen één of twee kinderen hebben. Voor elk kind worden gegevens verstrekt over de geboortedatum en het geslacht, en de gegevens voor elk kind staan ​​in aparte kolommen; het is onze taak om deze gegevens in het juiste formaat voor analyse te brengen.

Houd er rekening mee dat we twee variabelen hebben met informatie over elk kind: hun geslacht en geboortedatum (kolommen met het voorvoegsel Doop bevatten geboortedatum, kolommen met voorvoegsel geslacht het geslacht van het kind bevatten). Het verwachte resultaat is dat ze in afzonderlijke kolommen moeten verschijnen. Dit kunnen we doen door een specificatie te genereren waarin de column .value zal twee verschillende betekenissen hebben.

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

Laten we dus stap voor stap kijken naar de acties die door de bovenstaande code worden uitgevoerd.

  • pivot_longer_spec(-family) — maak een specificatie die alle bestaande kolommen comprimeert, behalve de familiekolom.
  • separate(col = name, into = c(".value", "child")) - splits de kolom . Naam, dat de namen van de bronvelden bevat, waarbij het onderstrepingsteken wordt gebruikt en de resulterende waarden in de kolommen worden ingevoerd .waarde и kind.
  • mutate(child = parse_number(child)) — transformeer de veldwaarden kind van tekst naar numeriek gegevenstype.

Nu kunnen we de resulterende specificatie toepassen op het originele dataframe en de tabel in de gewenste vorm brengen.

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

Wij gebruiken argumenten na.rm = TRUE, omdat de huidige vorm van de gegevens het creëren van extra rijen voor niet-bestaande waarnemingen afdwingt. Omdat gezin 2 heeft slechts één kind, na.rm = TRUE garandeert dat familie 2 één rij in de uitvoer heeft.

Datumframes converteren van lang naar breed formaat

pivot_wider() - is de omgekeerde transformatie, en omgekeerd vergroot het aantal kolommen van het datumframe door het aantal rijen te verkleinen.

R-pakket Tidr en zijn nieuwe functies pivot_longer en pivot_wider

Dit soort transformatie wordt uiterst zelden gebruikt om gegevens in een nauwkeurige vorm te brengen, maar deze techniek kan nuttig zijn voor het maken van draaitabellen die in presentaties worden gebruikt, of voor integratie met andere tools.

Eigenlijk de functies pivot_longer() и pivot_wider() zijn symmetrisch en veroorzaken acties die omgekeerd zijn aan elkaar, dat wil zeggen: df %>% pivot_longer(spec = spec) %>% pivot_wider(spec = spec) и df %>% pivot_wider(spec = spec) %>% pivot_longer(spec = spec) zal de originele df retourneren.

Het eenvoudigste voorbeeld van het converteren van een tabel naar een breed formaat

Om te demonstreren hoe de functie werkt pivot_wider() we zullen de dataset gebruiken vis_ontmoetingen, waarin informatie wordt opgeslagen over hoe verschillende stations de beweging van vissen langs de rivier registreren.

#> # 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 de meeste gevallen zal deze tabel informatiever en gemakkelijker te gebruiken zijn als u de informatie voor elk station in een aparte kolom presenteert.

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>

Deze dataset registreert alleen informatie wanneer er vissen zijn gedetecteerd door het station, d.w.z. als een vis niet door een bepaald station is geregistreerd, staan ​​deze gegevens niet in de tabel. Dit betekent dat de uitvoer wordt gevuld met NA.

In dit geval weten we echter dat het ontbreken van een record betekent dat de vis niet is gezien, dus we kunnen het argument gebruiken waarden_fill in functie pivot_wider() en vul deze ontbrekende waarden in met nullen:

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>

Een kolomnaam genereren op basis van meerdere bronvariabelen

Stel je voor dat we een tabel hebben met daarin een combinatie van product, land en jaar. Om een ​​testdatumframe te genereren, kunt u de volgende code uitvoeren:

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

Het is onze taak om het dataframe uit te breiden, zodat één kolom gegevens bevat voor elke combinatie van product en land. Om dit te doen, geeft u gewoon het argument door namen_van een vector die de namen bevat van de velden die moeten worden samengevoegd.

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

U kunt ook specificaties op een functie toepassen pivot_wider(). Maar wanneer ingediend pivot_wider() de specificatie doet de tegenovergestelde conversie pivot_longer(): De kolommen gespecificeerd in . Naam, met behulp van waarden uit .waarde en andere kolommen.

Voor deze dataset kunt u een aangepaste specificatie genereren als u wilt dat elke mogelijke land- en productcombinatie een eigen kolom heeft, en niet alleen de kolommen die in de gegevens aanwezig zijn:

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

Een aantal geavanceerde voorbeelden van het werken met het nieuwe closer-concept

Gegevens opschonen met de dataset US Census Income and Rent als voorbeeld.

gegevensset us_rent_income bevat mediaan inkomen en huurinformatie voor elke staat in de VS voor 2017 (dataset beschikbaar in pakket nette volkstelling).

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 de vorm waarin de gegevens in de dataset zijn opgeslagen us_rent_income ermee werken is buitengewoon lastig, dus we willen graag een dataset met kolommen maken: huren, huur_moe, hoe, inkomen_moe. Er zijn veel manieren om deze specificatie te maken, maar het belangrijkste punt is dat we elke combinatie van variabele waarden en waarden moeten genereren schatting/moeen genereer vervolgens de 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

Het verstrekken van deze specificatie pivot_wider() geeft ons het resultaat waar we naar op zoek zijn:

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

De Wereldbank

Soms zijn er meerdere stappen nodig om een ​​dataset in de gewenste vorm te brengen.
Gegevensset wereld_bank_pop bevat gegevens van de Wereldbank over de bevolking van elk 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 een ​​nette dataset te maken met elke variabele in een eigen kolom. Het is onduidelijk welke stappen precies nodig zijn, maar we beginnen met het meest voor de hand liggende probleem: het jaartal is verspreid over meerdere kolommen.

Om dit op te lossen, moet je de functie gebruiken 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

De volgende stap is het kijken naar de indicatorvariabele.
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 de bevolkingsgroei is, is SP.POP.TOTL de totale bevolking, en SP.URB. * hetzelfde, maar alleen voor stedelijke gebieden. Laten we deze waarden in twee variabelen verdelen: oppervlakte - oppervlakte (totaal of stedelijk) en een variabele die feitelijke gegevens bevat (bevolking of groei):

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 hoeven we alleen de variabele in twee kolommen te splitsen:

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

Contactlijst

Nog een laatste voorbeeld: stel je voor dat je een lijst met contactpersonen hebt die je van een website hebt gekopieerd en geplakt:

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

Het in tabelvorm brengen van deze lijst is behoorlijk lastig omdat er geen variabele is die identificeert welke gegevens bij welk contact horen. We kunnen dit oplossen door op te merken dat de gegevens van elk nieuw contact beginnen met "naam", zodat we een unieke identificatie kunnen creëren en deze met één kunnen verhogen telkens wanneer de veldkolom de waarde "naam" bevat:

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 we voor elk contact een unieke ID hebben, kunnen we het veld en de waarde in kolommen omzetten:

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>

Conclusie

Mijn persoonlijke mening is dat het nieuwe concept opgeruimder echt intuïtiever en qua functionaliteit aanzienlijk superieur aan oudere functies spread() и gather(). Ik hoop dat dit artikel je heeft geholpen ermee om te gaan pivot_longer() и pivot_wider().

Bron: www.habr.com

Voeg een reactie