dplyr in R-handleiding: Gegevens samenvoegen en koppelen met voorbeelden

โšก Slimme samenvatting

dplyr voegt dataframes samen in R met vier werkwoorden: left_join(), right_join(), inner_join() en full_join(). Het bijbehorende pakket tidyr herschikt vervolgens het samengevoegde resultaat met behulp van gather(), spread(), separate() en unite().

  • ๐Ÿ”— Muterende joins: left_join() behoudt elke rij van de brontabel en right_join() behoudt elke rij van de doeltabel.
  • ๐ŸŽฏ Wedstrijdcontrole: inner_join() verwijdert rijen die niet overeenkomen, terwijl full_join() beide kanten behoudt en de gaten opvult met NA.
  • โ€‹ Samengestelde sleutels: Geef de waarde door = c(โ€œIDโ€, โ€œyearโ€) wanneer een enkele kolom geen rij uniek identificeert.
  • ๐Ÿ”„ Reshaping: gather() maakt een brede tafel lang en spread() maakt hem weer terug, keeping รฉรฉn variabele per kolom.
  • โœ‚๏ธ Splitsing en vereniging: `separate()` splitst een kolom op basis van een scheidingsteken en `unite()` voegt kolommen weer samen tot รฉรฉn kolom.
  • โš ๏ธ Versie-opmerking: pivot_longer(), pivot_wider() en separate_wider_delim() vervangen de oudere tidyr reshaping functies.

Dplyr in R: Gegevens samenvoegen en koppelen

Inleiding tot gegevensanalyse

Voordat iemand zich aansluit of iets reshaping Het werkwoord is logisch, het helpt om te zien waar gegevensmanipulatie past. Data-analyse kan worden onderverdeeld in drie delen:

  • Extractie: Ten eerste moeten we de gegevens uit vele bronnen verzamelen en combineren.
  • Transformeren: Deze stap omvat de gegevensmanipulatie. Zodra we alle gegevensbronnen hebben geconsolideerd, kunnen we beginnen met het opschonen van de gegevens.
  • Visualiseer: De laatste stap is het visualiseren van onze gegevens om onregelmatigheden te controleren.

Het onderstaande diagram laat zien hoe de drie fasen met elkaar verbonden zijn.

Driestaps data-analyseproces dat voorbeelden laat zientracverandering, transformatie en visualisatie
Gegevensanalyseproces

Een van de grootste uitdagingen voor datawetenschappers is datamanipulatie. Data is immers nooit direct beschikbaar in het gewenste formaat. Datawetenschappers moeten minstens de helft van hun tijd besteden aan het opschonen en manipuleren van de data. Dit is een van de meest cruciale taken binnen hun functie. Als het datamanipulatieproces niet volledig, nauwkeurig en grondig is, zal het model niet naar behoren functioneren.

R dplyr

R heeft een pakket genaamd dplyr dat datatransformatie afhandelt. Het is opgebouwd rond een kleine set kernfuncties โ€” filter(), select(), arrange(), mutate() en summarise() โ€” plus een reeks join-functies. Zodra de data in de juiste vorm is, kan ggplot2 deze visualiseren.

We zullen leren hoe we het dplyr-pakket kunnen gebruiken om een GegevensframeAls R nog niet is geรฏnstalleerd, volg dan de instructies. Installatiestappen voor R en RStudioVoer vervolgens install.packages("dplyr") uit.

Gegevens samenvoegen met dplyr

dplyr biedt een leuke en handige manier om datasets te combineren. We hebben mogelijk veel bronnen van invoergegevens en op een gegeven moment moeten we ze combineren. Een join met dplyr voegt variabelen toe aan de rechterkant van de oorspronkelijke gegevensset.

dplyr sluit zich aan

Hieronder volgen vier belangrijke soorten joins die in dplyr worden gebruikt om twee datasets samen te voegen. Alle vier gebruiken dezelfde argumenten โ€” de twee tabellen en de sleutel โ€” en verschillen alleen in welke niet-overeenkomende rijen behouden blijven:

