Учебное пособие по библиотеке dplyr в R: объединение и соединение данных с примерами.

⚡ Умное резюме

Пакет dplyr объединяет и соединяет фреймы данных в R с помощью четырех методов: left_join(), right_join(), inner_join() и full_join(). Сопутствующий ему пакет tidyr затем преобразует результат объединения с помощью методов gather(), spread(), separate() и unite().

  • 🔗 Изменение соединений: Функция left_join() сохраняет все строки исходной таблицы, а функция right_join() — все строки целевой таблицы.
  • 🎯 Контроль матча: Функция inner_join() удаляет несовпадающие строки, а функция full_join() сохраняет обе стороны и заполняет пробелы значениями NA.
  • 🗝️ Составные клавиши: Передавайте значение = c(“ID”, “year”) всякий раз, когда отдельный столбец не позволяет однозначно идентифицировать строку.
  • 🔄 Решаping: Функция gather() превращает широкую таблицу в длинную, а функция spread() возвращает её в исходное положение.ping Одна переменная на столбец.
  • ✂️ Раскол и объединение: Функция separate() разделяет столбец по разделителю, а функция unite() объединяет столбцы обратно в один.
  • ⚠️ Примечание к версии: Функции pivot_longer(), pivot_wider() и separate_wider_delim() заменяют более старую функцию tidyr resha.ping функции.

Dplyr в R: слияние и объединение данных

Введение в анализ данных

Перед любым присоединением или репостомping Использование глагола имеет смысл, это помогает понять, где уместна манипуляция данными. Анализ данных Его можно разделить на три части:

  • Extracпроизводство: Во-первых, нам нужно собрать данные из многих источников и объединить их.
  • Transform: Этот шаг включает в себя манипулирование данными. Как только мы объединим все источники данных, мы сможем приступить к очистке данных.
  • Визуализируйте: Последний шаг — визуализировать наши данные, чтобы проверить их неравномерность.

На приведенной ниже диаграмме показано, как связаны между собой три этапа.

Трехэтапный процесс анализа данных, демонстрирующий, например,tracтрансформация, преобразование и визуализация
Процесс анализа данных

Одна из самых серьезных проблем, с которыми сталкиваются специалисты по анализу данных, — это обработка данных. Данные никогда не бывают доступны в желаемом формате. Специалистам по анализу данных необходимо тратить как минимум половину своего времени на очистку и обработку данных. Это одна из важнейших задач в их работе. Если процесс обработки данных не является полным, точным и тщательным, модель не будет работать корректно.

R dplyr

В R есть пакет dplyr, который занимается преобразованием данных. Он построен на основе небольшого набора основных функций — filter(), select(), arrange(), mutate() и summarise() — а также семейства функций объединения (join). После того, как данные будут сформированы, ggplot2 может их визуализировать.

Мы научимся использовать пакет dplyr для работы с файлами. Фрейм данныхЕсли R еще не установлен, следуйте инструкциям. Шаги по настройке R и RStudioЗатем выполните команду install.packages(“dplyr”).

Объединение данных с помощью dplyr

dplyr предоставляет приятный и удобный способ объединения наборов данных. У нас может быть много источников входных данных, и в какой-то момент нам потребуется их объединить. Соединение с dplyr добавляет переменные справа от исходного набора данных.

dplyr Joins

Ниже описаны четыре важных типа объединений, используемых в dplyr для слияния двух наборов данных. Все четыре принимают одни и те же аргументы — две таблицы и ключ — и отличаются только тем, какие несовпадающие строки остаются:

Функция Цель аргументы Несколько ключей
left_join() Объедините два набора данных. Сохраняйте все наблюдения из исходной таблицы. x, y, by = “ID” x, y, by = c(“ID”, “ID2”)
right_join() Объедините два набора данных. Сохраняйте все наблюдения из целевой таблицы. x, y, by = “ID” x, y, by = c(“ID”, “ID2”)
внутреннее соединение() Объедините два набора данных. Исключите все строки, не соответствующие заданным параметрам. x, y, by = “ID” x, y, by = c(“ID”, “ID2”)
полное_соединение() Объедините два набора данных. Сохраните все наблюдения. x, y, by = “ID” x, y, by = c(“ID”, “ID2”)

Эти четыре глагола соответствуют левому, правому, внутреннему и полному внешнему соединениям SQLБазовый R достигает тех же результатов с помощью аргументов all, all.x и all.y. объединить ().

Мы рассмотрим все типы объединений на простом примере.

Прежде всего, мы создадим два набора данных. Таблица 1 содержит две переменные: ID и y, а Таблица 2 — ID и z. В каждом случае нам необходимо иметь пара ключей переменная. В нашем случае ID — это наш ключ переменная. Функция будет искать одинаковые значения в обеих таблицах и привязывать возвращаемые значения к правой части таблицы 1. На рисунке ниже показаны две таблицы рядом.

Две таблицы-примера, имеющие общий столбец ID перед слиянием с помощью dplyr.

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

Наиболее распространенный способ объединения двух наборов данных — использование функции left_join(). На рисунке ниже показано, что пары ключ-соответствие соответствуют строкам A, B, C и D, а E и F остаются. С помощью left_join() мы сохраняем все строки из исходной таблицы и игнорируем строки, у которых нет пары ключ-соответствие в целевой таблице. В нашем примере значение E отсутствует в таблице 1, поэтому эта строка удаляется. Значение F берется из исходной таблицы, поэтому оно сохраняется после left_join() и возвращает NA в столбце z.

Пример dplyr left_join()

Приведённая ниже диаграмма воспроизводит то, что происходит во время выполнения функции left_join().

Диаграмма dplyr left_join keeping каждую строку исходной таблицы и удалитьping ИД Е

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

Выход:

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

Обратите внимание, что если обе таблицы содержат столбец с одинаковым именем, dplyr различает их с помощью суффиксов .x и .y, показанных выше.

dplyr right_join()

Функция right_join() работает точно так же, как left_join(). Единственная разница заключается в том, что строка удалена. Значение E, доступное в целевом фрейме данных, существует в новой таблице и принимает значение NA для столбца y.

Пример dplyr right_join()

На приведенной ниже диаграмме показано зеркальное изображение.

Диаграмма dplyr right_join keeping каждую строку целевой таблицы и удалитьping ИД F

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

Выход:

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

Когда несовпадающие наблюдения оказываются совершенно бесполезными, мы можем вернуться Важно строки, которые существуют в и наборы данных. Это правильный выбор, когда нам нужен полный набор данных, и мы не хотим заполнять пропущенные значения средним или медианой.

Здесь на помощь приходит функция inner_join(). Она исключает несовпадающие строки с обеих сторон.

Пример dplyr Internal_join()

На приведенной ниже диаграмме выделены четыре идентификатора, которые сохраняются после объединения.

Диаграмма функции dplyr inner_join, возвращающей только четыре идентификатора, присутствующие в обеих таблицах.

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

Выход:

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

Наконец, функция full_join() сохраняет все наблюдения и заменяет пропущенные значения на NA.

Пример dplyr full_join()

На приведенной ниже диаграмме показаны все идентификаторы из обеих таблиц, сохранившиеся после объединения.

Диаграмма dplyr full_join keeping все шесть идентификаторов и заполнение пропущенных значений значением NA.

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

Выход:

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

Несколько пар ключей

И наконец, в нашем наборе данных может быть несколько ключей. Рассмотрим следующий набор данных, где у нас есть годы и список товаров, купленных клиентом. На скриншоте ниже показаны две таблицы и столбцы ID и год, которые вместе идентифицируют строку.

Две таблицы данных, имеющие общий составной ключ, образованный столбцами ID и Year.

Если объединить обе таблицы только по ID, то каждый год будет сопоставлен с каждым годом, и количество строк резко возрастет. Чтобы исправить ситуацию, мы можем передать две переменные, представляющие собой пары ключ-год: ID и год, которые присутствуют в обоих наборах данных. Для объединения таблицы 1 и таблицы 2 можно использовать следующий код:

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

Выход:

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

Начиная с версии dplyr 1.1.0 (январь 2023 г.) один и тот же ключ можно записать как join_by(ID, year), и dplyr теперь предупреждает о неожиданных совпадениях "многие ко многим", поскольку dplyr 1.1.0 присоединяется к анонсу .

Функции очистки данных в R

Объединение решает лишь половину проблемы, поскольку объединенную таблицу все равно необходимо переформатировать. Ниже приведены четыре важные функции для упорядочивания (очистки) данных:

Функция Цель аргументы
собирать() Преобразуйте данные из широких в длинные (данные, ключ, значение, na.rm = ЛОЖЬ)
распространение() Преобразование данных из длинных в широкие (данные, ключ, значение)
отдельный() Разделите одну переменную на две (data, col, into, sep = “”, remove = TRUE)
объединить() Объединить две переменные в одну. (data, col, conc, sep = “”, remove = TRUE)

Примечание к версии: Функции gather() и spread() были заменены на pivot_longer() и pivot_wider() в tidyr 1.0.0, а separate() — на семейство separate_wider_delim() в tidyr 1.3.0. Замененные функции по-прежнему работают, поэтому все приведенные ниже примеры работают, но в новом коде следует отдавать предпочтение более новым семействам функций, показанным в tidyr поворотная виньеткаФункция unite() остается актуальной.

Мы используем пакет tidyr, входящий в коллекцию tidyverse, для обработки, очистки и визуализации данных. Если R был установлен с Anaconda, этот пакет уже доступен по адресу [ссылка на пакет]. https://anaconda.org/r/r-tidyr.

Если он еще не установлен, введите следующую команду для установки tidyr:

install.packages("tidyr")

собирать()

Цель функции gather() — преобразовать данные из широкого формата в длинный.

Синтаксис

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

Пример

Ниже мы можем наглядно представить концепцию решаping От широкой к длинной. Мы хотим создать один столбец с именем «рост», заполняемый строками переменных четверти. На рисунке ниже слева показана широкая таблица, а справа — измененная длинная таблица.

Решаping Преобразование широкой квартальной таблицы в длинный формат с помощью функции tidyr gather.

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

Выход:

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

Выход:

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

В функции gather() мы создаём две новые переменные, quarter и growth, поскольку наш исходный набор данных содержит одну групповую переменную country и пары ключ-значение. В tidyr 1.0.0 и более поздних версиях аналогичная операция преобразования записывается как pivot_longer(messy, cols = q1_2017:q4_2017, names_to = “quarter”, values_to = “growth”).

распространение()

Функция spread() делает противоположное тому, что делает функция gather().

Синтаксис

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

Пример

Мы можем преобразовать более упорядоченный набор данных обратно в неупорядоченный с помощью функции spread().

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

Выход:

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

Современный эквивалент — pivot_wider(tidier, names_from = quarter, values_from = growth).

отдельный()

Функция separate() разделяет столбец на две части в соответствии с разделителем. Эта функция полезна в ситуациях, когда переменная представляет собой дату. В нашем анализе может потребоваться сосредоточиться на месяце и годе, и мы хотим разделить столбец на две новые переменные.

Синтаксис

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.

Пример

Мы можем отделить квартал от года в более аккуратном наборе данных, применив функциюdependent().

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

Выход:

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

объединить()

Функция unite() объединяет два столбца в один.

Синтаксис

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

Пример

В приведенном выше примере мы разделили квартал и год. А что, если мы хотим их объединить? Мы используем следующий код:

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

Выход:

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

Преобразованная структура данных теперь готова к этапам моделирования, описанным в остальной части статьи. Серия обучающих материалов по R.

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

Функция merge() выражает каждое соединение с помощью флагов all, all.x и all.y, в то время как dplyr определяет поведение в самом глаголе. dplyr также сохраняет исходный порядок строк и возвращает tibble. Базовый подход R описан в [ссылка на описание]. объединение фреймов данных руководства.

Они фильтруют объединения, поэтому никогда не добавляют столбцы. Функция semi_join(x, y) сохраняет строки x, которые имеют совпадение в y, а функция anti_join(x, y) сохраняет строки, которые не имеют совпадения. Обе полезны для проверки ключей перед выполнением изменяющего объединения.

Явно сопоставьте их с помощью by = c(“ID” = “customer_id”) или используйте более новую вспомогательную функцию join_by(ID == customer_id). Без сопоставления.pingdplyr выполняет поиск по каждому общему имени столбца, что может незаметно сузить результат или, наоборот, привести к его искажению.

Ключевое значение повторяется с обеих сторон, поэтому генерируются все возможные комбинации. Сначала проверьте duplicated() для каждого ключа, объедините стороны "многие" или передайте relationship = "многие ко многим", чтобы указать намерение. dplyr предупреждает о неожиданных совпадениях "многие ко многим".

Функция filter() выбирает строки, функция select() выбирает столбцы, функция arrange() заклинанияФункция `mutate()` добавляет столбцы, а `summarise()` сворачивает группы, созданные функцией `group_by()`. Конвейер передает один результат в следующий глагол; `%>%` поставляется вместе с `dplyr`, а `|>` — это встроенная функция R.

Искусственный интеллект может анализировать структуру данных, отмечать повторяющиеся или неправильно введенные ключи перед объединением, а также предлагать варианты переформатирования.ping Используйте глагол, подходящий к структуре, и объясните внезапное изменение количества строк простым языком. Всегда перезапускайте код и проверяйте размеры самостоятельно.

Да. Второй пилот GitHub Работает в RStudio Desktop 2023.09.0 и более поздних версиях и выполняет объединение и сводку данных на основе комментария. Posit отмечает, что предлагаемые варианты не являются детерминированными, поэтому перед запуском проверьте каждую сгенерированную строку.

Объедините элементы в цепочку или сверните список с помощью функции Reduce(function(x, y) left_join(x, y, by = “ID”), list(df1, df2, df3)). Функция purrr::reduce() делает то же самое. Проверяйте значение nrow() после каждого шага, поскольку повторяющиеся ключи накапливаются при объединении элементов.

Подведем итог этой публикации следующим образом: