Slå samman dataramar i R: Full och partiell matchning

⚡ Smart sammanfattning

Att sammanfoga dataramar i R sammanfogar två tabeller på en eller flera kolumner med delade nyckelringar. Funktionen merge() täcker inner-, vänster-, höger- och fullständiga kopplingar, och den här genomgången demonstrerar både en fullständig matchning och en partiell matchning.

  • 🔑 Viktiga kolumner: merge() sammanfogar vid by, eller vid by.x och by.y när nyckeln har olika namn i varje ram.
  • 🔗 Hela matchen: Standardinställningen för inner join behåller bara de rader vars nyckel visas i båda dataframes.
  • 🧩 Delvis matchning: Om all.x = TRUE sätts behålls varje rad i den första bildrutan och luckorna fylls med NA.
  • 📐 Måttkontroll: Jämför dim() före och efter en sammanslagning för att fånga rader som förlorats eller duplicerats av sammanfogningen.
  • ⚙️ Anslutningskontroll: Flaggorna all, all.x och all.y väljer inre, vänster, höger eller fullständigt yttre beteende.
  • 🛠️ Modernt alternativ: dplyr-namnen sammanfogar sig varje namn i själva verbet och bevarar den ursprungliga radordningen.

Slå samman dataramar i R

Mycket ofta har vi data från flera källor. För att göra en analys måste vi göra det sammanfoga två dataramar tillsammans med en eller flera vanliga nyckelvariabler.

Typer av sammanslagningar (Join) i R

Innan du går igenom exemplen är det bra att veta att merge() utför alla join-typer som en SQL-användare förväntar sig. Beteendet styrs av argumenten all, all.x och all.y snarare än av ett annat funktionsnamn.

Gå med typ Rader behållna merge()-anrop dplyr-ekvivalent
Inre koppling (standard) Endast nycklar finns i båda ramarna sammanfoga(x, y, by = “k”) inner_join(x, y, by = “k”)
Vänster yttre skarv Alla rader av x, NA där y inte har någon matchning merge(x, y, by = "k", all.x = TRUE) vänster_join(x, y, by = “k”)
Höger yttre fog Alla rader i y, NA där x inte har någon matchning merge(x, y, by = "k", all.y = TRUE) höger_join(x, y, by = “k”)
Full ytterskarv Varje rad från båda ramarna merge(x, y, by = "k", all = TRUE) full_join(x, y, by = “k”)
Kors gå med Varje kombination av rader merge(x, y, by = NULL) korskoppling(x, y)

Två detaljer är värda att komma ihåg före det första samtalet:

  • Om du utelämnar 'by' görs R-sammanslagning på varje kolumnnamn som de två ramarna delar, vilket sällan är vad man vill.
  • merge() sorterar resultatet efter nyckelkolumnen; använd sort = FALSE för att behålla den inkommande ordningen.

Hel match

En fullständig matchning returnerar endast de värden som har en motsvarighet i måltabellen. Rader utan matchning tas bort från den nya dataframen. En partiell matchning, däremot, behåller dessa rader och fyller de saknade kolumnerna med NA.

Vi kommer att se en enkel inre koppling. Nyckelordet inre join väljer poster som har matchande värden i båda tabellerna. För att sammanfoga två datamängder kan vi använda funktionen merge(). Vi kommer att använda tre argument:

merge(x, y, by.x = x, by.y = y)

Arguments:
-x: The origin data frame
-y: The data frame to merge
-by.x: The column used for merging in x data frame. Column x to merge on
-by.y: The column used for merging in y data frame. Column y to merge on

Exempel:

Skapa första datamängden med variabler

  • efternamn
  • nationalitet

Skapa en andra datamängd med variabler

  • efternamn
  • filmer

Den gemensamma nyckelvariabeln är efternamn. Vi kan slå samman båda dataramar och kontrollera att dimensionen är 7×3.

Vi lägger till stringsAsFactors=FALSE i dataframen eftersom vi inte vill R att omvandla strängarna till en faktor; variabeln bör förbli en teckenvektor. Sedan R 4.0.0 är detta redan standard för data.frame(), så argumentet är valfritt i ny kod och ofarligt i gammal kod.

# Create origin dataframe(

producers <- data.frame(   
    surname =  c("Spielberg","Scorsese","Hitchcock","Tarantino","Polanski"),    
    nationality = c("US","US","UK","US","Poland"),    
    stringsAsFactors=FALSE)

# Create destination dataframe
movies <- data.frame(    
    surname = c("Spielberg",
		"Scorsese",
                "Hitchcock",
              	"Hitchcock",
                "Spielberg",
                "Tarantino",
                "Polanski"),    
    title = c("Super 8",
    		"Taxi Driver",
    		"Psycho",
    		"North by Northwest",
    		"Catch Me If You Can",
    		"Reservoir Dogs","Chinatown"),                
     		stringsAsFactors=FALSE)

# Merge two datasets
m1 <- merge(producers, movies, by.x = "surname")
m1
dim(m1)

Produktion:

surname		nationality		title
1 Hitchcock		UK		Psycho
2 Hitchcock		UK		North by Northwest
3 Polanski		Poland		Chinatown
4 Scorsese		US		Taxi Driver
5 Spielberg		US		Super 8
6 Spielberg		US		Catch Me If You Can
7 Tarantino		US		Reservoir Dogs

Låt oss slå samman dataramar när de vanliga nyckelvariablerna har olika namn.

Vi byter efternamn till namn i filmens dataram. Vi använder funktionen identisk(x1, x2) för att kontrollera om båda dataramarna är identiska.

# Change name of ` movies ` dataframe
colnames(movies)[colnames(movies) == 'surname'] <- 'name'
# Merge with different key value
m2 <- merge(producers, movies, by.x = "surname", by.y = "name")
# Print head of the data
head(m2)

Produktion:

##surname     nationality		title
## 1 Hitchcock          UK		Psycho
## 2 Hitchcock          UK		North by Northwest
## 3 Polanski          Poland		Chinatown
## 4 Scorsese           US		Taxi Driver
## 5 Spielberg          US		Super 8
## 6 Spielberg          US		Catch Me If You Can
# Check if data are identical
identical(m1, m2)

Produktion:

## [1] TRUE

Detta visar att sammanslagningsoperationen utförs även om kolumnnamnen är olika.

Delvis matchning

Den inre kopplingen ovan tappade tyst allt utan en motsvarighet. Det är inte förvånande att två dataframes inte har samma gemensamma nyckelvariabler. I full matchning, returnerar dataramen endast rader som finns i både x- och y-dataramen. Med partiell sammanslagning, är det möjligt att behålla raderna utan matchande rader i den andra dataramen. Dessa rader kommer att ha NA i de kolumner som vanligtvis är fyllda med värden från y. Vi kan göra det genom att ställa in all.x= TRUE.

Till exempel kan vi lägga till en ny producent, Lucas, i producentens dataframe utan filmreferenserna i filmernas dataframe. Om vi ​​sätter all.x = FALSE kommer R endast att koppla samman de matchande värdena i båda datamängderna. I vårt fall kommer producenten Lucas inte att kopplas till resultatet, eftersom han saknas i en datamängd.

Låt oss se dimensionen för varje utdata när vi anger all.x= TRUE och när vi inte gör det.

# Create a new producer
add_producer <-  c('Lucas', 'US')
#  Append it to the ` producer` dataframe
producers <- rbind(producers, add_producer)
# Use a partial merge 
m3 <-merge(producers, movies, by.x = "surname", by.y = "name", all.x = TRUE)
m3

Produktion:

Konsolutgången nedan visar den extra Lucas-raden, där NA står för den saknade filmtiteln.

Konsolutdata för den partiella sammanslagningen som visar Lucas med NA i titelkolumnen

# Compare the dimension of each data frame
dim(m1)

Produktion:

## [1] 7 3
dim(m2)

Produktion:

## [1] 7 3
dim(m3)

Produktion:

## [1] 8 3

Som vi kan se är den nya dataframen 8×3, jämfört med 7×3 för m1 och m2. R fyller titelkolumnen med NA för Lucas, producenten som inte har någon matchande rad i filmens dataframe.

merge() vs dplyr Joins i R

Base R löser varje join med en funktion och en uppsättning flaggor. dplyr paketet ger istället varje join sitt eget verb, vilket många team tycker är lättare att läsa i en pipeline.

