تُعد عملية تنظيف البيانات وهندستها حجر الزاوية في مسار التحليل الإحصائي وعلوم البيانات الحديثة، حيث يقضي الممارسون والباحثون ما يربو على ثمانين بالمائة من وقتهم في تهيئة البيانات الخام وتحويلها إلى بنى هيكلية قابلة للتحليل الرصين. وفي بيئة الحوسبة الإحصائية R Project for Statistical Computing، تتجلى أهمية معالجة المتغيرات وتوليفها بوصفها مهارة لا غنى عنها لبناء مصفوفات بيانات متماسكة وخالية من التكرار والتشوهات الهيكلية. إن دمج عمودين أو أكثر في عمود واحد يمثل أحد أكثر الإجراءات شيوعاً وأهمية؛ إذ تتعدد دوافعه ما بين إنشاء معرفات فريدة للمشاهدات، أو توحيد المتغيرات الزمنية والجغرافية، أو إعداد النصوص لعرضها بيئياً وفي التقارير الأكاديمية.
تتنوع المنهجيات والوظائف التي توفرها لغة R لإتمام هذا الغرض، متراوحة بين الوظائف المدمجة الكلاسيكية في الحزمة الأساسية (Base R) مثل الدالة paste والدالة paste0، والأدوات المتطورة والحديثة التي يقدمها نظام Tidyverse عبر حزمة tidyr ودالتها الشهيرة unite، فضلاً عن الحلول المتقدمة التي توفرها حزم السلاسل النصية المتخصصة مثل glue والمكتبات عالية الأداء الحسابي مثل data.table. هذا التنوع يمنح محلل البيانات مرونة استثنائية، لكنه يتطلب في المقابل فهماً عميقاً للفروق الدقيقة في الأداء، وإدارة الذاكرة، وطرق معالجة القيم المفقودة، وتوافق الأنواع البيانية المختلفة لضمان موثوقية النتائج الإحصائية.
يهدف هذا الدليل الشامل والمفصل إلى تقديم مرجع أكاديمي وتطبيقي متكامل حول كيفية دمج عمودين في عمود واحد في لغة R. سنستعرض من خلاله الأسس النظرية والتطبيقية، بدءاً من تشريح آليات التحويل الداخلي للبيانات، مروراً بالأمثلة البرمجية المباشرة والمتقدمة، ووصولاً إلى تحليل الكفاءة الحسابية عند التعامل مع مجموعات البيانات الضخمة (Big Data) ومعالجة المشكلات الشائعة مثل ترميز النصوص والأصفار البادئة، بما يضمن تزويد الباحث والمبرمج بالمعرفة الضرورية لكتابة أكواد برمجية تتسم بالمتانة، والكفاءة، وقابلية إعادة الإنتاج.
- 1. مقدمة شاملة حول دمج الأعمدة في لغة البرمجة R وأهميتها التحليلية
- 2. إعداد بيئة العمل وإنشاء مجموعات البيانات التجريبية
- 3. دمج الأعمدة باستخدام الدالة paste في حزمة Base R
- 4. استخدام الدالة paste0 للدمج المباشر دون فواصل
- 5. دمج الأعمدة باستخدام دالة unite من حزمة tidyr
- 6. معالجة وتوفيق أنواع البيانات المختلفة أثناء الدمج
- 7. تقنيات الدمج المتقدمة باستخدام دالتي sprintf و glue
- 8. دمج ثلاثة أعمدة أو أكثر والتعامل مع نطاقات متعددة
- 9. معالجة التحديات والمشكلات الشائعة أثناء عملية الدمج
- 10. كفاءة الأداء الحسابي والتعامل مع مجموعات البيانات الضخمة
- 11. تطبيقات وسيناريوهات واقعية في معالجة البيانات
- 12. المقارنة الشاملة وأفضل الممارسات الموصى بها برمجياً
- خاتمة
- References
1. مقدمة شاملة حول دمج الأعمدة في لغة البرمجة R وأهميتها التحليلية
1.1 مفهوم دمج المتغيرات والأعمدة في هياكل البيانات (Data Frames)
يمثل إطار البيانات (Data Frame) البنية الهيكلية الأكثر استخداماً وشيوعاً في لغة البرمجة R لتخزين البيانات الجدولية ثنائية الأبعاد، حيث يُنظم الجدول في صورة صفوف تعبر عن الحالات أو المشاهدات الفردية، وأعمدة تمثل المتغيرات المقاسة. تتسم هذه البنية بتنوعها؛ إذ يمكن لكل عمود أن يحمل نوعاً بيانياً مستقلاً (كالبيانات الرقمية Numeric، أو النصية Character، أو المنطقية Logical، أو الفئوية Factor). مفهوم دمج الأعمدة (Column Concatenation or Unification) يشير برمجياً إلى عملية أخذ قيم عمودين أو أكثر من نفس الصف وتوحيدها معاً في سلسلة نصية واحدة أو متغير مركب جديد يوضع في عمود مستقل أو يحل محل الأعمدة الأصلية وفقاً للغرض التحليلي المستهدف.
تكتسب هذه العملية أهميتها البالغة من قدرتها على تبسيط العلاقات المعقدة بين المتغيرات وتجريدها. فعلى سبيل المثال، يؤدي دمج البيانات النصية والعددية في عمود واحد إلى تقليل التشعبات في بنية البيانات ويسهل من عمليات الفلترة والاستعلام السريع. إن توحيد المتغيرات يتيح لمحلل البيانات تقليل أبعاد الجداول في الحالات التي تكون فيها المتغيرات المنفصلة غير ذات دلالة إحصائية فردية، مما يرفع من جودة تنظيم البيانات واتساقها الهيكلي، ويجعل الجداول أكثر مواءمة لمتطلبات النمذجة المتقدمة وقواعد البيانات العلائقية الحديثة.
علاوة على ذلك، يؤثر التوحيد الممنهج للأعمدة بشكل مباشر على قابلية القراءة والصيانة للأكواد؛ فعندما يتم توحيد العناصر المرتبطة منطقياً في كيان بياني واحد، يصبح تدفق العمل التحليلي (Analytical Workflow) أكثر وضوحاً، ويقلل من الأخطاء البشرية المحتملة عند إجراء العمليات الحسابية أو التحويلات اللاحقة. إن سلامة بنية البيانات واتساقها يمثلان الأساس الصلب الذي تُبنى عليه كافة الاستدلالات الإحصائية والقرارات المستندة إلى البيانات.
1.2 الدواعي التحليلية والإحصائية لتوحيد الأعمدة المنفصلة
تتعدد الدواعي الإحصائية والعملية التي تدفع الباحثين ومحللي البيانات إلى توحيد الأعمدة المنفصلة في لغة R. يأتي في مقدمة هذه الدواعي تجهيز المتغيرات للتحليلات الإحصائية الطولية (Longitudinal Analysis) والتكرارية؛ حيث تتطلب النماذج الخطية المختلطة (Linear Mixed Models) وتحليلات التباين للقياسات المتكررة (Repeated Measures ANOVA) في كثير من الأحيان تمييز كل وحدة تجريبية عبر الزمن من خلال متغير تركيبي يجمع بين معرّف الفرد ورقم الجلسة أو الموجة الزمنية، لتفادي التداخل الإحصائي وضمان دقة تقدير التباين داخل الأفراد وبينهم.
من الدواعي المحورية الأخرى إنشاء متغيرات مفتاحية فريدة (Primary and Foreign Keys) لإجراء عمليات الربط والدمج بين الجداول المختلفة (Data Merging and Joins). في كثير من المسوح وقواعد البيانات الواقعية، لا يتوفر معرّف فريد بسيط، بل يتوزع التمييز على عدة متغيرات، مثل رقم المحافظة ورقم الأسرة ورقم الفرد داخل الأسرة. إن توحيد هذه الأعمدة في متغير مفتاحي واحد يضمن دقة الربط بنسبة مئة بالمئة ويمنع حدوث تكرارات خاطئة أو فقدان للبيانات أثناء تنفيذ عمليات الربط الخارجي أو الداخلي عبر حزم مثل dplyr.
إضافة إلى ذلك، يلعب دمج الأعمدة دوراً جوهرياً في تحسين تمثيل البيانات الزمنية والفئوية؛ فدمج أعمدة اليوم والشهر والسنة في حقل واحد هو الخطوة الأولى لتحويل المتغيرات النصية إلى كائنات زمنية حقيقية (Date Objects) يمكن تطبيق خوارزميات السلاسل الزمنية عليها. كما يساعد الدمج في بناء مسميات فئوية مركبة (Composite Labels) تسهل من تفسير معاملات الانحدار وتجعل التقارير الإحصائية والجداول المستخرجة أكثر بلاغة ووضوحاً للقارئ الأكاديمي وصانع القرار.
1.3 نظرة عامة على التقنيات المتاحة في R للدمج
توفر بيئة البرمجة R ترسانة متنوعة من الأدوات البرمجية لإنجاز عملية دمج الأعمدة، وتختلف هذه الأدوات فيما بينها من حيث الفلسفة التصميمية، والسرعة، وسهولة القراءة، وتبعيات الحزم. تنقسم هذه التقنيات بصورة أساسية إلى ثلاث مدارس برمجية رئيسية: مدرسة النظام الأساسي (Base R)، ومدرسة منظومة البيانات المرتبة (Tidyverse)، ومدرسة المعالجة عالية الأداء المتمثلة في مكتبة (data.table) ومكتبات التنسيق المتقدم مثل glue و stringr.
في الحزمة الأساسية Base R، تبرز الدالتان paste و paste0 كخيارين أصيلين لا يتطلبان تثبيت أي حزم إضافية، مما يجعلهما مثاليتين للاستخدام في الحزم المستقلة والبرمجيات الخفيفة. تتميز هذه الدوال بمرونتها العالية في قبول عدد غير محدود من المتجهات مع إمكانية التحكم في الفواصل النصية عبر المعامل sep، إلا أنها تتطلب في بعض الأحيان معالجة يدوية إضافية للتعامل مع القيم المفقودة (NA) التي تُعامل كنصوص صريحة بشكل افتراضي.
في المقابل، تقدم منظومة Tidyverse الدالة unite عبر حزمة tidyr، والتي صُممت خصيصاً لتتناغم مع تدفق العمل القائم على عامل الربط التسلسلي (Pipe Operator). تتميز unite بقدرتها على التعامل الذكي مع أسماء الأعمدة، وحذف الأعمدة الأصلية تلقائياً لتوفير المساحة وتنظيف الجدول، وإسقاط القيم المفقودة بسلاسة عبر معاملات مدمجة، مما يجعلها الخيار المفضل في مسارات التحليل الحديثة التي تركز على مقروئية الكود وصيانته السهلة.
2. إعداد بيئة العمل وإنشاء مجموعات البيانات التجريبية
2.1 تثبيت واستدعاء الحزم البرمجية الأساسية
لضمان بيئة عمل برمجية متكاملة وقابلة لإعادة الإنتاج، يجب التأكد من استخدام إصدار حديث ومستقر من بيئة R، ثم تثبيت واستدعاء الحزم التحليلية التي سنعتمد عليها في الشروحات والتطبيقات العملية. تُعد حزمة tidyverse حزمة شاملة تضم داخلها مكتبات tidyr و dplyr و ggplot2 وغيرها، ويمكن تثبيتها من مستودع CRAN الرسمي عبر استخدام الأمر البرمجي install.packages مع تمرير اسم الحزمة كمتسلسلة نصية بين علامتي اقتباس.
بعد اكتمال التثبيت بنجاح، يتم استدعاء الحزم داخل جلسة العمل الحالية باستخدام الدالة library. يُفضل في التطبيقات الإحصائية الدقيقة استدعاء الحزم الأساسية التي نحتاجها صراحة، مثل استدعاء library(tidyr) ومكتبة library(dplyr) ومكتبة library(data.table) لتجنب التضارب بين أسماء الدوال (Namespace Masking). يتيح هذا الإجراء المحافظة على خفة بيئة العمل وسرعة استجابتها.
كما يُنصح بضبط خيارات البيئة العامة في بداية النصوص البرمجية، مثل تعيين خيار منع تحويل السلاسل النصية تلقائياً إلى عوامل عبر الإعداد stringsAsFactors = FALSE في الإصدارات القديمة (وهو السلوك الافتراضي المحمود في R 4.0 وما بعدها)، بالإضافة إلى ضبط خيار الترميز لدعم النصوص متعددة اللغات ومنها اللغة العربية، مما يضمن ثبات المخرجات البرمجية وعدم تغير سلوك الدوال عند تشغيل الكود على أنظمة تشغيل مختلفة.
2.2 إنشاء إطار بيانات تجريبي يجمع متغيرات رقمية وزمنية
لتطبيق التقنيات المختلفة بشكل عملي وملموس، سنقوم بإنشاء إطار بيانات تجريبي (Mock Data Frame) يحاكي بيانات حقيقية مأخوذة من دراسة طولية أو سجلات مبيعات شهرية، بحيث يشتمل الجدول على متغيرات من أنواع متباينة: متغيرات رقمية صحيحة، ومتغيرات نصية، ومتغيرات تحتوي على قيم مفقودة للتدريب على التعامل مع الحالات الواقعية المعقدة.
يمكن إنشاء هذا الجدول باستخدام الدالة data.frame مع تحديد الأعمدة التالية: عمود معرف الفرد (patient_id) ويحتوي على أرقام صحيحة، وعمود رمز المركز الطبي (clinic_code) كقيم نصية، وعمود سنة التسجيل (reg_year) كقيم عددية، وعمود شهر التسجيل (reg_month) كقيم نصية أو عددية، وأخيراً عمود يعبر عن مستوى الاستجابة أو النتيجة السريرية (outcome_score). هذا التنوع في المتغيرات يمنحنا أرضية خصبة لتجربة مختلف أساليب الدمج واختبار دقتها الإحصائية.
بعد بناء الجدول برمجياً وإسناده إلى متغير باسم df_sample، يتم استعراض الأسطر الأولى من إطار البيانات باستخدام دالة head أو دالة print القياسية. يوضح هذا العرض الأولي كيفية تراصف البيانات داخل الأعمدة والصفوف، مما يساعد في تصور الناتج النهائي المطلوب الوصول إليه بعد تطبيق عمليات التوحيد والدمج اللاحقة.
2.3 استكشاف بنية البيانات وفحص أنواع المتغيرات
قبل الشروع في كتابة أي دالة لدمج الأعمدة، من الضروري للغاية استكشاف البنية التركيبية للبيانات والتحقق الصارم من أنواع المتغيرات (Data Types). توفر لغة R الدالة str (Structure) التي تعد الأداة الأكثر فعالية في تقديم تشخيص شامل وفوري لهيكل البيانات، حيث توضح عدد الملاحظات، وعدد المتغيرات، ونوع كل عمود برمجياً (مثل int، num، chr، Factor) بالإضافة إلى عينة من القيم المخزنة في كل عمود.
كذلك يُنصح بتطبيق دالة summary للحصول على ملخص إحصائي سريع يتضمن القيم الصغرى والعظمى والمتوسطات الحسابية للمتغيرات الرقمية، إلى جانب حصر دقيق لعدد القيم المفقودة (NAs) في كل عمود. يُعد فحص القيم المفقودة ذا أهمية حاسمة في هذه المرحلة، لأن بعض دوال الدمج تتعامل مع الفراغات بطرق متباينة، مما قد ينتج عنه تشوهات غير مقصودة في السلاسل النصية المدمجة.
إن فهم نوع البيانات الأصلي يحدد المعالجات التحضيرية اللازمة قبل الدمج؛ فالأعمدة الرقمية التي تحتوي على فواصل عشرية قد تفقد تنسيقها إذا لم يتم ضبطها مسبقاً، والأعمدة الفئوية (Factors) تتطلب انتباهاً خاصاً لمستوياتها (Levels) الداخلية لكي لا تؤول قيمها إلى المؤشرات الرقمية التحتية بدلاً من التسميات النصية الفعلية. الفحص الدقيق هو الدرع الواقي من الأخطاء الصامتة في معالجة البيانات.
3. دمج الأعمدة باستخدام الدالة paste في حزمة Base R
3.1 البنية التركيبية الأساسية للدالة paste ومعلماتها
تُعد الدالة paste إحدى أقدم وأقوى الدوال النصية المدمجة في لغة R الأساسية، وتتميز ببنيتها المرنة التي تستقبل عدداً لا نهائياً من المتجهات النصية أو الرقمية المراد دمجها بالتوازي. الصيغة العامة للدالة تعتمد على تمرير المتغيرات كمدخلات متتالية تفصل بينها فواصل عادية، متبوعة بمعاملات التحكم في التنسيق وأهمها المعامل sep والمعامل collapse.
يتحكم المعامل sep (Separator) في الرمز أو السلسلة النصية التي تُدرج بين العناصر المتناظرة في المتجهات المدخلة عند دمجها أفقياً على مستوى كل صف. القيمة الافتراضية لهذا المعامل هي مسافة فارغة واحدة (” “)، ولكن يمكن تخصيصه لأي رمز مثل الشرطة العادية أو السفلية أو علامات الترقيم. أما المعامل collapse، فيُستخدم لتقليص المتجه الناتج بالكامل إلى سلسلة نصية مفردة واحدة، وهو ما لا نحتاجه عادة عند دمج أعمدة جدول لإنشاء عمود جديد، بل نكتفي بضبط sep للحفاظ على عدد صفوف الجدول دون تغيير.
من السمات التقنية البارزة للدالة paste قيامها بما يُعرف بالتحويل الضمني للأنواع (Implicit Type Coercion)؛ حيث تقوم الدالة تلقائياً وبشكل متجهي بتحويل أي مدخل غير نصي (سواء كان رقماً صحيحاً، أو عدداً عشرياً، أو قيمة منطقية) إلى سلسلة نصية مطابقة قبل إتمام عملية الدمج، مما يجنب المبرمج الحاجة إلى تحويل الأنواع يدوياً عبر دالة as.character في أغلب السيناريوهات البسيطة.
3.2 تطبيق عملي: دمج عمودي الشهر والسنة لإنشاء متغير تاريخ مركب
لتوضيح التطبيق العملي للدالة paste، لنفترض أن لدينا إطار البيانات التجريبي الذي يتضمن عمود السنة باسم reg_year وعمود الشهر باسم reg_month، ونرغب في توحيدهما لإنشاء عمود مركب يمثل تاريخ التسجيل بصيغة موحدة (مثل “2023_May” أو “2023-05”). يتم تحقيق ذلك من خلال تمرير العمودين مباشرة داخل دالة paste مع تحديد الفاصل المطلوب عبر المعامل sep.
يتم كتابة الكود البرمجي عن طريق إسناد النتيجة إلى عمود جديد في إطار البيانات باستخدام عامل الإسناد التقليدي، مثل: df_sample$full_date <- paste(df_sample$reg_year, df_sample$reg_month, sep = “-“). في هذا السطر البرمجي، تقوم R بتطبيق العملية بشكل متجهي (Vectorized)، حيث يتم دمج العنصر الأول من عمود السنة مع العنصر الأول من عمود الشهر بفاصل شرطة، ويتكرر ذلك تزامناً عبر جميع صفوف الجدول بنفس الكفاءة ودون الحاجة لأي حلقة تكرارية.
عقب تنفيذ هذا السطر، يتم فحص مخرجات الجدول المحدث باستخدام دالة head للتحقق من أن العمود الجديد full_date قد أُضيف بنجاح إلى أقصى يمين الجدول وأنه يحتوي على القيم المركبة بشكل صحيح ودقيق لكل صف، مع بقاء الأعمدة الأصلية reg_year و reg_month كما هي في الجدول دون أي تعديل أو حذف، وهو ما يتيح إجراء مقارنات فورية للتأكد من سلامة التحويل.
3.3 تخصيص الفواصل النصية والرموز داخل دالة paste
توفر دالة paste حرية مطلقة في اختيار الفواصل والرموز النصية التي تتوسط القيم المدمجة، مما يسمح بمواءمة المخرجات مع مختلف المعايير القياسية العالمية والمحلية. يمكن للمحلل استخدام الشرطة المائلة (“/”) لإنشاء مسارات أو تواريخ ذات نمط كلاسيكي، أو استخدام النقطة (“.”) لبناء مسميات متسلسلة هرمياً، أو النقطتين الرأسيتين (“:”) لتمثيل الفترات الزمنية بدقة متناهية.
بالإضافة إلى ذلك، تتيح دالة paste دمج نصوص ثابتة ومسميات توضيحية مباشرة مع قيم الأعمدة أثناء عملية التوحيد. على سبيل المثال، يمكن إنشاء عمود وصفي يوضح حالة المريض عبر كتابة: paste(“Center:”, df_sample$clinic_code, “| Score:”, df_sample$outcome_score, sep = ” “). في هذا النمط، تُعامل السلاسل النصية الثابتة كمتجهات ذات طول يساوي واحداً، ويتم تكرارها تلقائياً (Recycling Rule) عبر جميع صفوف الجدول، مما ينتج عنه جمل وصفية متناسقة ومقروءة بشكل فوري.
تظهر أهمية هذا التخصيص عند تجهيز المسميات للتقارير الآلية أو عند إعداد المعاملات النصية لنماذج الذكاء الاصطناعي ومعالجة اللغات الطبيعية (NLP)؛ حيث يُسهم إدراج الفواصل الصحيحة والرموز التفسيرية في إبراز الحدود الدلالية بين البيانات المختلفة وتفادي التداخل اللغوي بين المصطلحات والأرقام المدمجة.
3.4 إدارة القيم المفقودة (NA) عند استخدام دالة paste
من أهم الجوانب التقنية التي يجب على مبرمج R إدراكها عند التعامل مع الدالة paste هو سلوكها الافتراضي تجاه القيم المفقودة (Not Available – NA). على النقيض من بعض لغات البرمجة والوظائف الإحصائية التي قد تُسقط القيمة المفقودة أو تعيد ناتجاً فارغاً بالكامل، فإن دالة paste تقوم بتحويل قيمة NA المنطقية إلى سلسلة نصية صريحة مكونة من حرفين (“NA”)، مما يؤدي إلى ظهور نصوص مركبة مثل “2023-NA” أو “Center_A-NA”.
في معظم التطبيقات الإحصائية والتحليلية، يُعد ظهور النص “NA” داخل المتغيرات المدمجة تشوهاً غير مرغوب فيه في البيانات، إذ قد يُفسر لاحقاً كنص حقيقي وليس كقيمة مفقودة يجب استبعادها من الحسابات والنماذج. لتجنب هذا السلوك غير المرغوب، يجب على المحلل اتخاذ خطوات معالجة استباقية قبل إجراء الدمج، إما باستبدال القيم المفقودة بسلاسل فارغة (“”) أو باستخدام دوال شرطية دقيقة.
تتمثل إحدى الاستراتيجيات الفعالة في استخدام الدالة ifelse لمعالجة المتجه قبل دمجه، أو استخدام دالة مخصصة تفحص وجود NA وتقوم بتعويضها بسلسلة نصية فارغة، مثل: ifelse(is.na(x), “”, x). كما يمكن اللجوء إلى حزم متقدمة مثل stringr ودالتها str_c التي تتميز بامتلاك سلوك بديل حيث تُرجع NA بالكامل إذا كان أحد المدخلات مفقوداً، أو الانتقال إلى دالة unite التي توفر خياراً مدمجاً وحصيفاً لإدارة هذه المشكلة كما سيتم توضيحه لاحقاً.
4. استخدام الدالة paste0 للدمج المباشر دون فواصل
4.1 الفروق الجوهرية والوظيفية بين paste و paste0
تم إدخال الدالة paste0 في إصدارات لغة R لتقديم حل برمجي مباشر وسريع لعمليات الدمج النصي التي لا تتطلب أي فاصل بين المتغيرات. من الناحية الوظيفية والتركيبية، تُعد الدالة paste0 اختصاراً برمجياً دقيقاً ومكافئاً تماماً لاستدعاء الدالة paste مع تعيين المعامل sep إلى سلسلة نصية فارغة (sep = “”)، ولكن مع تجريد المعاملات غير الضرورية لتبسيط الكود وتوفير عدد ضربات المفاتيح للمبرمج.
من المنظور الحسابي وهندسة البرمجيات، تتميز paste0 بأداء تنفيذي أسرع نسبياً من paste التقليدية؛ نظراً لأنها مبرمجة في لغة C الأساسية (C Internal Code) بحيث تتجاوز مرحلة فحص وتحليل قيمة المعامل sep في كل استدعاء. على الرغم من أن هذا الفرق الزمني قد لا يكون ملحوظاً في مجموعات البيانات الصغيرة المكونة من بضع مئات من الصفوف، إلا أنه يصبح ملموساً وذا أهمية في العمليات التكرارية الضخمة ومجموعات البيانات التي تحتوي على ملايين السجلات.
يُنصح برمجياً باستخدام paste0 دائماً عندما يكون الغرض هو الالتصاق المباشر للمحارف دون فواصل، مثل دمج بادئات الرموز (Prefixes) مع الأرقام، أو عند بناء معرفات مركبة متصلة. يعزز هذا الاستخدام من مقروئية الكود؛ إذ ينقل على الفور للقارئ نية المبرمج بعدم رغبته في إقحام أي مسافات أو فواصل بين العناصر المدمجة دون الحاجة للبحث في معلمات الدالة.
4.2 مثال تطبيقي: توليد معرفات فريدة (IDs) عبر الدمج المباشر
يمثل توليد المعرفات الفريدة للمشاركين أو المعاملات أحد أبرز التطبيقات العملية للدالة paste0. لنفترض في دراستنا التجريبية أننا بحاجة إلى توليد معرف عالمي موحد (Composite Subject Identifier) يجمع بين رمز المركز الطبي (clinic_code) ورقم المريض التسلسلي (patient_id) دون أي مسافات فاصلة تفادياً للمشاكل التقنية عند تصدير البيانات إلى نظم إدارة قواعد البيانات (DBMS).
يتم تنفيذ هذا الإجراء بسطر برمجي بسيط ومباشر: df_sample$subject_uid <- paste0(df_sample$clinic_code, df_sample$patient_id). إذا كانت قيمة clinic_code في الصف الأول هي “CLN” وقيمة patient_id هي 101، فإن العمود الجديد subject_uid سيحتوي مباشرة على القيمة “CLN101”. تتميز هذه القيمة باتصالها وتوافقها التام مع قيود أسماء المتغيرات والمفاتيح الأساسية في الأنظمة البرمجية الخارجية.
عقب توليد هذا المعرف المركب، يُجرى فحص إحصائي للتحقق من تفرد القيم الجديدة (Uniqueness) باستخدام الدالة any(duplicated(df_sample$subject_uid)) أو عبر حساب طول القيم الفريدة ومقارنتها بالعدد الإجمالي لصفوف الجدول. يضمن هذا الإجراء أن الدمج قد أسفر بالفعل عن معرفات أحادية غير مكررة يمكن الاعتماد عليها بثقة تامة في كافة مراحل التتبع والربط الإحصائي المستقبلي.
4.3 التوافق مع العمليات المتجهية (Vectorized Operations)
تستند القوة الحقيقية للدالة paste0 في لغة R إلى دعمها الأصيل والمطلق للعمليات المتجهية (Vectorized Operations). في لغات البرمجة الإجرائية التقليدية مثل C أو Java أو Python الأساسية، يتطلب دمج قيم عمودين في مصفوفة كتابة حلقة تكرارية صريحة (for loop) للمرور على كل صف على حدة ودمج عناصره، وهو ما يستهلك زمناً برمجياً كبيراً ويؤدي إلى بطء التنفيذ في بيئات الحوسبة المفسرة.
في لغة R، تعمل الدالة paste0 على مستوى المتجه بالكامل ككتلة واحدة في الذاكرة؛ حيث تُرسل المتجهات المدخلة مباشرة إلى مكتبات C المضمنة والمجمعة (Compiled Code) ليتم تنفيذ الدمج بالتوازي على مستوى المعالج. يمنح هذا التصميم لغة R كفاءة حاسوبية هائلة، حيث يمكن معالجة مئات الآلاف من الصفوف في أجزاء ضئيلة من الثانية دون استنزاف لموارد النظام أو الحاجة لكتابة كود معقد.
ينعكس هذا التوافق المتجهي أيضاً على قدرة paste0 على تطبيق قواعد إعادة التدوير (Vector Recycling) بشكل ذكي. فإذا قمنا بدمج عمود بيانات يحتوي على آلاف الصفوف مع نص مفرد يمثل بادئة ثابتة مثل “SUBJ_”، تقوم R داخلياً بمطابقة طول المتجه الأقصر مع المتجه الأطول بسلاسة متناهية، مما ينتج كوداً نظيفاً، مقتضباً، وعالي الكفاءة البرمجية.
5. دمج الأعمدة باستخدام دالة unite من حزمة tidyr
5.1 فلسفة البيانات المرتبة (Tidy Data) ودور دالة unite
تنطلق حزمة tidyr من فلسفة حوسبية ثورية وضع أسسها العالم Hadley Wickham تُعرف بنظام “البيانات المرتبة” (Tidy Data)، والتي تنص على أن كل متغير يجب أن يشكل عموداً مستقلاً، وكل مشاهدة يجب أن تشكل صفاً، وكل نوع من الوحدات الرصدية يجب أن يشكل جدولاً. في هذا السياق المتناسق، تأتي الدالة unite لتؤدي دوراً محورياً في إعادة تشكيل البيانات وتوحيد الأعمدة المرتبطة منطقياً بأسلوب يتوافق تماماً مع قواعد لغة البيانات الحديثة.
تتميز دالة unite باندماجها التام مع عامل الربط التسلسلي (Pipe Operator) سواء كان النمط الكلاسيكي في مكتبة magrittr المتمثل في الرمز (%>%) أو عامل الربط الأصلي المدمج في إصدارات R الحديثة (|>). يتيح هذا التكامل للمحلل قراءة الكود وكتابته في صورة سلسلة منطقية متتابعة من العمليات المعالجة للبيانات، مما ينقل تركيز المبرمج من التراكيب اللغوية المعقدة إلى تدفق البيانات الفعلي وتحولاتها.
إضافة إلى ذلك، توفر unite واجهة مستخدم برمجية أكثر أماناً وتماسكاً مقارنة بدوال Base R؛ حيث تقبل أسماء الأعمدة كرموز صريحة دون الحاجة إلى وضعها بين علامات اقتباس (Non-Standard Evaluation – NSE)، مما يقلل من احتمالية الأخطاء الإملائية ويجعل الأكواد البرمجية أكثر أناقة وسهولة في التدقيق والمراجعة الجماعية في بيئات العمل البحثية.
5.2 الصيغة العامة لدالة unite والمعاملات الأساسية
تعتمد البنية التركيبية لدالة unite على تمرير إطار البيانات كمدخل أول، يليه اسم العمود الجديد المراد إنشاؤه عبر المعامل col، ثم تحديد أسماء الأعمدة المراد دمجها، وأخيراً تحديد الفاصل عبر المعامل sep. القيمة الافتراضية للفاصل في دالة unite هي الشَرطة السفلية (“_”)، وهي قيمة معيارية ممتازة تتوافق مع أفضل ممارسات تسمية المتغيرات في لغات البرمجة.
تتجلى مرونة unite في أسلوب تحديد الأعمدة المراد دمجها؛ إذ لا يقتصر الأمر على كتابة أسمائها منفردة، بل يمكن استخدام النطاقات ومحددات الاختيار المرنة (Tidyselect Helpers). على سبيل المثال، يمكن كتابة الأمر التالي لدمج عمودي السنة والشهر: df_sample <- df_sample %>% unite(col = “year_month”, reg_year, reg_month, sep = “/”). يقوم هذا الكود بإنشاء عمود جديد باسم year_month يحمل التاريخ بفاصل الشرطة المائلة.
كما تتميز الدالة بقدرتها على إدراج العمود المدمج في نفس الموضع المكاني الذي كانت تحتله الأعمدة الأصلية داخل هيكل الجدول، بدلاً من إضافته إجبارياً في نهاية الجدول كما يحدث في دوال Base R. هذا الحفاظ على الترتيب المكاني للأعمدة يسهم في بقاء البيانات منظمة ومنطقية دون الحاجة إلى إعادة ترتيب الأعمدة يدوياً عبر دالة relocate أو select.
5.3 التحكم في بقاء أو حذف الأعمدة الأصلية (remove parameter)
أحد الفروق الجوهرية والبالغة الأهمية بين دالة unite ودوال Base R التقليدية يكمن في معامل التحكم بالحذف (remove). سلوك دالة unite الافتراضي هو ضبط المعامل remove = TRUE، مما يعني أنها تقوم تلقائياً بحذف الأعمدة الأصلية التي تم دمجها من إطار البيانات وإبقاء العمود المدمج الجديد فقط. هذا السلوك صُمم خصيصاً للحفاظ على رشاقة الجداول وتجنب ازدواجية البيانات وتكرارها.
ومع ذلك، تفرض كثير من السيناريوهات التحليلية والإحصائية ضرورة الاحتفاظ بالمتغيرات الأصلية لإجراء تحليلات فرعية موازية (مثل استخدام السنة بمفردها كمتغير تجميعي في نماذج أخرى مع الاحتفاظ بالمتغير المركب). في مثل هذه الحالات، يوفر نظام tidyr حلاً سهلاً للغاية من خلال تغيير قيمة المعامل إلى remove = FALSE، مثل: df_sample %>% unite(“date_composite”, reg_year, reg_month, sep = “-“, remove = FALSE).
يمنح هذا الخيار المحلل مرونة فائقة في اتخاذ القرار المناسب بناءً على متطلبات المشروع؛ ففي مراحل تنظيف البيانات النهائية وتصدير التقارير، يُفضل الحذف لتقليل حجم الذاكرة وتبسيط العرض، بينما في مراحل التحليل الاستكشافي للبيانات (Exploratory Data Analysis – EDA)، يُعد الإبقاء على المتغيرات الأولية خياراً استراتيجياً لفحص العلاقات والارتباطات الأولية قبل اتخاذ قرارات النمذجة النهائية.
5.4 التعامل الذكي مع القيم المفقودة عبر na.rm
تتفوق دالة unite بشكل استثنائي على دالة paste في كيفية معالجتها للقيم المفقودة، حيث تحتوي الدالة على معامل مخصص وذكي يحمل اسم na.rm (NA Remove). عند ترك هذا المعامل على قيمته الافتراضية (na.rm = FALSE)، يتماثل سلوك الدالة مع paste في تحويل المفقودات إلى نصوص صريحة، ولكن عند تفعيله وضبطه إلى na.rm = TRUE، تظهر القوة الحقيقية لبيئة Tidyverse.
عند تفعيل na.rm = TRUE، تقوم دالة unite باستبعاد أي قيمة مفقودة من عملية الدمج في ذلك الصف تحديداً، وتدمج فقط القيم الصالحة والموجودة دون إدراج الفاصل المخصص بجوار الفراغ. على سبيل المثال، إذا كان لدينا صف يحتوي على الرمز “Center_A” في العمود الأول وقيمة NA في العمود الثاني، فإن ناتج الدمج بفاصل شرطة سيكون ببساطة “Center_A” بدلاً من “Center_A-NA” أو “Center_A-“.
إذا كانت جميع القيم في صف معين للعمودين المراد دمجهما مفقودة بالكامل (NA و NA)، فإن الدالة تُرجع سلسلة نصية فارغة (“”) بدلاً من إنتاج نصوص مشوهة. هذه المعالجة الذكية والمؤتمتة تختصر عشرات الأسطر البرمجية من المعالجات الشرطية اليدوية وتضمن بقاء مجموعات البيانات نقية وخالية من التشوهات النصية الناتجة عن مفقودات الإدخال.
6. معالجة وتوفيق أنواع البيانات المختلفة أثناء الدمج
6.1 دمج الأعمدة الرقمية (Numeric) مع المتغيرات النصية (Character)
في كثير من التطبيقات العملية، يواجه محلل البيانات حاجة ملحة لدمج أعمدة ذات طبيعة عددية مع أعمدة نصية، مثل دمج اسم المقياس مع قيمته العددية، أو دمج رقم المعاملة مع رمز الفئة. في بيئة R، تؤدي محاولة دمج أنواع غير متجانسة إلى تفعيل قواعد التحويل التلقائي للأنواع (Coercion Rules)، حيث تُحول القيم الرقمية إلى سلاسل نصية لأن السلاسل النصية تمثل النوع الأكثر شمولاً ومرونة لاستيعاب كافة الرموز.
تكمن التحديات الدقيقة في هذا التحويل التلقائي في كيفية تمثيل الأعداد العشرية وفقدان التنسيق المرغوب؛ فعلى سبيل المثال، قد يتحول العدد 12.500 إلى النص “12.5” بسبب إسقاط الأصفار اللاحقة تلقائياً في R، أو قد تظهر أعداد ذات منازل عشرية طويلة جداً ومقربة بشكل غير مناسب. لتفادي هذه المشكلة، يجب على المحلل التحكم الصارم في تنسيق المتغيرات الرقمية قبل دمجها باستخدام دالة format أو دالة round لتوحيد عدد المنازل العشرية.
كذلك يجب الانتباه عند دمج المتغيرات المنطقية (TRUE/FALSE) مع النصوص أو الأرقام؛ حيث تتحول في دالة paste إلى السلاسل “TRUE” و “FALSE”، بينما قد يفضل المحلل تحويلها إلى قيم ثنائية (1/0) قبل الدمج لضمان إيجاز المعرفات الناتجة. إن إدراك هذه التحولات الضمنية يضمن للمحلل عدم حدوث أي انحرافات غير مقصودة في دلالة البيانات الإحصائية أثناء عملية التوليف النصي.
6.2 دمج المتغيرات الفئوية (Factors) والحفاظ على المستويات
تُعد المتغيرات الفئوية (Factors) من أهم وأدق هياكل البيانات في لغة R، حيث تُستخدم لتمثيل المتغيرات النوعية والتصنيفية وتحتوي داخلياً على متجه من الأرقام الصحيحة المقترنة بجدول مستويات نصية (Levels). عند محاولة دمج عمود فئوي مع عمود آخر، تظهر بعض التعقيدات البرمجية التي قد تؤدي إلى نتائج غير متوقعة إذا لم يتم التعامل معها بوعي إحصائي وبرمجي سليم.
عند تمرير عمود من نوع Factor إلى دوال الدمج مثل paste أو unite، تقوم الدوال تلقائياً باستخراج المستويات النصية للقيم واستخدامها في السلسلة المدمجة الناتجة، ويكون الناتج النهائي عموداً من النوع النصي (Character). إذا كان الغرض التحليلي يستوجب استخدام هذا العمود المركب الجديد في نماذج إحصائية كمتغير فئوي (مثل تحليل التباين ثنائي الاتجاه Two-Way ANOVA)، فيجب على الباحث إعادة تحويل العمود المدمج صراحة إلى عامل باستخدام دالة factor.
عند إعادة التحويل إلى عامل، يجب إيلاء عناية فائقة لترتيب المستويات (Factor Levels)؛ فالترتيب الافتراضي في R يكون أبجدياً، وهو ما قد لا يتوافق مع الترتيب المنطقي المطلوب (كالترتيب التراتبي للجرعات أو الفئات العمرية). يمكن استخدام حزمة forcats المتخصصة لإعادة ضبط ترتيب المستويات المدمجة بدقة، مما يضمن أن تظهر المقارنات الإحصائية وفئات الأساس (Reference Levels) في نماذج الانحدار بالشكل العلمي الصحيح.
6.3 دمج التواريخ والأوقات مع الحفاظ على التنسيق المعياري
يمثل دمج أعمدة التاريخ المنفصلة مع أعمدة الوقت سيناريو كلاسيكياً متكرراً في معالجة بيانات السلاسل الزمنية، وسجلات المرضى، ومستشعرات الإنترنت للأشياء (IoT). على سبيل المثال، قد يحتوي إطار البيانات على عمود event_date بصيغة “2023-10-15” وعمود منفصل event_time بصيغة “14:30:00”. دمج هذين العمودين هو الخطوة الحاسمة لإنشاء طابع زمني كامل ودقيق من نوع POSIXct.
يتم تنفيذ الدمج الأولي باستخدام دالة paste أو unite بفاصل مسافة واحدة: df_sample$full_timesta\mp_str <- paste(df_sample$event_date, df_sample$event_time, sep = ” “). ينتج عن هذه الخطوة سلسلة نصية متكاملة، إلا أنها تظل كائناً نصياً غير قابل للعمليات الحسابية الزمنية مثل حساب الفروق الزمنية أو استخراج أسابيع السنة.
لتحويل هذه السلسلة المدمجة إلى متغير زمني فعلي، يتم استخدام دوال حزمة lubridate المتقدمة مثل دالة ymd_hms أو الدالة المضمنة as.POSIXct مع تحديد النطاق الزمني الصحيح (Timezone). يضمن هذا التحويل الالتزام بالمعيار الدولي ISO 8601 لتمثيل التواريخ والأوقات، مما يتيح تطبيق التحليلات الإحصائية الزمنية المتقدمة ورسم منحنيات البقاء والاستجابة عبر الزمن بدقة متناهية.
7. تقنيات الدمج المتقدمة باستخدام دالتي sprintf و glue
7.1 التنسيق الدقيق للسلاسل النصية باستخدام دالة sprintf في Base R
تستمد الدالة sprintf جذورها التاريخية من لغة البرمجة C الكلاسيكية، وتُعد الأداة المثلى في Base R لتحقيق أعلى درجات الدقة والتحكم في تنسيق السلاسل النصية والأرقام أثناء الدمج. تعمل هذه الدالة من خلال تمرير قالب نصي أولي يحتوي على محددات تنسيق خاصة (Format Specifiers)، تليها المتغيرات والأعمدة التي ستملأ تلك المحددات بالترتيب.
تشمل محددات التنسيق الأكثر شيوعاً الرمز %s لتمثيل النصوص، والرمز %d للأعداد الصحيحة، والرمز %f للأعداد الحقيقية ذات الفواصل العشرية. تتيح الدالة قدرات فريدة لا تتوفر مباشرة في paste، مثل التحكم الدقيق في عدد الخانات العشرية عبر كتابة %.2f لتقريب الأرقام إلى خانتين عشريتين تلقائياً أثناء الدمج، أو إضافة أصفار بادئة للأعداد الصحيحة عبر كتابة %04d لتحويل الرقم 5 إلى “0005”.
تتجلى قوة sprintf عند بناء صيغ ومؤشرات مركبة ومعقدة تجمع بين قيم متفرقة ونصوص وصفية ومقاييس إحصائية في جملة موحدة لكل صف. بفضل سرعتها الفائقة وانعدام أي تبعيات خارجية لها، تظل sprintf الخيار المفضل لمطوري حزم R الذين يبحثون عن أقصى درجات الاستقرار والتحكم في المخرجات النصية المدمجة.
7.2 استخدام حزمة glue لبناء نصوص مركبة بأسلوب تعبيري
تمثل حزمة glue، المطورة ضمن منظومة Tidyverse، ثورة حقيقية في أسلوب معالجة النصوص وتوليفها داخل لغة R. تعتمد الحزمة على مفهوم استيفاء النصوص البرمجية (String Interpolation) بأسلوب يماثل F-Strings في لغة Python، حيث تتيح كتابة أسماء الأعمدة والمتغيرات والتعبيرات البرمجية مباشرة داخل السلسلة النصية ومحاطة بأقواس مجعدة {}.
عند التعامل مع إطارات البيانات، تقدم الحزمة دالة متخصصة وفائقة الروعة تُدعى glue_data. تتيح هذه الدالة تمرير إطار البيانات مباشرة واستدعاء أعمدته داخل النص بمنتهى السلاسة؛ على سبيل المثال: df_sample <- df_sample %>% mutate(description = glue_data(., “المريض رقم {patient_id} مسجل في العيادة {clinic_code} بدرجة {outcome_score}”)). يتم تنفيذ هذا التعبير متجهياً على كافة الصفوف لإنتاج نصوص وصفية دقيقة وغنية دلالياً.
لا يقتصر سحر glue على استدعاء أسماء المتغيرات فقط، بل يمكن كتابة دوال وتعبيرات رياضية ومنطقية كاملة داخل الأقواس المجعدة، مثل تقريب الأرقام أو تحويل الحروف أو إجراء عمليات جمع سريعة. يجعل هذا التصميم التعبيري الأكواد البرمجية غاية في الأناقة والوضوح، ويسهل بشكل ملحوظ من صيانتها وتحديثها من قبل فرق العمل البرمجية المتعددة.
7.3 مقارنة معيارية بين glue و sprintf و paste
عند المفاضلة الهندسية والبرمجية بين الدوال الثلاث: paste و sprintf و glue، تبرز معايير المقروئية، والمرونة، والاعتمادية الخارجية كعناصر حاسمة في اتخاذ القرار البرمجي الأمثل لكل سيناريو عمل.
من حيث سهولة القراءة (Readability)، تكتسح دالة glue المنافسة؛ إذ يستطيع أي مبرمج فهم النتيجة المتوقعة للنص المدمج فور قراءة الكود دون الحاجة لتتبع مواقع المعاملات والفواصل المعقدة. تأتي sprintf في المرتبة الثانية من حيث الأناقة في التحكم الرياضي بالأرقام، بينما تصبح عبارات paste شديدة التعقيد وصعبة القراءة عندما يتجاوز عدد الأعمدة المدمجة ثلاثة أو أربعة أعمدة نظراً لتشابك الفواصل وعلامات الاقتباس.
من حيث التبعيات والأداء الأساسي (Dependencies & Overhead)، تتفوق paste و sprintf لكونهما دوال أصيلة في النظام الأساسي لـ R ولا تتطلبان تحميل أي حزم إضافية، مما يجعلهما مثاليتين للأنظمة المدمجة والخوادم محدودة الموارد وتطوير الحزم الأساسية. أما glue، فرغم حاجتها لتثبيت حزمة مستقلة، إلا أنها تعوض ذلك بكفاءة محركها المكتوب بلغة C، مما يجعلها الخيار الأحدث والأكثر تفضيلاً في مشاريع تحليل البيانات وتطوير تطبيقات Shiny التفاعلية.
8. دمج ثلاثة أعمدة أو أكثر والتعامل مع نطاقات متعددة
8.1 دمج عدة أعمدة في خطوة واحدة باستخدام Base R
لا يقتصر دمج الأعمدة على توحيد حقلين فقط، بل تتطلب السيناريوهات الواقعية في كثير من الأحيان دمج ثلاثة أو أربعة أو حتى عشرات الأعمدة دفعة واحدة، كما هو الحال عند بناء مسارات جغرافية كاملة (الدولة، المقاطعة، المدينة، الرمز البريدي) أو دمج نتائج استبيانات متعددة الأسئلة. في Base R، يمكن تمرير أي عدد من الأعمدة مباشرة داخل الدالة paste تفصل بينها فواصل، وتتولى الدالة دمجها جميعاً بترتيب تمريرها باستخدام نفس الفاصل الموحد.
ومع ذلك، إذا كان لدينا عدد كبير جداً من الأعمدة (مثلاً 20 عموداً متتالياً)، يصبح تمريرها يدوياً عموداً تلو الآخر أمراً مملاً ومعرضاً للأخطاء الإملائية. للتعامل مع هذا التحدي بكفاءة عالية، توفر لغة R دالة متقدمة وعبقرية تُدعى do.call. تتيح هذه الدالة تطبيق دالة معينة (مثل paste) على جميع عناصر قائمة أو مصفوفة من البيانات كمعاملات منفصلة.
يمكن كتابة هذا التكنيك الراقي عبر الكود التالي: df_sample$all_merged <- do.call(paste, c(df_sample[, c(“col1”, “col2”, “col3”, “col4”)], sep = “_”)). في هذا السطر، يتم تقطيع إطار البيانات لاستخراج الأعمدة المطلوبة كقائمة من المتجهات، ثم تُمرر إلى do.call لتدمجها جميعاً في خطوة واحدة فائقة السرعة وبكود مقتضب ومثالي للمصفوفات العريضة (Wide Matrices).
8.2 استخدام محددات الأعمدة التابعة لـ tidyverse (Select Helpers)
تقدم منظومة tidyverse عبر حزمتي tidyr و dplyr تجربة فائقة السلاسة والمرونة عند دمج مجموعات ونطاقات واسعة من الأعمدة، وذلك بفضل دعمها الكامل لمحددات الأعمدة الذكية المعروفة بـ (Tidyselect Helpers). تُغني هذه الأدوات المبرمج عن كتابة أسماء الأعمدة يدوياً وتعتمد بدلاً من ذلك على الخصائص الهيكلية والأنماط التسموية للأعمدة.
يمكن للمحلل استخدام عامل النقطتين (:) لدمج نطاق متتابع من الأعمدة بناءً على مواقعها داخل الجدول، مثل: df %>% unite(“survey_total”, q1:q10, sep = “-“). يقوم هذا الكود بدمج جميع الأعمدة الواقعة بين السؤال الأول q1 والسؤال العاشر q10 دون الحاجة لتسمية الأعمدة الثمانية التي تتوسطهما، مما يقلل الكود ويوفر وقتاً ثميناً في مرحلة الإعداد.
كذلك تتيح الدوال المساعدة المتقدمة دمج الأعمدة بناءً على مطابقة النصوص في أسمائها؛ فيمكن استخدام starts_with(“score_”) لدمج كافة الأعمدة التي تبدأ كلماتها ببادئة محددة، أو ends_with(“_date”) لدمج الأعمدة المنتهية بنمط معين، أو matches() لتطبيق التعبيرات النمطية (Regular Expressions). هذا الأسلوب الديناميكي يجعل الأكواد قادرة على التكيف تلقائياً حتى لو تغير عدد الأعمدة في البيانات المدخلة مستقبلاً طالما أنها تتبع نفس النمط التسموي.
8.3 الدمج الشرطي للأعمدة بناءً على قواعد منطقية
في بعض المسائل التحليلية المعقدة، قد لا يرغب الباحث في تطبيق عملية الدمج بشكل متماثل على كافة الصفوف، بل يقتضي المنطق التحليلي دمج أعمدة معينة فقط إذا تحقق شرط إحصائي أو منطقي محدد في ذلك الصف، واستخدام قيمة بديلة أو دمج أعمدة أخرى في حال عدم تحقق الشرط. هذا الإجراء يُعرف بالدمج الشرطي للأعمدة (Conditional Column Combination).
لتحقيق هذا الدمج الشرطي، يتم استخدام الدالة المتجهية ifelse في Base R أو الدالة الأكثر قوة وتنظيماً case_when التابعة لحزمة dplyr. لنفترض أننا نريد دمج عمود رمز المريض مع رمز العيادة فقط إذا كان المريض ينتمي للعيادات الخارجية، بينما نكتفي برقم المريض فقط إذا كان ينتمي للأقسام الداخلية لتجنب إرباك السجلات.
يتم التعبير عن ذلك عبر الكود التالي: df_sample <- df_sample %>% mutate(custom_id = case_when(clinic_type == “Outpatient” ~ paste(clinic_code, patient_id, sep = “-“), clinic_type == “Inpatient” ~ as.character(patient_id), TRUE ~ “Unknown”)). يتيح هذا النهج المنطقي مرونة استثنائية في معالجة الحالات الشاذة والاستثنائية في مجموعات البيانات الواقعية، ويضمن اتساق المخرجات النهائية مع القواعد المعيارية للمشروع التحليلي.
9. معالجة التحديات والمشكلات الشائعة أثناء عملية الدمج
9.1 التعامل مع مشكلة الأصفار البادئة والترميز العلمي للأرقام
تُعد مشكلة فقدان الأصفار البادئة (Leading Zeros) من أكثر المشكلات إحباطاً وشيوعاً عند التعامل مع البيانات الرقمية المعرفة للمفاهيم التصنيفية مثل الرموز البريدية، والأرقام القومية، وأكواد العينات الطبية. عند استيراد البيانات إلى R، يتم تحويل هذه الأكواد تلقائياً إلى أرقام صحيحة، مما يؤدي إلى حذف الصفر البادئ (فالرمز “0123” يتحول إلى الرقم 123)، وعند دمج هذا العمود مع عمود آخر تظهر المعرفات ناقصة ومشوهة.
لحل هذه المشكلة قبل إجراء الدمج، يجب استعادة الطول النصي الثابت للأرقام باستخدام دالة sprintf مع محدد الخانات المناسب (مثل %05d لضمان طول من 5 خانات مسبوقة بأصفار)، أو استخدام دالة str_pad التابعة لمكتبة stringr التي تسمح بملء السلسلة بأصفار من جهة اليسار حتى تصل للطول المستهدف: stringr::str_pad(df_sample$zip_code, width = 5, pad = “0”).
مشكلة أخرى بالغة الأهمية هي الترميز العلمي (Scientific Notation)؛ حيث تميل R إلى تمثيل الأرقام الكبيرة جداً (مثل أرقام المعاملات المكونة من 12 خانة) بصيغة الأسس مثل 1.23e+11. إذا دُمج هذا العمود رقمياً، سيتحول النص العلمي إلى السلسلة المدمجة بدلاً من الرقم الحقيقي الكامل. يتم التغلب على ذلك بضبط خيار options(scipen = 999) في بداية الجلسة لمنع الترميز العلمي نهائياً، أو استخدام دالة format(x, scientific = FALSE) لضمان طباعة وتوليف الرقم بأكمله كأرقام صحيحة صريحة.
9.2 إزالة المسافات البيضاء الزائدة والرموز غير المرغوب فيها
تحتوي السلاسل النصية المدخلة يدوياً أو المصدرة من استمارات الويب غالباً على مسافات بيضاء غير مرئية في بداياتها أو نهاياتها (Leading and Trailing Whitespaces)، أو فراغات مزدوجة في المنتصف. عند دمج عمودين يحتوي أحدهما على مسافات زائدة، يتم تضمين تلك المسافات داخل المتغير المدمج الجديد، مما يؤدي إلى فشل عمليات المطابقة والربط الإحصائي المستقبلي بين الجداول وظهور أخطاء مستترة في التحليل.
تتطلب أفضل الممارسات تنظيف الأعمدة النصية مسبقاً وتطهيرها من الشوائب قبل إرسالها لدوال الدمج. توفر R الأساسية دالة trimws لإزالة المسافات من الأطراف، بينما تقدم حزمة stringr الدالة الشاملة str_squish التي تزيل المسافات البادئة والناهية وتقوم بتقليص المسافات المزدوجة المتتالية داخل النص إلى مسافة واحدة فقط.
يمكن تطبيق هذا التنظيف المتجهي المسبق عبر dplyr بسهولة على كافة الأعمدة النصية دفعة واحدة باستخدام دالة mutate مع المحدد across: df_sample <- df_sample %>% mutate(across(where(is.character), stringr::str_squish)). يضمن هذا السطر تنظيفاً شاملاً للبيانات، مما يجعل المخرجات المدمجة نقية، ومتسقة الطول، وجاهزة تماماً للاستخدام في الفهرسة والمطابقة الإحصائية الدقيقة.
9.3 حل مشكلات ترميز المحارف (Encoding Issues)
تزداد عمليات دمج النصوص حساسية عند التعامل مع بيانات تحتوي على حروف عربية أو لغات غير لاتينية؛ حيث تظهر أحياناً مشكلة الأحرف المشوهة أو علامات الاستفهام المعروفة بمشكلة الرموز التالفة (Mojibake) عند دمج نصوص مشفرة بترميزات مختلفة (مثل دمج عمود مشفر بـ Windows-1256 مع عمود آخر مشفر بـ UTF-8).
لضمان سلامة النصوص المدمجة باللغة العربية، يجب التأكد من ضبط ترميز كافة المتغيرات النصية في إطار البيانات إلى المعيار العالمي الموحد UTF-8 قبل تنفيذ الدمج. توفر لغة R دالة Encoding لفحص ترميز المتجهات، ودالة enc2utf8 للتحويل الإجباري للسلاسل النصية إلى ترميز UTF-8 المستقر والشامل لكافة المحارف.
كما يُنصح في بيئات أنظمة التشغيل المختلفة (خاصة بيئة Windows) بضبط لغة الجلسة وإعدادات الموقع (Locale) في مستهل النص البرمجي عبر استدعاء الأمر Sys.setlocale(“LC_ALL”, “Arabic”) أو تعيينها إلى “en_US.UTF-8” في الأنظمة الشبيهة بيونكس. يضمن هذا الإجراء أن تتم عمليات الدمج، والفرز، والبحث النصي اللاحق باللغة العربية بأعلى درجات الدقة والاتساق ودون حدوث أي تلف في بنية النصوص والمسميات الإحصائية.
10. كفاءة الأداء الحسابي والتعامل مع مجموعات البيانات الضخمة
10.1 دمج الأعمدة باستخدام حزمة data.table عالية السرعة
عند الانتقال من مجموعات البيانات الأكاديمية الصغيرة إلى معالجة البيانات الضخمة (Big Data) التي تضم عشرات أو مئات الملايين من الصفوف، تصبح كفاءة الذاكرة وسرعة المعالجة المعيار الحاكم لاختيار أداة الدمج. في هذا النطاق، تتربع حزمة data.table على عرش الحلول فائقة السرعة في بيئة R بفضل اعتمادها على التعديل الموضعي في الذاكرة (Modification by Reference).
تستخدم data.table العامل المميز := لإضافة وتعديل الأعمدة موضعياً دون الحاجة إلى إنشاء نسخ مكررة من إطار البيانات في الذاكرة العشوائية (RAM). عند دمج عمودين في جدول ضخم، يتم كتابة الكود بالصيغة فائقة السرعة التالية: setDT(dt_large); dt_large[, full_id := paste0(clinic_code, “_”, patient_id)]. يتم تنفيذ هذه العملية على مستوى الذاكرة مباشرة بأدنى استهلاك ممكن لموارد الحاسوب.
إضافة إلى ذلك، توفر data.table وظيفة الدالة fifelse والتعامل المتوازي التلقائي عبر المعالجات متعددة الأنوية (OpenMP Multithreading)، مما يجعل زمن تنفيذ دمج الأعمدة على مصفوفات تحتوي على عشرين مليون صف يستغرق بضع ثوانٍ معدودة، مقارنة بدقائق طويلة قد تستغرقها الدوال التقليدية التي تستهلك الذاكرة في نسخ البيانات وإعادة تخصيص المساحات التخزينية.
10.2 قياس زمن التنفيذ واستهلاك الذاكرة بين الطرق المختلفة
لإجراء تقييم علمي وموضوعي للفروق الأدائية بين تقنيات الدمج المختلفة، يُستخدم أسلوب القياس المعياري الدقيق (Benchmarking) عبر حزمة متخصصة مثل microbenchmark. تتيح هذه الحزمة تشغيل الأوامر البرمجية المختلفة لعدد محدد من التكرارات (مثلاً 100 مرة) وحساب المتوسطات والانحرافات المعيارية لزمن التنفيذ بدقة متناهية تصل إلى الميكروثانية والنانوثانية.
تُظهر نتائج التجارب المعيارية على مجموعات البيانات المتوسطة والضخمة (من مئة ألف إلى عشرة ملايين صف) تفوقاً كاسحاً للدوال المكتوبة داخلياً بلغة C. تأتي الدالة paste0 في مقدمة دوال Base R من حيث سرعة التنفيذ، متفوقة بفارق طفيف على paste. أما في بيئات الجداول الضخمة، تتفوق data.table بفضل انعدام الحمل الزائد لنسخ الكائنات (Zero-Copy Overhead)، بينما تسجل دالة unite زمناً أطول نسبياً نظراً للمرونة الإضافية والتحققات الهيكلية التي تجريها داخلياً لضمان سلامة بنية Tidy Data.
من حيث استهلاك الذاكرة العشوائية (Memory Allocation)، تُظهر أدوات قياس الذاكرة مثل حزمة bench أن استخدام Base R التقليدي أو tidyverse يتطلب تخصيص مساحة ذاكرة تعادل على الأقل ضعف حجم الأعمدة المدمجة لاستيعاب الكائنات المؤقتة قبل إسنادها، في حين تحافظ data.table على استهلاك ذاكرة منخفض وثابت للغاية، مما يجعلها صمام الأمان لمنع انهيار جلسات العمل (Memory Crash) عند تحليل مجموعات البيانات الحيوية والضخمة.
10.3 أفضل الممارسات لتحسين سرعة المعالجة في المشاريع الضخمة
لضمان أعلى كفاءة حوسبية وأقصر زمن استجابة في مشاريع تحليل البيانات المتقدمة، يجب على مهندس البيانات الإحصائي اتباع مجموعة من الممارسات البرمجية الرشيدة عند إجراء عمليات دمج وتوليف الأعمدة. أولى هذه القواعد هي تجنب استخدام الحلقات التكرارية الصريحة (loops) أو دوال عائلة apply لدمج عناصر الصفوف نهائياً، والاعتماد الحصري والمطلق على الدوال المتجهية المدمجة.
القاعدة الثانية تتمثل في تأجيل عمليات دمج الأعمدة إلى أقصى مرحلة ممكنة في مسار معالجة البيانات؛ فإذا كانت خطة العمل تتضمن فلترة للبيانات واستبعاد سبعين بالمائة من الصفوف غير المستوفية للشروط، فيجب إجراء الفلترة أولاً وتخفيض حجم الجدول، ثم تطبيق دمج الأعمدة على الصفوف المتبقية فقط، بدلاً من إهدار الموارد الحسابية في دمج ملايين الصفوف التي سيتم حذفها لاحقاً.
أما القاعدة الثالثة، فتتعلق باختيار الأداة المناسبة لحجم البيانات وطبيعة المشروع؛ ففي نصوص التحليل الاستكشافي وإعداد التقارير اليومية التي لا تتجاوز بياناتها بضعة آلاف من الصفوف، يُفضل استخدام unite أو glue لمنح الأولوية لمقروئية الكود وسهولة صيانته. بينما في مسارات الإنتاج الضخمة وتدريب نماذج التعلم الآلي على خوادم المعالجة المركزية، يجب التحول إلى data.table لتحقيق أقصى استغلال ممكن للعتاد والذاكرة المتاحة.
11. تطبيقات وسيناريوهات واقعية في معالجة البيانات
11.1 تجهيز معرّفات فريدة للمشاركين والجلسات في الدراسات والبحوث
في الأبحاث الطبية والسريرية متعددة المراكز (Multicenter Clinical Trials)، يمثل تكرار أرقام المرضى خطراً كبيراً يهدد سلامة البيانات؛ حيث يقوم كل مستشفى بترقيم مرضاه محلياً بالبادئة 1، 2، 3… إلخ. عند تجميع البيانات في قاعدة بيانات وطنية واحدة، يصبح دمج معرف المركز الطبي مع رقم المريض التسلسلي ضرورة حتمية وأساسية لتوليد معرف عالمي متفرد يمنع أي تداخل بين السجلات الطبية.
يتكرر هذا السيناريو أيضاً في الدراسات الطولية النفسية والتربوية التي تتضمن جلسات تقييم متعددة لنفس المشارك عبر الزمن؛ حيث يتم دمج معرّف الطالب (Student_ID) مع رقم موجة التقييم (Wave_Number) لإنشاء مفتاح رئيسي مركب (Composite Primary Key) مثل “STU8902_W3”. يُستخدم هذا المفتاح لاحقاً لربط استبيانات الأداء بملفات القياسات الفسيولوجية دون أي غموض في تحديد الجلسة المعنية.
بفضل هذا الدمج المنهجي، يتمكن الباحث من إجراء عمليات الربط المعقدة (Left/Inner Joins) بين جداول السمات الثابتة (كالجنس والعمر) وجداول القياسات المتغيرة زمنياً بكفاءة مطلقة، مما يوفر بنية تحتية رقمية رصينة لتطبيق نماذج النمو الكامنة (Latent Growth Modeling) وتحليلات البقاء على قيد الحياة.
11.2 بناء متغيرات تصنيفية متعددة المستويات للتحليل الإحصائي
يعد بناء المتغيرات التصنيفية المركبة من التطبيقات الشائعة جداً في التحليل الإحصائي المتقدم، خاصة عند الرغبة في فحص التفاعلات غير الخطية بين متغيرين فئويين في جداول التوزيع التكراري المتقاطع (Cross-Tabulations) أو عند بناء نماذج الانحدار اللوجستي للتنبؤ بالظواهر المعقدة.
على سبيل المثال، قد يرغب الباحث في دراسة تأثير التفاعل بين الجنس (Gender: Male/Female) والفئة العمرية (Age_Group: Young/Middle/Senior) ككيان تصنيفي موحد. يتم دمج العمودين لإنشاء متغير جديد يحمل مستويات ستة واضحة ومحددة مثل: “Male_Young”، “Male_Middle”، “Female_Senior”… إلخ. يسهل هذا المتغير المدمج من استخدام دالة group_by في حزمة dplyr لحساب الإحصاءات الوصفية والمتوسطات والانحرافات المعيارية لكل مجموعة فرعية على حدة وبأمر برمجي واحد.
كما يفيد هذا التوحيد في تحسين كفاءة تمثيل البيانات في النماذج الإحصائية التي تتطلب تفاعلاً كاملاً بين العوامل؛ إذ يتيح للباحث تعيين فئة مرجعية مركبة ومحددة بدقة (Reference Group) للمقارنة المباشرة في جدول معاملات الانحدار، مما يجنب المحلل صعوبات تفسير معاملات التفاعل المتشابكة في النماذج الإحصائية التقليدية.
11.3 تحضير البيانات للتمثيل المرئي وإنشاء الملصقات البيانية
لا تكتمل العملية التحليلية دون إيصال النتائج بصرياً عبر رسوم بيانية تفاعلية ورصينة تُنشر في المجلات العلمية والتقارير التنفيذية. في هذا الإطار، يلعب دمج الأعمدة دوراً جوهرياً في تجهيز الملصقات البيانية ومحاور الرسوم في حزمة الرسوم الشهيرة ggplot2.
في كثير من المخططات البيانية (مثل المخططات الشريطية Bar Charts أو خرائط التمثيل اللوني Heatmaps)، يفضل عرض مسميات المحاور بشكل مدمج وغني بالمعلومات، كدمج اسم المتغير مع نسبته المئوية أو حجم العينة الخاص به (مثال: “Treatment A (n=150, 45%)”) بدلاً من الاكتفاء بالاسم المجرد. يتم توليف هذا العمود المركب مسبقاً باستخدام دالة paste أو sprintf ثم تمريره مباشرة كمتغير للمحور الأفقي أو الرأسي داخل الدالة aes() في ggplot2.
كذلك يُستخدم الدمج في إعداد نصوص التلميحات التفاعلية (Tooltips) في مكتبات الرسوم التفاعلية مثل plotly؛ حيث يتم دمج عدة متغيرات وصفية وإحصائية في حقل نصي واحد منسق برموز HTML وفواصل الأسطر، مما يتيح للمستخدم عند تمرير الفأرة فوق أي نقطة بيانية استعراض تقرير وصفي شامل وموجز لتلك المشاهدة دون تشويه المظهر العام للرسم البياني.
12. المقارنة الشاملة وأفضل الممارسات الموصى بها برمجياً
12.1 جدول مقارنة شامل بين مختلف طرق الدمج في R
لتلخيص المشهد البرمجي وتسهيل اتخاذ القرار التحليلي المناسب للباحثين والمطورين، يوضح الجدول التالي مقارنة منهجية شاملة بين أبرز التقنيات المتاحة لدمج الأعمدة في لغة R وفقاً لمعايير الأداء، وسهولة القراءة، والتعامل مع القيم المفقودة، والاعتماديات البرمجية:
| الأداة / الدالة | الحزمة البرمجية | مستوى سهولة القراءة | السرعة واستهلاك الذاكرة | التعامل مع القيم المفقودة (NA) | أفضل سيناريو للاستخدام |
|---|---|---|---|---|---|
| paste | Base R | متوسط | سريعة جداً ومدمجة | تحول NA إلى نص صريح (“NA”) | الحزم المستقلة وسكربتات Base R الخفيفة |
| paste0 | Base R | متوسط إلى مرتفع | الأسرع في النظام الأساسي | تحول NA إلى نص صريح (“NA”) | الدمج المباشر بدون فواصل وتوليد البادئات |
| unite | tidyr (tidyverse) | مرتفع جداً وأنيق | جيدة في البيانات المتوسطة | تدعم الحذف الذكي عبر na.rm = TRUE | مسارات البيانات المرتبة والتحليل الاستكشافي |
| glue_data | glue | استثنائي وبلاغي | سريعة ومكتوبة بـ C | تتطلب معالجة يدوية للمفقودات | بناء الجمل الوصفية وملصقات التقارير |
| sprintf | Base R | متوسط (أسلوب C) | فائقة السرعة والتحكم | تحول NA إلى نصوص | التنسيق الرقمي الدقيق والأصفار البادئة |
| data.table (:=) | data.table | مرتفع للمتمرسين | الأقوى عالمياً في السرعة والذاكرة | حسب الدالة الممررة داخلياً | مجموعات البيانات الضخمة (ملايين الصفوف) |
12.2 قائمة مرجعية (Checklist) للتحقق قبل وبعد دمج الأعمدة
لضمان الجودة الشاملة وتفادي الأخطاء المستترة في تدفقات معالجة البيانات، يُوصى باتباع قائمة التحقق المنهجية التالية قبل وبعد تنفيذ أي عملية دمج للأعمدة:
- التحقق القبلي من أنواع المتغيرات: فحص بنية الأعمدة الأصلية باستخدام دالة str للتأكد من خلو المتغيرات الرقمية من الترميز العلمي وأن المتغيرات الفئوية مستقرة في مستوياتها.
- فحص معدل القيم المفقودة: حصر عدد قيم NA في الأعمدة المدخلة واختيار الدالة المناسبة (مثل تفعيل na.rm = TRUE في دالة unite) لتجنب ظهور كلمة “NA” كنص داخل البيانات.
- تنظيف المسافات المحيطية: تطبيق دوال تقليص المسافات البيضاء (مثل trimws أو str_squish) على الأعمدة النصية لضمان عدم تضمين فراغات عشوائية داخل السلسلة المدمجة.
- التحقق البعدي من عدد الصفوف: التأكد المطلق من أن إجمالي عدد صفوف إطار البيانات لم يتغير بعد عملية الدمج ولم يحدث أي تقليص غير مقصود.
- فحص تفرد المعرفات المركبة: في حال كان الغرض من الدمج توليد مفتاح أساسي، يجب استخدام دالة any(duplicated()) للتأكد التام من عدم وجود قيم مكررة تشوه الربط لاحقاً.
- فحص سلامة الترميز اللغوي: معاينة عينات من النصوص المدمجة للتأكد من أن الأحرف العربية وغير اللاتينية تظهر بشكل سليم دون علامات استفهام أو رموز تالفة.
12.3 توصيات لكتابة كود برمجي نظيف وقابل لإعادة الاستخدام
يتطلب التميز في برمجة R الالتزام الصارم بأدلة الأسلوب البرمجي المعياري (مثل Tidyverse Style Guide). عند كتابة أكواد دمج الأعمدة، يجب تسمية العمود المدمج الجديد باسم واضح، وصريح، ومعبر دلالياً عن محتواه الداخلي، مع استخدام نمط الأحرف الصغيرة المفصولة بشرطة سفلية (snake_case) مثل patient_full_id وتجنب الأسماء المبهمة والمختصرة بشكل مفرط مثل v1 أو new_col.
في المشاريع البرمجية الكبيرة، إذا تكررت عملية دمج أعمدة متماثلة في عدة أجزاء من مسار العمل، فإن أفضل الممارسات تملي بناء دالة برمجية مخصصة (Custom Function) تغلف هذا الإجراء بمدخلات واضحة وتوثيق داخلي رصين. هذا التجريد البرمجي يمنع تكرار الكود (DRY Principle – Don’t Repeat Yourself) ويضمن أنه في حال تغيرت متطلبات الفاصل أو التنسيق مستقبلاً، يتم التعديل في موضع واحد فقط داخل الدالة دون الحاجة لتتبع عشرات الأسطر في المشروع.
أخيراً، يجب توثيق الكود عبر تعليقات برمجية تشرح باختصار الغرض الإحصائي والتحليلي من عملية الدمج، لاسيما عند استخدام معاملات متقدمة أو دوال تنسيق دقيقة مثل sprintf. الكود النظيف والموثق لا يخدم فقط فريق العمل الحالي، بل يضمن أيضاً استدامة البحث العلمي وقابلية إعادة إنتاجه وتطويره لسنوات طويلة قادمة.
خاتمة
استعرضنا في هذا الدليل الشامل والمفصل كافة الأبعاد النظرية والبرمجية والتطبيقية لعملية دمج عمودين أو أكثر في عمود واحد داخل بيئة البرمجة الإحصائية R. لقد أظهرت الشروحات أن هذه العملية، على الرغم من بساطتها الظاهرية، تمثل ركيزة أساسية في هندسة البيانات وتتطلب فهماً عميقاً للفروق الدقيقة بين مختلف الأدوات المتاحة، بدءاً من دوال النظام الأساسي paste و paste0 فائقة الاستقرار، ومروراً بدالة unite الأنيقة في منظومة tidyr، ووصولاً إلى حلول السرعة القصوى في data.table والتنسيق التعبيري في glue.
إن الاختيار الحصيف للأداة والفاصل المناسب، مع الإدارة الصارمة للقيم المفقودة، والتنظيف الاستباقي للمسافات البيضاء، ومراعاة سلامة ترميز النصوص وضبط التنسيقات الرقمية والزمنية، يشكل الفارق الحقيقي بين تحليل إحصائي هش ومعرض للأخطاء الصامتة، وبين مسار تحليلي متين، وموثوق، وقابل لإعادة الإنتاج في كبرى البيئات الأكاديمية والإنتاجية. إن إتقان هذه المهارات البرمجية يمنح الباحث ومحلل البيانات الكفاءة والثقة التامة في ترويض البيانات الخام وتحويلها إلى رؤى إحصائية واضحة تدعم اتخاذ القرارات الرشيدة.
References
- Chambers, J. M. (2016). Extending R. CRC Press. https://doi.org/10.1201/9781315381305
- Dowle, M., & Srinivasan, A. (2023). data.table: Extension of `data.frame` (R package version 1.14.8). CRAN. https://CRAN.R-project.org/package=data.table
- Grolemund, G., & Wickham, H. (2017). R for data science: Import, tidy, transform, visualize, and model data. O’Reilly Media. https://r4ds.had.co.nz/
- Hester, J., & Bryan, J. (2022). glue: Interpreted string literals (R package version 1.6.2). CRAN. https://CRAN.R-project.org/package=glue
- Mersmann, O. (2021). microbenchmark: Accurate timing functions (R package version 1.4.10). CRAN. https://CRAN.R-project.org/package=microbenchmark
- R Core Team. (2023). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. https://www.R-project.org/
- Wickham, H. (2014). Tidy data. Journal of Statistical Software, 59(10), 1–23. https://doi.org/10.18637/jss.v059.i10
- Wickham, H. (2019). Advanced R (2nd ed.). Chapman and Hall/CRC. https://doi.org/10.1201/9781351201315
- Wickham, H., & Girlich, M. (2023). tidyr: Tidy messy data (R package version 1.3.0). CRAN. https://CRAN.R-project.org/package=tidyr
- Wickham, H., François, R., Henry, L., & Müller, K. (2023). dplyr: A grammar of data manipulation (R package version 1.1.2). CRAN. https://CRAN.R-project.org/package=dplyr