Обединяване на кадри с данни в R: пълно и частично съвпадение

⚡ Умно обобщение

Сливането на рамки с данни в R свързва две таблици по една или повече колони със споделен ключ. Функцията merge() обхваща вътрешни, леви, десни и пълни съединения, а това ръководство демонстрира както пълно, така и частично съвпадение.

  • 🔑 Ключови колони: merge() се свързва с by или с by.x и by.y, когато ключът носи различно име във всеки кадър.
  • 🔗 Пълен мач: Вътрешното съединение по подразбиране запазва само редовете, чийто ключ се появява и в двата кадъра с данни.
  • 🧩 Частично съвпадение: Задаването на all.x = TRUE запазва всеки ред от първия кадър и запълва празните места с NA.
  • 📐 Проверка на размерите: Сравнете dim() преди и след сливане, за да уловите загубени или дублирани редове от съединението.
  • Присъединяване към контрола: Флаговете all, all.x и all.y избират поведение inner, left, right или full outner.
  • 🛠️ Модерна алтернатива: dplyr имената се свързват в самия глагол и запазват оригиналния ред на редовете.

Обединяване на кадри с данни в R

Много често имаме данни от множество източници. За да извършим анализ, трябва да се сливат две рамки с данни заедно с една или повече общи ключови променливи.

Видове сливания (Join) в R

Преди да разгледаме примерите, е полезно да знаем, че merge() изпълнява всеки тип съединение, който един SQL потребител очаква. Поведението се контролира от аргументите all, all.x и all.y, а не от различно име на функция.

Тип присъединяване Редовете са запазени извикване на merge() еквивалент на dplyr
Вътрешно съединение (по подразбиране) Само ключове, присъстващи и в двата кадъра сливане(x, y, от = „k“) вътрешно_съединяване(x, y, от = „k“)
Ляво външно съединение Всички редове на x, NA, където y няма съвпадение сливане(x, y, от = „k“, всички.x = TRUE) ляво_съединяване(x, y, от = „k“)
Десен външен съединител Всички редове на y, NA, където x няма съвпадение сливане(x, y, от = „k“, всички.y = TRUE) right_join(x, y, от = „k“)
Пълно външно съединяване Всеки ред от двата кадъра сливане(x, y, от = „k“, всички = TRUE) пълно_съединяване(x, y, от = „k“)
Кръстосано присъединяване Всяка комбинация от редове сливане(x, y, от = NULL) кръстосано_съединяване(x, y)

Две подробности, които си струва да запомните преди първото обаждане:

  • Пропускането на „by“ кара R да се слива с всяко име на колона, което двете рамки споделят, което рядко е това, което искате.
  • merge() сортира резултата по ключовата колона; подайте sort = FALSE, за да запазите входящия ред.

Пълен мач

Пълното съвпадение връща само стойностите, които имат еквивалент в целевата таблица. Редовете без съвпадение се премахват от новия кадър с данни. Частичното съвпадение, за разлика от това, запазва тези редове и запълва липсващите колони с NA.

Ще видим просто вътрешно присъединяване. Ключовата дума inner join избира записи, които имат съвпадащи стойности и в двете таблици. За да обединим два набора от данни, можем да използваме функцията merge(). Ще използваме три аргумента:

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

Пример:

Създайте първи набор от данни с променливи

  • фамилно име
  • националност

Създайте втори набор от данни с променливи

  • фамилно име
  • кино

Общата ключова променлива е фамилното име. Можем да обединим и двете рамки с данни и проверете дали размерността е 7×3.

Добавяме stringsAsFactors=FALSE в рамката с данни, защото не искаме R да преобразува низовете в фактор; променливата трябва да остане вектор от символи. От R 4.0.0 насам това вече е стойността по подразбиране за data.frame(), така че аргументът е незадължителен в новия код и безвреден в стария код.

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

Изход:

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

Нека обединим рамки с данни, когато общите ключови променливи имат различни имена.

Променяме фамилното име на име в рамката с данни за филми. Използваме функцията identical(x1, x2), за да проверим дали и двете рамки с данни са идентични.

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

Изход:

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

Изход:

## [1] TRUE

Това показва, че операцията по сливане се извършва дори ако имената на колоните са различни.

Частично съвпадение

Вътрешното съединение по-горе тихо премахва всичко без съответстващ елемент. Не е изненадващо, че два фрейма от данни нямат едни и същи общи ключови променливи. В пълно съвпадение, рамката с данни се връща само за лична употреба редове, открити както в x, така и в y рамка с данни. с частично сливане, е възможно да запазите редовете без съвпадащи редове в другия кадър с данни. Тези редове ще имат NA в тези колони, които обикновено се пълнят със стойности от y. Можем да направим това, като зададем all.x= TRUE.

Например, можем да добавим нов продуцент, Лукас, в рамката с данни за продуцента, без да имаме референции към филми в нея. Ако зададем all.x= FALSE, R ще обедини само съответстващите стойности и в двата набора от данни. В нашия случай продуцентът Лукас няма да бъде обединен в резултата, защото липсва в единия набор от данни.