Kriterier Bassammanslagning() dplyr-anslutningar
Att välja koppling all.x / all.y / alla flaggor Namngivet i verbet: left_join(), full_join()
Radordning Sorteras efter nyckel om inte sortering = FALSKT Ordningen i den vänstra tabellen bevaras
Hastighet på stora bildrutor Långsammare Generellt snabbare
Saknad nyckelkolumn Misslyckas sent eller sammanfogas på fel kolumner Fel omedelbart
beroenden Bas R, inget att installera Kräver dplyr-paketet

De två sammanslagningarna som visas ovan översätts direkt till dplyr-verb:

library(dplyr)
# Same inner join as merge(producers, movies, by.x = "surname", by.y = "name")
m4 <- inner_join(producers, movies, by = c("surname" = "name"))
# Same partial merge as all.x = TRUE
m5 <- left_join(producers, movies, by = c("surname" = "name"))

Base merge() är det säkrare valet i ett paket som inte ska ha några beroenden. dplyr är det bättre valet i en interaktiv analys, där läsbarhet och hastighet är viktigare.

Vanliga sammanslagningsfel i R och hur man åtgärdar dem

De flesta sammanslagningsproblem anger sig själva som ett oväntat radantal snarare än ett felmeddelande, så att kontrollera dim() efter varje sammankoppling är en vana värd att bygga upp.

  • Resultatet har fler rader än någon av indatavärdena. En nyckel som upprepas i båda ramarna producerar en många-till-många-koppling, och R returnerar varje kombination. Kontrollera nycklarna med table(duplicated(x$k)) innan de sammanfogas.
  • Resultatet är tomt. Nyckelkolumnerna skiljer sig vanligtvis åt i typ, eller så har en av dem mellanslag. Kör str() på båda ramarna och rensa nyckeln med trimws() innan sammanfogningen.
  • Kolumner återkommer som title.x och title.y. Båda bildrutorna har en icke-nyckelkolumn med samma namn. Skicka suffix = c("_producer", "_film") för att göra ursprunget uppenbart.
  • Raderna är inte längre i sin ursprungliga ordning. merge() sorterar på nyckeln som standard. Lägg till sort = FALSE, eller använd en explicit sort efteråt.
  • En viktig jämförelse misslyckas med faktorer. Jämför tecken, inte faktornivåer: linda in nyckeln i as.character() innan ramar som skapats under äldre R-standardvärden sammanfogas.

När samma sammanslagning måste köras upprepade gånger, linda in den i en användardefinierad funktion så argumenten kan inte glida mellan körningarna.

Vanliga frågor

R sammanfogar på varje kolumnnamn som de två ramarna delar. Med en delad kolumn är det bekvämt; med flera begränsar det resultatet tyst, och med ingen returnerar det en korskoppling. Att namnge nyckeln explicit undviker alla tre överraskningar.

Inte i ett enda merge()-anrop. Kedja anropen, eller vik en lista med Reduce(function(x, y) merge(x, y, by = “k”), list(df1, df2, df3)). Verifiera radantalet efter varje steg, eftersom duplicerade nycklar snabbt sammansätts.

Båda bildrutorna hade en icke-nyckelkolumn med samma namn, så R avklarar dem. Skicka suffix = c("_producer", "_film") för att ge kopiorna meningsfulla namn, eller ta bort den redundanta kolumnen innan sammanslagning.

Nej. merge() sorterar resultatet på nyckelkolumnen som standard. Skicka sort = FALSE för att behålla den inkommande ordningen, eller använd en dplyr koppling, vilket bevarar ordningen på den vänstra ramen.

Ange en vektor: merge(x, y, by = c("efternamn", "år")). När namnen skiljer sig åt, skicka matchande vektorer till by.x och by.y. Båda vektorerna måste lista kolumnerna i samma ordning.

Använd by = "row.names", eller förkortningen by = 0. R lägger tillbaka radnamnen som en kolumn som heter Row.names, som du vanligtvis vill byta namn på eller ta bort innan du fortsätter analysen.

Beskriv de två bildrutorna och radantalet, så pekar en AI-assistent på duplicerade nycklar som den troligaste orsaken och föreslår en duplicate()-kontroll. Bekräfta diagnosen mot dina egna data innan du ändrar kopplingen.

Ja. RStudio Desktop 2023.09.0 och senare levereras med ett alternativ för att välja att delta GitHub Copilot integration som utarbetar en sammanslagning från en kommentar. Kontrollera vilken sammanslagningstyp den väljer, eftersom en fel flagga ändrar radantalet tyst.

Sammanfatta detta inlägg med: