Menu
flag Ar iconالعربيةdown icon

التجميع والتلخيص في R (aggregate وtapply وdplyr)

كل الطرق لحساب إحصاءات لكل مجموعة في R: العد بـ table()، وtapply() لإحصاء واحد لكل مجموعة، وواجهة الصيغة في aggregate()، وgroup_by() مع summarize() في dplyr.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

عدّ الصفوف لكل مجموعة: ‏table()

أبسط أسئلة التجميع هو "كم عدد كل نوع؟"، ويجيب عنه base R في استدعاء واحد. تعدّ table() عدد مرات ظهور كل قيمة:

يعطي عمود واحد أعدادًا لكل قيمة، ويعطي عمودان جدولًا متقاطعًا كاملًا (المناطق صفوفًا والخطط أعمدة). ولمعرفة "ما النسبة؟" غلّف ذلك بـ prop.table(table(...)). وتُعد table() أسرع طريق إلى إجابة تكرارية في R كله، فلا تلجأ إلى أداة أثقل حين يكون العد كل ما تحتاجه.

إحصاء واحد لكل مجموعة: ‏tapply()

تقسّم tapply(values, groups, function) المتجه الأول وفق الثاني وتطبّق الدالة على كل جزء:

النتيجة متجه مسمّى، تسميات المجموعات أسماءً والإحصاءات قيمًا، ما يجعله مثاليًا للاستعلامات السريعة (means["EU"]). ويُفك الاسم إلى "table apply"، أي تطبيق دالة على امتداد جدول تجميع. وتنتمي الدالة إلى العائلة نفسها التي تضم sapply() وlapply()، وتغطيها وثيقة عائلة apply.

وحدّ tapply() هو الشكل: فالمتجه المسمّى مرهق في الدمج أو الرسم أو متابعة المعالجة. وحين يكون الملخص محطة وسيطة لا الإجابة النهائية، فأنت تريد استرجاع data frame، وهو بالضبط ما تُرجعه الأداة التالية.

حصان العمل بالصيغة: ‏aggregate()

aggregate() هي أداة التجميع الكاملة في base R: تُرجع data frame، وتُقرأ واجهة صيغتها كما تنطق الجملة. فـ value ~ group تعني "القيمة مفصّلة حسب المجموعة":

إضافة عوامل تجميع ليست سوى + another_column داخل الصيغة، فالاستدعاء الثاني يجمع لكل تركيبة من المنطقة والربع. ويمكنك أيضًا تجميع عدة أعمدة قيم دفعة واحدة عبر cbind(a, b) ~ group. ولأن المخرجات data frame عادي، فهو ينساب مباشرة إلى دمج أو ترتيب أو رسم بياني، وهذه هي أداة base التي ينبغي اعتمادها افتراضيًا للملخصات المجمّعة.

وثمة سلوك هادئ يجدر معرفته: تحذف واجهة الصيغة الصفوف التي تحوي NA في أي عمود مستخدَم قبل التجميع. وهذا ما تريده عادةً، لكنه أحيانًا تفسير عدد يبدو منخفضًا.

أسلوب dplyr: ‏group_by() + summarize()

المعيار الحديث هو نمط الفعلين في dplyr، إذ تعلن group_by() عن التجميع، وتطوي summarize() كل مجموعة في صف واحد، محسوبةً ما تشاء من الإحصاءات التي تسمّيها (المثال ثابت، فالبيئة التجريبية تشغّل base R فقط):

library(dplyr)

sales |>
    group_by(region) |>
    summarize(
        n     = n(),
        total = sum(amount),
        avg   = mean(amount)
    )

هنا تتفوق dplyr فعلًا على base R: عدة إحصاءات لكل مجموعة في استدعاء واحد سهل القراءة، وهو ما يتطلب التواءات في aggregate()، إضافة إلى n() مجانًا، وانسياب النتيجة مباشرة إلى الأنبوب التالي. (والدالة summarise() هي الدالة نفسها بالإملاء البريطاني.)

وثمة أمر يحيّر المبتدئين: عند وجود عدة عوامل تجميع، تزيل summarize() الأخير منها فقط وتترك النتيجة مجمّعة، وتطبع رسالة بذلك. لذا صرّح بما تريد عبر الوسيط .groups: تُرجع summarize(avg = mean(amount), .groups = "drop") إطارًا عاديًا غير مجمّع، وهي العادة الافتراضية الصحيحة. فالإطار المجمّع الذي يتسلل إلى شيفرة لاحقة يجعل mutate() وأخواتها تعمل لكل مجموعة بصمت، وهو مصدر كلاسيكي للنتائج المربكة.

الاختيار بينها

  • العد: ‏table()، ولا شيء يتفوق على استدعاء واحد.
  • إحصاء واحد ونظرة سريعة: ‏tapply()، واقرأ الجواب من المتجه المسمّى.
  • مخرجات data frame في بيئة base فقط: ‏aggregate() مع صيغة.
  • عدة إحصاءات، أو جزء من سلسلة معالجة، أو أي عمل طموح: ‏group_by() |> summarize().

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

مثال تطبيقي: ‏mtcars حسب عدد الأسطوانات

كل ما سبق مجتمعًا على مجموعة بيانات مدمجة: لكل عدد أسطوانات، كم سيارة، وما متوسط اقتصاد الوقود والقدرة الحصانية:

إحدى عشرة سيارة رباعية الأسطوانات بمتوسط نحو 26.7 ميل لكل غالون، وسبع سداسية الأسطوانات بنحو 19.7، وأربع عشرة ثمانية الأسطوانات بنحو 15.1، بينما تسير القدرة الحصانية في الاتجاه المعاكس. استدعاءان وجدول ملخص كامل: هذا هو نوع الأسئلة التي وُجد التجميع للإجابة عنها.

الخلاصة

  • table() للأعداد، وprop.table() للنسب.
  • تُرجع tapply(values, groups, fn) متجهًا مسمّى، مناسبًا للنظرات السريعة والاستعلامات السهلة.
  • تُرجع aggregate(value ~ group, data, FUN) إطار بيانات، وتضيف + عوامل تجميع، وتضيف cbind() أعمدة قيم.
  • الصيغة group_by() |> summarize(n = n(), avg = mean(x), .groups = "drop") في dplyr هي المعيار الحديث للملخصات متعددة الإحصاءات.
  • اختر بحسب شكل المخرجات، فكلها متفقة على الأرقام.

في المستند التالي: دمج الجداول التي تشترك في مفتاح عبر merge() وعائلة الوصل في dplyr.

الأسئلة الشائعة

كيف أحسب المتوسط لكل مجموعة في R؟

يقدم base R أداتين: تُرجع tapply(df$value, df$group, mean) متجهًا مسمّى بمتوسطات المجموعات، وتُرجع aggregate(value ~ group, data = df, FUN = mean) النتيجة نفسها على هيئة data frame. وفي dplyr: df |> group_by(group) |> summarize(avg = mean(value)).

كيف أعدّ التكرارات حسب المجموعة في R؟

تعدّ table(df$group) الصفوف لكل قيمة مجموعة في استدعاء واحد، وتُنتج table(df$a, df$b) جدولًا متقاطعًا لعمودين. وفي dplyr تؤدي count(df, group) المهمة نفسها وتُرجع data frame، وهو أسهل في متابعة المعالجة.

ماذا تفعل aggregate() في R؟

تقسّم aggregate() إطار البيانات وفق عمود تجميع واحد أو أكثر، وتطبّق دالة على كل جزء، وتُرجع data frame بالنتائج. وتُقرأ واجهة الصيغة بطريقة طبيعية: aggregate(sales ~ region + quarter, data = df, FUN = mean) تعني المبيعات مجمّعة حسب المنطقة والربع ومحسوب متوسطها.

ما الفرق بين tapply وaggregate؟

الحساب نفسه بشكل مخرجات مختلف. تُرجع tapply() متجهًا مسمّى (أو مصفوفة عند وجود عاملَي تجميع)، وهو مفيد للاستعلامات السريعة. وتُرجع aggregate() إطار بيانات، وهو أفضل حين تغذي النتيجة تحليلًا لاحقًا أو دمجًا أو رسمًا بيانيًا. وعند التردد اختر aggregate().

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن