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() я обръща назад, keeping по една променлива на колона.
  • ✂️ Разделяне и обединяване: separate() разделя колона по разделител, а unite() свързва колоните обратно в една.
  • ⚠️ Забележка за версията: pivot_longer(), pivot_wider() и separate_wider_delim() заместват по-старата версия на tidyr resha.ping функции.

Dplyr в R: Сливане и обединяване на данни

Въведение в анализа на данни

Преди всяко присъединяване или преструктуриранеping Глаголът има смисъл, помага да се види къде се вписва манипулирането на данни. Анализ на данните може да се раздели на три части:

  • ExtracАЦИ: Първо, трябва да съберем данните от много източници и да ги комбинираме.
  • Transform: Тази стъпка включва манипулиране на данни. След като консолидираме всички източници на данни, можем да започнем да почистваме данните.
  • Визуализирайте: Последният ход е да визуализираме нашите данни, за да проверим нередностите.

Диаграмата по-долу показва как са свързани трите етапа.

Триетапен процес на анализ на данни, показващ extracция, трансформация и визуализация
Процес на анализ на данни

Едно от най-значимите предизвикателства, пред които са изправени специалистите по обработка на данни, е манипулирането на данни. Данните никога не са налични в желания формат. Специалистите по обработка на данни трябва да отделят поне половината от времето си за почистване и манипулиране на данните. Това е една от най-важните задачи в работата. Ако процесът на манипулиране на данни не е пълен, прецизен и строг, моделът няма да работи правилно.

R dplyr

R има пакет, наречен dplyr, който обработва трансформацията на данни. Той е изграден около малък набор от основни функции — filter(), select(), arrange(), mutate() и summarize() — плюс семейство от функции за свързване. След като данните са във форма, ggplot2 може да ги визуализира.

Ще научим как да използваме пакета dplyr за манипулиране на DataFrameАко R все още не е инсталиран, следвайте инструкциите. Стъпки за настройка на R и RStudio, след което изпълнете install.packages(“dplyr”).

Обединяване на данни с dplyr

dplyr предоставя приятен и удобен начин за комбиниране на набори от данни. Може да имаме много източници на входни данни и в даден момент трябва да ги комбинираме. Обединяването с dplyr добавя променливи отдясно на оригиналния набор от данни.

dplyr се присъединява

Следват четири важни типа съединения, използвани в dplyr за обединяване на два набора от данни. И четирите приемат едни и същи аргументи – двете таблици и ключа – и се различават само по това кои несъответстващи редове остават:

функция Цел Аргументи Множество ключове
left_join() Обединете два набора от данни. Запазете всички наблюдения от таблицата на произхода x, y, by = „ИД“ x, y, by = c(„ИД“, „ИД2“)
right_join() Обединете два набора от данни. Запазете всички наблюдения от целевата таблица x, y, by = „ИД“ x, y, by = c(„ИД“, „ИД2“)
inner_join() Обединяване на два набора от данни. Изключване на всички несъответстващи редове x, y, by = „ИД“ x, y, by = c(„ИД“, „ИД2“)
full_join() Обединяване на два набора от данни. Запазване на всички наблюдения x, y, by = „ИД“ x, y, by = c(„ИД“, „ИД2“)

Тези четири глагола се съпоставят с LEFT, RIGHT, INNER и FULL OUTER съединенията на 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 ID 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 inner_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() запазва всички наблюдения и замества липсващите стойности с 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 и 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

От версия 1.1.0 (януари 2023 г.) насам същият ключ може да бъде записан като join_by(ID, year) и dplyr вече предупреждава за неочаквани съвпадения тип „много към много“, тъй като dplyr 1.1.0 се присъединява към съобщение обяснява.

Функции за почистване на данни в R

Сливането решава само половината от проблема, защото комбинираната таблица все още трябва да бъде преоформена. Следват четири важни функции за подреждане (почистване) на данните:

функция Цел Аргументи
събирам() Преобразувайте данните от широки към дълги (данни, ключ, стойност, na.rm = FALSE)
разпространение() Преобразувайте данните от дълги към широки (данни, ключ, стойност)
отделен() Разделяне на една променлива на две (данни, колона, в, раздел = „“, премахване = TRUE)
обединявам() Обединете две променливи в една (данни, колона, конц., раздел = „“, премахване = 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 широка тримесечна таблица в дълъг формат с функцията за събиране на подредени елементи

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 = тримесечие, values_from = растеж).

отделен()

Функцията 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.

Пример

Можем да разделим тримесечието от годината в по-подредения набор от данни, като приложим функцията отделно().

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.

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

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). Без съпоставянеping, dplyr съвпада с всяко споделено име на колона, което може незабелязано да стесни резултата или да го увеличи.

Ключовата стойност се повтаря от двете страни, така че се генерира всяка комбинация. Първо проверете duplicated() за всеки ключ, агрегирайте страната „много“ или предайте relationship = „много към много“, за да дефинирате намерението. dplyr предупреждава за неочаквани съвпадения „много към много“.

filter() избира редове, select() избира колони, arrange() видове, mutate() добавя колони, а summarize() свива групите, създадени от group_by(). Каналът (pipe) предава един резултат на следващия глагол; %>% се доставя с 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() след всяка стъпка, защото дублиращите се ключове се комбинират в съединенията.

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