Functie Objectief argumenten Meerdere sleutels
left_join() Voeg twee datasets samen. Bewaar alle waarnemingen uit de oorsprongstabel x, y, by = โ€œIDโ€ x, y, by = c(โ€œIDโ€, โ€œID2โ€)
right_join() Voeg twee datasets samen. Bewaar alle waarnemingen uit de bestemmingstabel x, y, by = โ€œIDโ€ x, y, by = c(โ€œIDโ€, โ€œID2โ€)
innerlijke_join() Voeg twee datasets samen. Sluit alle niet-overeenkomende rijen uit. x, y, by = โ€œIDโ€ x, y, by = c(โ€œIDโ€, โ€œID2โ€)
volledige_join() Voeg twee datasets samen. Behoud alle waarnemingen. x, y, by = โ€œIDโ€ x, y, by = c(โ€œIDโ€, โ€œID2โ€)

Deze vier werkwoorden corresponderen met de LINKER-, RECHTER-, BINNENSTE- en VOLLE BUITENSTE-verbindingen van SQL. Base R bereikt dezelfde resultaten via de argumenten all, all.x en all.y van samenvoegen().

We zullen alle soorten joins bestuderen aan de hand van een eenvoudig voorbeeld.

Allereerst maken we twee datasets aan. Tabel 1 bevat twee variabelen, ID en y, terwijl Tabel 2 ID en z verzamelt. In beide gevallen hebben we een sleutelpaar variabel. In ons geval is ID onze sleutel variabele. De functie zoekt naar identieke waarden in beide tabellen en koppelt de geretourneerde waarden aan de rechterkant van tabel 1. De onderstaande afbeelding toont de twee tabellen naast elkaar.

Twee voorbeeldtabellen die een ID-sleutelkolom delen vรณรณr een dplyr-samenvoeging.

library(dplyr)
df_primary <- tribble(
  ~ID, ~y,
   "A", 5,
   "B", 5,
   "C", 8,
   "D", 0,
  "F", 9)
df_secondary <- tribble(
  ~ID, ~z,
   "A", 30,
   "B", 21,
   "C", 22,
   "D", 25,
   "E", 29)

dplyr left_join()

De meest gebruikelijke manier om twee datasets samen te voegen is met behulp van de functie left_join(). De onderstaande afbeelding laat zien dat het sleutelpaar overeenkomt met rijen A, B, C en D, terwijl E en F overblijven. Met left_join() behouden we alle rijen in de oorspronkelijke tabel en negeren we de rijen die geen sleutelpaar hebben in de doeltabel. In ons voorbeeld bestaat de waarde E niet in tabel 1, dus die rij wordt verwijderd. De waarde F komt uit de oorspronkelijke tabel, dus die wordt behouden na de left_join() en retourneert NA in kolom z.

Voorbeeld van dplyr left_join()

Het onderstaande diagram laat zien wat er gebeurt tijdens een left_join().

Diagram van dplyr left_join keeping elke rij van de oorspronkelijke tabel verwijderenping ID E

left_join(df_primary, df_secondary, by ='ID')

Output:

## 
# A tibble: 5 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>		
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25
## 5     F     9    NA

Merk op dat wanneer beide tabellen een kolom met dezelfde naam bevatten, dplyr deze onderscheidt met de achtervoegsels .x en .y zoals hierboven weergegeven.

dplyr right_join()

De functie right_join() werkt precies zoals left_join(). Het enige verschil is dat de rij is geschrapt. De waarde E, beschikbaar in het doelgegevensframe, bestaat in de nieuwe tabel en neemt de waarde NA aan voor de kolom y.

Voorbeeld van dplyr right_join()

Onderstaande afbeelding toont het spiegelbeeld.

Diagram van dplyr right_join keeping elke rij van de doeltabel verwijderenping ID F

right_join(df_primary, df_secondary, by = 'ID')

Output:

##
# A tibble: 5 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25
## 5     E    NA    29

dplyr inner_join()

Als niet-overeenkomende waarnemingen helemaal niet bruikbaar zijn, kunnen we ze retourneren. Slechts de rijen die bestaan โ€‹โ€‹in zowel datasets. Dit is de juiste keuze wanneer we een complete dataset nodig hebben en ontbrekende waarden niet willen invullen met het gemiddelde of de mediaan.

De functie inner_join() biedt hier uitkomst. Deze sluit de rijen aan beide zijden uit die niet overeenkomen.

Voorbeeld van dplyr inner_join()

Het onderstaande diagram toont de vier ID's die na de samenvoeging behouden blijven.

Diagram van dplyr inner_join die alleen de vier ID's retourneert die in beide tabellen voorkomen.

inner_join(df_primary, df_secondary, by ='ID')

Output:

## 
# A tibble: 4 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25

dplyr full_join()

Tot slot behoudt de functie full_join() alle waarnemingen en vervangt ontbrekende waarden door NA.

Voorbeeld van dplyr full_join()

Het onderstaande diagram toont alle ID's uit beide tabellen die na de samenvoeging behouden blijven.

Diagram van dplyr full_join keeping alle zes ID's en het invullen van ontbrekende waarden met NA

full_join(df_primary, df_secondary, by = 'ID')

Output:

## # A tibble: 6 x 3
##      ID   y.x   y.y
##   <chr> <dbl> <dbl>
## 1     A     5    30
## 2     B     5    21
## 3     C     8    22
## 4     D     0    25
## 5     F     9    NA
## 6     E    NA    29

Meerdere sleutelparen

Tot slot kunnen we meerdere sleutels in onze dataset hebben. Neem bijvoorbeeld de volgende dataset met jaartallen en een lijst met producten die door de klant zijn gekocht. De onderstaande schermafbeelding toont de twee tabellen en de kolommen ID en jaar die samen een rij identificeren.

Twee dataframes die een samengestelde sleutel delen, bestaande uit de kolommen ID en jaar.

Als we beide tabellen alleen op basis van ID samenvoegen, wordt elk jaar aan elk ander jaar gekoppeld en explodeert het aantal rijen. Om dit te verhelpen, kunnen we twee sleutel-waardeparen doorgeven: ID en jaar, die in beide datasets voorkomen. We kunnen de volgende code gebruiken om tabel 1 en tabel 2 samen te voegen:

df_primary <- tribble(
  ~ID, ~year, ~items,
  "A", 2015,3,
  "A", 2016,7,
  "A", 2017,6,
  "B", 2015,4,
  "B", 2016,8,
  "B", 2017,7,
  "C", 2015,4,
  "C", 2016,6,
  "C", 2017,6)
df_secondary <- tribble(
  ~ID, ~year, ~prices,
  "A", 2015,9,
  "A", 2016,8,
  "A", 2017,12,
  "B", 2015,13,
  "B", 2016,14,
  "B", 2017,6,
  "C", 2015,15,
  "C", 2016,15,
  "C", 2017,13)
left_join(df_primary, df_secondary, by = c('ID', 'year'))

Output:

## # A tibble: 9 x 4
##      ID  year items prices
##   <chr> <dbl> <dbl>  <dbl>
## 1     A  2015     3      9
## 2     A  2016     7      8
## 3     A  2017     6     12
## 4     B  2015     4     13
## 5     B  2016     8     14
## 6     B  2017     7      6
## 7     C  2015     4     15
## 8     C  2016     6     15
## 9     C  2017     6     13

Sinds dplyr 1.1.0 (januari 2023) kan dezelfde sleutel worden geschreven als join_by(ID, year), en dplyr waarschuwt nu voor onverwachte vele-op-vele-relaties, omdat de dplyr 1.1.0 voegt zich bij de aankondiging verklaart.

Gegevensopschoonfuncties in R

Het samenvoegen lost slechts de helft van het probleem op, omdat de gecombineerde tabel nog steeds opnieuw moet worden opgemaakt. Hieronder volgen de vier belangrijkste functies om de gegevens op te schonen:

Functie Objectief argumenten
bijeenkomen() Transformeer de gegevens van breed naar lang (gegevens, sleutel, waarde, na.rm = FALSE)
spreiding() Transformeer de gegevens van lang naar breed (gegevens, sleutel, waarde)
verschillend() Splits รฉรฉn variabele op in tweeรซn (data, col, into, sep = โ€œโ€, remove = TRUE)
verenigen() Twee variabelen samenvoegen tot รฉรฉn (data, col, conc, sep = โ€œโ€, remove = TRUE)

Versie-opmerking: De functies gather() en spread() werden in tidyr 1.0.0 vervangen door pivot_longer() en pivot_wider(), en separate() door de separate_wider_delim()-familie in tidyr 1.3.0. De vervangen functies werken nog steeds, dus alle onderstaande voorbeelden zijn correct, maar nieuwe code zou de voorkeur moeten geven aan de nieuwere families die in de documentatie worden weergegeven. tidyr draaibare vignet. unite() blijft actueel.

We gebruiken het tidyr-pakket, onderdeel van de tidyverse-collectie, voor het manipuleren, opschonen en visualiseren van data. Als R is geรฏnstalleerd met Anaconda, is het pakket al beschikbaar via https://anaconda.org/r/r-tidyr.

Als het nog niet is geรฏnstalleerd, voer dan de volgende opdracht in om tidyr te installeren:

install.packages("tidyr")

bijeenkomen()

Het doel van de functie gather() is om de gegevens van breed naar lang te transformeren.

Syntaxis

gather(data, key, value, na.rm = FALSE)
Arguments:
-data: The data frame used to reshape the dataset 
-key: Name of the new column created
-value: Select the columns used to fill the key column
-na.rm: Remove missing values. FALSE by default

Voorbeeld

Hieronder kunnen we het concept van resha visualiseren.ping Van breed naar lang. We willen รฉรฉn kolom maken met de naam 'groei', gevuld met de rijen van de kwartaalvariabelen. De onderstaande afbeelding toont de brede tabel aan de linkerkant en de aangepaste lange tabel aan de rechterkant.

Reshaping een brede kwartaaltabel omzetten naar een lange tabelindeling met behulp van de tidyr gather-functie

library(tidyr)
# Create a messy dataset
messy <- data.frame(
  country = c("A", "B", "C"),
  q1_2017 = c(0.03, 0.05, 0.01),
  q2_2017 = c(0.05, 0.07, 0.02),
  q3_2017 = c(0.04, 0.05, 0.01),
  q4_2017 = c(0.03, 0.02, 0.04))
messy

Output:

##   country q1_2017 q2_2017 q3_2017 q4_2017
## 1       A    0.03    0.05    0.04    0.03
## 2       B    0.05    0.07    0.05    0.02
## 3       C    0.01    0.02    0.01    0.04
# Reshape the data
tidier <-messy %>%
gather(quarter, growth, q1_2017:q4_2017)
tidier

Output:

##    country quarter growth
## 1        A q1_2017   0.03
## 2        B q1_2017   0.05
## 3        C q1_2017   0.01
## 4        A q2_2017   0.05
## 5        B q2_2017   0.07
## 6        C q2_2017   0.02
## 7        A q3_2017   0.04
## 8        B q3_2017   0.05
## 9        C q3_2017   0.01
## 10       A q4_2017   0.03
## 11       B q4_2017   0.02
## 12       C q4_2017   0.04

In de gather()-functie maken we twee nieuwe variabelen aan, quarter en growth, omdat onze oorspronkelijke dataset รฉรฉn groepsvariabele bevat, country, en de sleutel-waardeparen. In tidyr 1.0.0 en later wordt dezelfde reshape geschreven als pivot_longer(messy, cols = q1_2017:q4_2017, names_to = โ€œquarterโ€, values_to = โ€œgrowthโ€).

spreiding()

De spread()-functie doet het tegenovergestelde van gather().

Syntaxis

spread(data, key, value)
arguments: 
data: The data frame used to reshape the dataset
key: Column to reshape long to wide
value: Rows used to fill the new column

Voorbeeld

We kunnen de nettere dataset weer omvormen tot een rommelige dataset met behulp van spread().

# Reshape the data
messy_1 <- tidier %>%
  spread(quarter, growth) 
messy_1

Output:

##   country q1_2017 q2_2017 q3_2017 q4_2017
## 1       A    0.03    0.05    0.04    0.03
## 2       B    0.05    0.07    0.05    0.02
## 3       C    0.01    0.02    0.01    0.04

Het moderne equivalent is pivot_wider(tidier, names_from = quarter, values_from = growth).

verschillend()

De functie `separate()` splitst een kolom in tweeรซn op basis van een scheidingsteken. Deze functie is handig in situaties waarin de variabele een datum is. Onze analyse vereist mogelijk dat we ons richten op de maand en het jaar, en we willen de kolom dan opsplitsen in twee nieuwe variabelen.

Syntaxis

separate(data, col, into, sep= "", remove = TRUE)
arguments:
-data: The data frame used to reshape the dataset 
-col: The column to split
-into: The name of the new variables
-sep: Indicates the symbol used that separates the variable, i.e.:  "-", "_", "&"
-remove: Remove the old column. By default sets to TRUE.

Voorbeeld

We kunnen het kwartaal van het jaar splitsen in de overzichtelijkere dataset door de functie separate() toe te passen.