Нека видим измерението на всеки изход, когато посочим all.x= TRUE и когато не го направим.

# 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

Изход:

Изходът от конзолата по-долу показва допълнителния ред за Lucas, като NA замества липсващото заглавие на филма.

Конзолен изход от частичното сливане, показващ Lucas с NA в колоната за заглавие

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

Изход:

## [1] 7 3
dim(m2)

Изход:

## [1] 7 3
dim(m3)

Изход:

## [1] 8 3

Както виждаме, новият кадър от данни е 8×3, в сравнение със 7×3 за m1 и m2. R запълва колоната за заглавие с NA за Лукас, продуцентът, който няма съответстващ ред във кадъра от данни за филмите.

merge() срещу dplyr Присъединявания в R

Базовият R решава всяко съединение с една функция и набор от флагове. dplyr пакетът вместо това дава на всяко съединение собствен глагол, който много екипи намират за по-лесен за четене в конвейер.

Критерии Базово сливане() dplyr се присъединява
Избор на съединението all.x / all.y / всички флагове Наименувани в глагола: left_join(), full_join()
Ред на редовете Сортирано по ключ, освен ако sort = FALSE Редът на лявата таблица е запазен
Скорост при големи кадри По-бавно Като цяло по-бързо
Липсваща ключова колона Неуспешно закъснява или се слива в грешните колони Грешки веднага
Зависимостите База R, няма какво да се инсталира Изисква пакета dplyr

Двете сливания, показани по-горе, се превеждат директно в dplyr глаголи:

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

Базовото merge() е по-безопасният избор в рамките на пакет, който не би трябвало да има зависимости. dplyr е по-добрият избор в интерактивен анализ, където четимостта и скоростта са по-важни.

Често срещани грешки при сливане в R и как да ги поправим

Повечето проблеми със сливането се обявяват като неочакван брой редове, а не като съобщение за грешка, така че проверката на dim() след всяко съединение е навик, който си струва да се изгради.

  • Резултатът има повече редове от всеки от входните данни. Ключ, който се повтаря и в двата кадъра, създава съединение „много към много“ и R връща всяка комбинация. Проверете ключовете с table(duplicated(x$k)) преди сливане.
  • Резултатът е празен. Ключовите колони обикновено се различават по тип или едната съдържа интервали в края. Изпълнете str() и на двата кадъра и почистете ключа с trimws() преди сливането.
  • Колоните се връщат като title.x и title.y. И двата кадъра съдържат неключова колона с едно и също име. Предайте суфикси = c(“_producer”, “_film”), за да направите произхода ясен.
  • Редовете вече не са в първоначалния си ред. merge() сортира по ключа по подразбиране. Добавете sort = FALSE или използвайте изрично сортиране след това.
  • Ключово сравнение се проваля по отношение на фактори. Сравнявайте символи, а не нива на факторизация: обвивайте ключа в as.character() преди да обедините кадрите, създадени с по-стари настройки по подразбиране на R.

Когато едно и също сливане трябва да се изпълнява многократно, увийте го в потребителски дефинирана функция така че аргументите не могат да се отклоняват между изпълненията.

Въпроси и Отговори

R извършва сливане на всяко име на колона, което двата фрейма споделят. С една споделена колона това е удобно; с няколко, резултатът се стеснява безшумно, а без нито една, връща кръстосано съединение. Изричното именуване на ключа избягва и трите изненади.

Не в едно извикване на merge(). Свържете извикванията във верига или сгънете списък с Reduce(function(x, y) merge(x, y, by = “k”), list(df1, df2, df3)). Проверявайте броя на редовете след всяка стъпка, защото дублиращите се ключове се натрупват бързо.

И двата кадъра съдържаха неключова колона с едно и също име, така че R ги премахва многозначността. Предайте суфикси = c(“_producer”, “_film”), за да дадете на копията смислени имена, или премахнете излишната колона преди сливането.

Не. merge() сортира резултата по ключовата колона по подразбиране. Предайте sort = FALSE, за да запазите входящия ред, или използвайте dplyr съединение, което запазва реда на лявата рамка.

Да се ​​предостави вектор: merge(x, y, by = c(“фамилия”, “година”)). Когато имената се различават, съвпадащите вектори се предават на by.x и by.y. И двата вектора трябва да изброяват колоните в един и същи ред.

Използвайте by = „row.names“ или съкращението by = 0. R добавя имената на редовете обратно като колона, наречена Row.names, която обикновено искате да преименувате или премахнете, преди да продължите анализа.

Опишете двата кадъра и броя на редовете, а асистент с изкуствен интелект ще посочи дублирани ключове като вероятна причина и ще предложи проверка с duplicated(). Потвърдете диагнозата спрямо собствените си данни, преди да промените съединението.

Да. RStudio Desktop 2023.09.0 и по-нови версии предлагат опция за включване Копилот на GitHub интеграция, която създава сливане от коментар. Проверете избрания тип съединение, тъй като грешен флаг променя броя на редовете безшумно.

Обобщете тази публикация с: