برنامج تعليمي حول 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الإنتاج: أولا، نحتاج إلى جمع البيانات من عدة مصادر ودمجها.
  • تحول: تتضمن هذه الخطوة معالجة البيانات. بمجرد دمج جميع مصادر البيانات، يمكننا البدء في تنظيف البيانات.
  • تصور: الخطوة الأخيرة هي تصور بياناتنا للتحقق من عدم انتظامها.

يوضح الرسم البياني أدناه كيفية ترابط المراحل الثلاث.

عملية تحليل البيانات ثلاثية المراحل توضح مثالاًtracالتحويل والتصور
عملية تحليل البيانات

يُعدّ التعامل مع البيانات أحد أبرز التحديات التي تواجه علماء البيانات، إذ لا تتوفر البيانات عادةً بالصيغة المطلوبة. لذا، يضطر علماء البيانات إلى تخصيص نصف وقتهم على الأقل لتنظيف البيانات ومعالجتها، وهو ما يُعتبر من أهم مهامهم. فإذا لم تكن عملية معالجة البيانات كاملة ودقيقة ومنضبطة، فلن يعمل النموذج بالشكل المطلوب.

R dplyr

تحتوي لغة البرمجة R على حزمة تُسمى dplyr تُعنى بتحويل البيانات. وهي مبنية على مجموعة صغيرة من الدوال الأساسية - filter() و select() و arrange() و mutate() و summarise() - بالإضافة إلى مجموعة من دوال الربط. وبمجرد أن تصبح البيانات جاهزة، يُمكن لـ ggplot2 عرضها بيانيًا.

سنتعلم كيفية استخدام حزمة dplyr لمعالجة إطار البياناتإذا لم يكن برنامج R مثبتًا بعد، فاتبع التعليمات التالية خطوات إعداد R و RStudioثم قم بتشغيل install.packages(“dplyr”).

دمج البيانات باستخدام dplyr

يوفر dplyr طريقة لطيفة ومريحة لدمج مجموعات البيانات. قد يكون لدينا العديد من مصادر البيانات المدخلة، وفي مرحلة ما، نحتاج إلى دمجها. يؤدي الانضمام إلى dplyr إلى إضافة متغيرات إلى يمين مجموعة البيانات الأصلية.

ينضم dplyr

فيما يلي أربعة أنواع مهمة من عمليات الربط المستخدمة في مكتبة 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”)

تُطابق هذه الأفعال الأربعة وصلات LEFT و RIGHT و INNER و FULL OUTER لـ SQL. تصل لغة R الأساسية إلى نفس النتائج من خلال الوسائط all و all.x و all.y دمج().

سندرس جميع أنواع الربط من خلال مثال بسيط.

أولاً، نقوم بإنشاء مجموعتي بيانات. يحتوي الجدول 1 على متغيرين، ID و y، بينما يجمع الجدول 2 المتغيرين ID و z. في كل حالة، نحتاج إلى زوج المفتاح عامل. في حالتنا، الهوية هي ملكنا مفتاح متغير. ستبحث الدالة عن القيم المتطابقة في كلا الجدولين وتربط القيم المُعادة إلى يمين الجدول 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 inside_join()

يوضح الرسم البياني أدناه المعرفات الأربعة التي تبقى بعد عملية الربط.

رسم تخطيطي لعملية الربط الداخلي (inner_join) في مكتبة dplyr، والتي تُرجع فقط المعرفات الأربعة الموجودة في كلا الجدولين.

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

أزواج مفاتيح متعددة

وأخيرًا وليس آخرًا، يمكننا استخدام عدة مفاتيح في مجموعة البيانات. لنفترض مجموعة البيانات التالية التي تحتوي على السنوات وقائمة بالمنتجات التي اشتراها العميل. تُظهر لقطة الشاشة أدناه الجدولين وعمودي المعرّف والسنة اللذين يُحددان معًا صفًا.

إطاران من البيانات يشتركان في مفتاح مركب مكون من عمودَي المعرّف والسنة

إذا قمنا بربط الجدولين باستخدام المعرّف فقط، فسيتم مطابقة كل سنة مع كل سنة أخرى، مما يؤدي إلى زيادة عدد الصفوف بشكل كبير. ولحل هذه المشكلة، يمكننا استخدام متغيرين مكونين من زوج مفتاح، وهما المعرّف والسنة، واللذان يظهران في كلا مجموعتي البيانات. يمكننا استخدام الكود التالي لدمج الجدول 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 = FALSE)
الانتشار() تحويل البيانات من طويلة إلى واسعة (البيانات، المفتاح، القيمة)
متفرق() قسّم متغيرًا واحدًا إلى متغيرين (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. لا تزال الدوال المستبدلة تعمل، لذا فإن جميع الأمثلة أدناه تعمل، ولكن يُفضل استخدام مجموعات الدوال الأحدث الموضحة في الكود الجديد. مشهد متحرك مرتبيبقى .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

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.

مثال

يمكننا فصل الربع عن العام في مجموعة البيانات الأكثر ترتيبًا عن طريق تطبيق الدالة المنفصلة ().

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() على كل مفتاح أولاً، ثم اجمع جانب العلاقة المتعددة، أو مرر العلاقة = "many-to-many" لتحديد الغرض. يحذر dplyr من حالات التطابق غير المتوقعة من نوع علاقة متعددة إلى متعددة.

تقوم الدالة filter() بتحديد الصفوف، وتقوم الدالة select() باختيار الأعمدة، وتقوم الدالة arrange() نوباتتضيف الدالة mutate() أعمدة، بينما تقوم الدالة summarise() بدمج المجموعات التي تم إنشاؤها بواسطة الدالة group_by(). يُمرر الأنبوب نتيجة واحدة إلى الفعل التالي؛ %>% يأتي مع dplyr و |> هو أمر أصلي في لغة R.

يمكن للمساعدين الذين يعملون بالذكاء الاصطناعي تحليل إطار البيانات، وتحديد المفاتيح المكررة أو المكتوبة بشكل خاطئ قبل عملية الربط، واقتراح إعادة التجزئة.ping استخدم الفعل المناسب للتصميم، واشرح أي تغيير مفاجئ في عدد الصفوف بلغة بسيطة. أعد تشغيل الكود دائمًا وتحقق من الأبعاد بنفسك.

نعم. مساعد الطيار جيثب يعمل هذا البرنامج في RStudio Desktop الإصدار 2023.09.0 والإصدارات الأحدث، ويُكمل عمليات الربط والتحويل من خلال تعليق. يُرجى ملاحظة أن الاقتراحات غير حتمية، لذا يُرجى مراجعة كل سطر مُولّد قبل تشغيله.

قم بربط عمليات الربط، أو قم بطي قائمة باستخدام Reduce(function(x, y) left_join(x, y, by = “ID”), list(df1, df2, df3)). تقوم الدالة purrr::reduce() بنفس المهمة. تحقق من nrow() بعد كل خطوة، لأن المفاتيح المكررة تتراكم عبر عمليات الربط.

تلخيص هذه التدوينة بـ: