Menu

Объединение датафреймов в R (merge, left_join)

Объединение датафреймов по общему ключу: merge() для внутреннего, левого, правого и полного соединения, разные имена ключей через by.x/by.y, семейство соединений dplyr и rbind() для склейки строк.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Две таблицы, один ключ

Реальные данные редко живут в одной таблице. Клиенты сидят в одном датафрейме, их заказы — в другом, а вопрос «сколько потратил каждый клиент?» требует обоих. Связывает их ключ — столбец, присутствующий в каждой таблице и идентифицирующий одну и ту же сущность. Объединение таблиц по ключу называется соединением (слово из SQL) или слиянием (слово базового R); операция одна и та же.

Вот пара таблиц, которую использует остальная часть страницы. Обратите внимание: клиент 5 сделал заказ, но отсутствует в таблице клиентов, а клиенты 2 и 4 никогда не заказывали:

Несовпадения сделаны намеренно — именно то, как соединение поступает с несовпавшими строками, и различает типы соединений.

merge(): по умолчанию внутреннее соединение

merge(x, y, by = "key") сопоставляет строки с равными ключами и склеивает их столбцы. По умолчанию она оставляет только ключи, присутствующие в обеих таблицах, — внутреннее соединение:

Возвращаются три строки. Ana появляется дважды — у неё два заказа, а соединение порождает по одной выходной строке на каждую совпавшую пару. Ben и Dana исчезли (нет заказов), как и загадочный заказ клиента 5 (нет клиента). Внутреннее соединение молча отбрасывает несовпавшие строки из обеих таблиц — ровно то, что нужно, когда вас интересуют только полные пары, и баг с тихой потерей данных, когда нет.

Левое, правое и полное соединения: all.x, all.y, all

Чтобы сохранить несовпавшие строки, укажите, чьи строки священны. all.x = TRUE сохраняет каждую строку первой таблицы — левое соединение, самое используемое на практике:

Теперь Ben и Dana выживают с NA в amount — «этот клиент существует; заказ не совпал». Эти NA информативны, а не мусор: is.na(result$amount) — это ровно список клиентов, которые никогда не заказывали (работа с ними разобрана в статье о пропущенных значениях). Остальные варианты — та же идея, направленная в другую сторону: all.y = TRUE сохраняет каждую строку второй таблицы (правое соединение — заказ неизвестного клиента 5 выжил бы с NA в name), а all = TRUE сохраняет всё с обеих сторон (полное соединение).

Выбирайте, спросив себя: чьи строки мне нельзя потерять? Обогащаете основную таблицу справочными данными — левое соединение, основная таблица первой. Проверяете обе стороны — полное соединение.

Разные имена ключей: by.x и by.y

Таблицы редко сходятся в именовании — id в одной, customer_id в другой. Не переименовывайте; сообщите merge() оба имени:

В выводе за ключом остаётся имя из первой таблицы. Связанный момент: если две таблицы делят неключевые имена столбцов (скажем, у обеих есть date), merge добавит суффиксы date.x и date.y — переименуйте их поскорее, читаются они ужасно.

Соединения dplyr

dplyr даёт каждому типу соединения собственный глагол, поэтому намерение выражено в имени функции, а не в аргументах-флагах (сниппет статичный; песочница выполняет только базовый R):

library(dplyr)

left_join(customers, orders, by = "id")
inner_join(customers, orders, by = "id")
full_join(customers, orders, by = "id")
left_join(customers, orders, by = c("id" = "customer_id"))  # different names

Помимо читаемости, left_join() сохраняет порядок строк первой таблицы (merge() пересортировывает по ключу) и громко предупреждает о соединениях «многие ко многим» — о семействе глаголов см. введение в dplyr.

Недооценённый член семейства — anti_join(): она возвращает строки первой таблицы, у которых нет совпадения во второй, — без добавления столбцов, только остатки:

anti_join(customers, orders, by = "id")   # customers who never ordered

Этот вопрос — «какие строки не совпали?» — постоянно возникает при очистке данных (несовпавшие идентификаторы, осиротевшие записи, неудавшиеся поиски), и anti_join() отвечает на него одним вызовом там, где базовому R нужно customers[!(customers$id %in% orders$id), ].

Склейка строк: rbind()

Соединение объединяет столбцы двух таблиц. Когда у вас вместо этого две партии строк одного вида — заказы за январь и за февраль, — вы складываете их через rbind():

Требование строгое: у обоих датафреймов должны быть одинаковые имена столбцов (в любом порядке — rbind сопоставляет по имени). Отсутствующий или лишний столбец — это ошибка, а не заполнение NA. Когда столбцы партий разошлись, bind_rows() из dplyr снисходительнее: он выравнивает по имени и заполняет пробелы значениями NA.

Взрыв из-за дублирующихся ключей

Классическая авария соединения: ключи, которые вы считали уникальными, таковыми не являются — причём в обеих таблицах. Каждое совпадение спаривается с каждым совпадением, умножая строки:

Две строки, соединённые с двумя строками, дают четыре — каждый x в паре с каждым y. На реальных данных именно так таблица в 10 000 строк становится таблицей в 3 миллиона строк с удвоенной суммой выручки. merge() делает это молча. Защита — это привычка: перед соединением проверяйте ключ, который вы считаете уникальным (anyDuplicated(customers$id) должно быть 0), а после соединения сверяйте nrow() с ожидаемым.

Что вы уносите с собой

  • merge(x, y, by = "key") — внутреннее соединение: несовпавшие строки исчезают молча.
  • all.x = TRUE (левое), all.y = TRUE (правое), all = TRUE (полное) сохраняют несовпавшие строки, заполняя NA.
  • Разные имена ключей: by.x / by.y в базовом R, by = c("a" = "b") в dplyr.
  • dplyr именует каждое соединение; anti_join() — строки, которые не совпали, — самый недооценённый.
  • rbind() складывает таблицы одинаковой формы; столбцы должны совпадать по имени.
  • Дублирующиеся ключи молча умножают строки — проверяйте anyDuplicated() до и nrow() после.

Дальше: перестройка между широким и длинным форматами через pivot_longer() и pivot_wider().

Часто задаваемые вопросы

Как объединить два датафрейма в R?

Используйте merge(x, y, by = "key") с общим ключевым столбцом. По умолчанию выполняется внутреннее соединение — выживают только строки, чей ключ есть в обоих датафреймах. Добавьте all.x = TRUE для левого соединения, all.y = TRUE для правого или all = TRUE для полного.

Как выполнить левое соединение в R?

Базовый R: merge(x, y, by = "key", all.x = TRUE) сохраняет каждую строку x и заполняет столбцы y значениями NA там, где совпадения нет. dplyr: left_join(x, y, by = "key") — тот же результат, и он ещё сохраняет исходный порядок строк x, чего merge() не делает.

Как объединить датафреймы, если ключевые столбцы называются по-разному?

Сообщите merge() оба имени: merge(x, y, by.x = "id", by.y = "customer_id"). В dplyr эквивалент это left_join(x, y, by = c("id" = "customer_id")) или, с современным помощником, by = join_by(id == customer_id).

В чём разница между merge и rbind в R?

Они объединяют в разных измерениях. merge() сопоставляет строки двух таблиц по ключу и объединяет их столбцы — это соединение. rbind() подкладывает строки одной таблицы под строки другой — у обеих должны быть одинаковые имена столбцов. Месячным файлам с одинаковыми столбцами нужен rbind(); клиентам плюс заказам нужен merge().

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