separate_tidier <-tidier %>%
separate(quarter, c("Qrt", "year"), sep ="_")
head(separate_tidier)

Output:

##   country Qrt year growth
## 1       A  q1 2017   0.03
## 2       B  q1 2017   0.05
## 3       C  q1 2017   0.01
## 4       A  q2 2017   0.05
## 5       B  q2 2017   0.07
## 6       C  q2 2017   0.02

verenigen()

De functie unite() voegt twee kolommen samen tot รฉรฉn.

Syntaxis

unite(data, col, conc ,sep= "", remove = TRUE)
arguments:
-data: The data frame used to reshape the dataset 
-col: Name of the new column
-conc: Name of the columns to concatenate
-sep: Indicates the symbol used that unites the variable, i.e:  "-", "_", "&"
-remove: Remove the old columns. By default, sets to TRUE

Voorbeeld

In het bovenstaande voorbeeld hebben we het kwartaal en het jaar gescheiden. Wat als we ze willen samenvoegen? Dan gebruiken we de volgende code:

unit_tidier <- separate_tidier %>%
  unite(Quarter, Qrt, year, sep ="_")
head(unit_tidier)

Output:

##   country Quarter growth
## 1       A q1_2017   0.03
## 2       B q1_2017   0.05
## 3       C q1_2017   0.01
## 4       A q2_2017   0.05
## 5       B q2_2017   0.07
## 6       C q2_2017   0.02

Het herschikte dataframe is nu klaar voor de modelleringsstappen die in de rest van dit document worden behandeld. R-zelfstudieserie.

Veelgestelde vragen

`merge()` drukt elke join uit via de vlaggen `all`, `all.x` en `all.y`, terwijl `dplyr` het gedrag in de functie zelf benoemt. `dplyr` behoudt ook de oorspronkelijke rijvolgorde en retourneert een tibble. De basisroute in R wordt behandeld in de dataframes samenvoegen gids.

Het zijn filterende joins, dus er worden nooit kolommen toegevoegd. `semi_join(x, y)` behoudt de rijen van `x` die een overeenkomst hebben in `y`, en `anti_join(x, y)` behoudt de rijen die dat niet hebben. Beide zijn handig om sleutels te controleren voordat een muterende join wordt uitgevoerd.

Map ze expliciet met by = c(โ€œIDโ€ = โ€œcustomer_idโ€), of gebruik de nieuwere helperfunctie join_by(ID == customer_id). Zonder een mappingdplyr zoekt naar overeenkomsten op basis van elke gedeelde kolomnaam, wat het resultaat ongemerkt kan verkleinen of juist enorm kan vergroten.

Een sleutelwaarde herhaalt zich aan beide zijden, waardoor elke combinatie wordt gegenereerd. Controleer eerst de waarde van `duplicated()` op elke sleutel, aggregeer de vele-op-vele-relatie of geef `relationship = โ€œmany-to-manyโ€` door om de intentie aan te geven. dplyr waarschuwt voor onverwachte vele-op-vele-relaties.

filter() selecteert rijen, select() selecteert kolommen, arrange() spreuken`mutate()` voegt kolommen toe en `summarise()` vouwt groepen samen die zijn gemaakt door `group_by()`. De pipe geeft het ene resultaat door aan het volgende werkwoord; `%>%` wordt meegeleverd met dplyr en `|>` is standaard R.

AI-assistenten kunnen een dataframe profileren, dubbele of verkeerd getypte sleutels markeren vรณรณr een join, en suggesties doen voor een resha.ping Gebruik een werkwoord dat bij de lay-out past en leg een plotselinge verandering in het aantal rijen in eenvoudige taal uit. Voer de code altijd opnieuw uit en controleer de afmetingen zelf.

Ja. GitHub-copiloot Werkt in RStudio Desktop 2023.09.0 en later en voltooit join- en pivot-pipelines op basis van een commentaar. Posit merkt op dat suggesties niet-deterministisch zijn, dus controleer elke gegenereerde regel voordat u deze uitvoert.

Koppel de joins aan elkaar, of vouw een lijst met Reduce(function(x, y) left_join(x, y, by = โ€œIDโ€), list(df1, df2, df3)). purrr::reduce() doet hetzelfde. Controleer nrow() na elke stap, omdat dubbele sleutels zich ophopen bij joins.

Vat dit bericht samen met: