التحليل الإحصائي, برمجة R

كيفية حساب المتوسط الشرطي في R (مع أمثلة)


يحتل مفهوم المتوسط الشرطي (Conditional Mean) مكانة مركزية واستثنائية في صميم التحليل الإحصائي الحديث، والنمذجة الرياضية، واستكشاف البيانات؛ إذ يمثل الأداة الجوهرية التي تتيح للباحثين والمحللين تجاوز النظرة العامة والسطحية للمتوسط الحسابي الإجمالي، والغوص في تفاصيل العلاقات البينية والتباينات الخفية داخل المجموعات الفرعية للبيانات. في المشهد التحليلي المعاصر، لا تكفي معرفة متوسط الدخل العام لمجتمع ما، أو متوسط أداء حملة إعلانية، بل تتطلب القرارات المستنيرة فهم كيف يتغير هذا المتوسط عند تقييده بشروط ديموغرافية، أو زمنية، أو سلوكية معينة. هنا يبرز دور التحليل الشرطي بوصفه العمود الفقري لنماذج الانحدار الخطي، والتعلم الآلي الإحصائي، وتصميم التجارب العلمية.

تُعد بيئة البرمجة الإحصائية R Project for Statistical Computing المنصة الرائدة والأكثر مرونة وموثوقية في تطبيق هذه المفاهيم الرياضية المعقدة وتحويلها إلى حلول برمجية وتحليلية قابلة للتنفيذ السريع. صُممت لغة R منذ نشأتها الأولى على يد علماء إحصاء لتكون لغة موجهة نحو التعامل مع البيانات والمتجهات، مما يجعل حساب المتوسطات المشروطة فيها عملية طبيعية تتناغم مع التفكير الرياضي السليم، سواء تم ذلك عبر الأدوات الأصلية للغة (Base R) أو عبر المنظومات البيئية الحديثة المتطورة مثل حزمة Tidyverse ومكتبة data.table عالية الأداء.

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

1. المفهوم الإحصائي للمتوسط الشرطي وأهميته التحليلية في لغة R

1.1 التعريف الرياضي والإحصائي للمتوسط الشرطي

يُعرَّف المتوسط الشرطي رياضياً بأنه القيمة المتوقعة المشروطة لمتغير عشوائي تابع (Y) بالنظر إلى تحقق قيمة معينة لمتغير أو مجموعة متغيرات مستقلة (X)، ويُرمز له بالصيغة الرياضية القياسية (E(Y|X = x)). في فضاء الاحتمالات المستمر، يُحسب هذا التوقع عن طريق مكاملة حاصل ضرب قيم المتغير التابع في دالة الكثافة الاحتمالية المشروطة عبر كامل نطاق (Y)، بينما يُحسب في الفضاء المنفصل عبر تجميع الجداء الاحتمالي لكل قيمة ممكنة. إن هذا التحديد الرياضي يعني الانتقال من فضاء العينة الكلي إلى فضاء عينة مقيد ومحدد بالشرط المفروض، مما يتيح دراسة السلوك الديناميكي للمتغير التابع تحت ظروف بيئية أو تجريبية متباينة.

يكمن الفرق الجوهري بين المتوسط الحسابي العام للعينة (Unconditional Mean) والمتوسط الشرطي للمجموعات الفرعية في أن المتوسط العام يفترض تجانس المجتمع وتماثل استجابات جميع وحدات الملاحظة، بينما يعترف المتوسط الشرطي بوجود عدم التجانس البنيوي (Structural Heterogeneity). عند حساب المتوسط العام، تُعامل جميع المشاهدات بأوزان متكافئة بغض النظر عن السياق، وهو ما قد يؤدي إلى طمس فروق بالغة الأهمية. على سبيل المثال، قد يُظهر المتوسط العام للأجور نمواً طفيفاً في قطاع معين، في حين يكشف المتوسط الشرطي حسب سنوات الخبرة أو المؤهل الأكاديمي عن تفاوتات جذرية وانقسامات هيكلية لا يمكن رصدها بدون هذا التقسيم الإحصائي المشروط.

في مجالات النمذجة الإحصائية وعلم البيانات التجريبي، يُمثل المتوسط الشرطي حجر الزاوية الذي تبنى عليه دالة الانحدار (Regression Function). في الواقع، الانحدار الخطي البسيط والمتعدد ليس إلا تقديراً بارامترياً للمتوسط الشرطي (E(Y|X)) كدالة خطية في المتغيرات التفسيرية. كما يمتد هذا المفهوم إلى التطبيقات السلوكية والنفسية والطبية؛ حيث يعتمد تقييم فعالية التدخلات العلاجية أو البرامج التدريبية على قياس الفرق بين المتوسط الشرطي للمجموعة التجريبية والمتوسط الشرطي للمجموعة الضابطة، مع التحكم في المتغيرات المربكة لضمان سلامة الاستدلال السببي.

1.2 بيئة البرمجة الإحصائية R ودورها في التحليل الشرطي

تمتاز بيئة البرمجة R بتصميم معماري فريد يستند إلى الحساب الموجه (Vectorized Computing)، مما يجعلها الأداة المثالية لتطبيق العمليات الشرطية على مجموعات البيانات المعقدة. بدلاً من الاعتماد على الحلقات التكرارية البطيئة (For-loops) لمعالجة البيانات صفاً تلو الآخر، تتعامل R مع الأعمدة والمتغيرات كمتجهات متكاملة، حيث يتم تطبيق الشروط المنطقية دفعة واحدة على مستوى الذاكرة. وتوفر هياكل البيانات الأساسية مثل أطر البيانات (Data Frames) وتنسيقات الجداول الحديثة (Tibbles) بيئة منظمة لتخزين المتغيرات العددية والفئوية جنباً إلى جنب مع الحفاظ على سلامة الأنواع والسمات الوصفية.

تعتمد آلية الفهرسة وتطبيق الأقنعة المنطقية (Logical Indexing) في R على توليد متجهات منطقية تحتوي على القيمتين الثنائيتين TRUE و FALSE كنتيجة لتقييم شرط معين. عند تمرير هذا المتجه المنطقي كدليل فهرسة لإطار البيانات أو للمتجه العددي المستهدف، تقوم R بتصفية واسترجاع العناصر التي تقابل القيمة TRUE فقط، متجاهلة تلقائياً العناصر الأخرى. تتم هذه العملية على مستوى منخفض في كود C المضمن داخل نواة R، مما يضمن كفاءة حسابية وسرعة استجابة فائقة عند استرجاع وتلخيص البيانات في الذاكرة العشوائية (RAM).

2. الصيغة الأساسية لحساب المتوسط الشرطي باستخدام Base R

2.1 بناء الجملة الأساسي واستخدام الأقواس المربعة للفهرسة

تعتمد الطريقة الأساسية والتقليدية لحساب المتوسط الشرطي في R الخالية من الحزم الخارجية (Base R) على دمج مشغلات الفهرسة بالأقواس المربعة [ , ] مع الدالة الإحصائية المدمجة mean(). تأخذ الصيغة النموذجية العامة الشكل التالي:

mean(df[df$variable == 'condition', 'target_variable'])

تقوم هذه الصيغة بتقييم التعبير المنطقي df$variable == 'condition' أولاً عبر جميع صفوف إطار البيانات df، مما ينتج عنه متجه منطقي بنفس طول عدد الصفوف. يتم وضع هذا المتجه في موضع الصفوف داخل مشغل الفهرسة (قبل الفاصلة)، بينما يتم تحديد اسم عمود الهدف 'target_variable' في موضع الأعمدة (بعد الفاصلة).

عند تنفيذ عملية الفهرسة هذه، تستخرج R القيم العددية لعمود الهدف المقابلة للصفوف المحققة للشرط فقط في صورة متجه عددي، ثم يتم تمرير هذا المتجه مباشرة كمدخل لدالة mean() لحساب وسطه الحسابي. تجدر الإشارة هنا إلى أهمية فهم سلوك التحويل التلقائي للأبعاد في R؛ فعند استخراج عمود فردي باستخدام الأقواس المربعة، تقوم R افتراضياً بإسقاط البعد الثنائي وتحويل النتيجة إلى متجه بسيط. في حال الرغبة في الحفاظ على هيكل إطار البيانات، يمكن استخدام الوسيطة drop = FALSE، إلا أن حساب المتوسط يتطلب متجهاً رقمياً، ولذلك فإن السلوك الافتراضي هو الأنسب لهذه الحالة.

# مثال توضيحي للصيغة الأساسية
# استخراج المتوسط للمتغير العددي بناءً على شرط نصي
calculated_mean <- mean(df[df$gender == "Female", "salary"], na.rm = TRUE)

2.2 إنشاء إطار بيانات تجريبي للتطبيق المباشر

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

# إنشاء إطار البيانات التجريبي
set.seed(42) # لضمان تطابق النتائج العشوائية
basketball_data <- data.frame(
 player_id = 1:12,
 player_name = c("Ahmed", "Salem", "Zaid", "Omar", "Khalid", "Tariq", 
 "Fahad", "Sultan", "Yousef", "Hamza", "Bilal", "Nasser"),
 team = c("Eagles", "Eagles", "Eagles", "Tigers", "Tigers", "Tigers", 
 "Hawks", "Hawks", "Hawks", "Wolves", "Wolves", "Wolves"),
 position = c("Guard", "Forward", "Guard", "Center", "Guard", "Forward", 
 "Forward", "Center", "Guard", "Forward", "Guard", "Center"),
 points = c(24, 18, 15, 29, 12, 22, 31, 14, 19, 8, 27, 16),
 assists = c(7, 3, 9, 2, 8, 4, 5, 1, 11, 2, 6, 3),
 minutes_played = c(34.5, 28.0, 31.2, 36.0, 22.5, 30.0, 38.5, 20.0, 33.0, 15.0, 35.5, 24.0),
 starter = c(TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE),
 stringsAsFactors = FALSE
)
# فحص الهيكل الداخلي لإطار البيانات
str(basketball_data)
# عرض ملخص إحصائي للمتغيرات
summary(basketball_data)

عند فحص بنية البيانات باستخدام الدالة str()، نلاحظ أن إطار البيانات يحتوي على 12 صفاً و8 أعمدة، تتنوع بين سلاسل نصية للمعرفات وأسماء الفرق، ومتغيرات عددية تمثل النقاط والتمريرات الحاسمة والدقائق الملعوبة، ومتغير منطقي يوضح ما إذا كان اللاعب أساسياً في التشكيلة. يوفر فحص البيانات عبر summary() نظرة أولية على نطاقات القيم، ونقاط البداية، والتشتت الإحصائي لكل متغير، مما يؤكد خلو البيانات من الأخطاء النوعية وجاهزيتها للتطبيق المباشر.

3. حساب المتوسط الشرطي للمتغيرات الفئوية (Categorical Variables)

3.1 تصفية البيانات بناءً على فئة نصية محددة

تُعد تصفية البيانات بناءً على مطابقة فئة نصية معينة أحد أكثر التطبيقات شيوعاً في التحليل الإحصائي. لحساب متوسط النقاط المسجلة للاعبي فريق معين، مثل فريق “Eagles”، نستخدم مشغل المساواة المنطقية == لعزل الصفوف التابعة لهذا الفريق تحديداً.

# حساب متوسط نقاط فريق Eagles
mean_eagles_points <- mean(basketball_data$points[basketball_data$team == "Eagles"])
print(paste("متوسط نقاط فريق Eagles هو:", round(mean_eagles_points, 2)))

يقوم الكود أعلاه بمقارنة كل عنصر في العمود basketball_data$team بالنص "Eagles". ينتج عن ذلك المتجه المنطقي: c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE). عند استخدام هذا المتجه لفهرسة عمود النقاط basketball_data$points، يتم استخراج القيم الثلاث الأولى فقط: c(24, 18, 15). تقوم الدالة mean() بجمع هذه القيم (المجموع = 57) وقسمتها على عددها (3)، لتكون النتيجة الدقيقة هي 19 نقطة.

يجب التنبيه إلى أن لغة R حساسة تماماً لحالة الأحرف (Case Sensitive) في مقارنة النصوص؛ فالشرط team == "eagles" بحرف صغير لن يطابق أي صف وسينتج عنه متجه منطقي يحتوي على FALSE في جميع مواضعه، مما يؤدي إلى محاولة حساب متوسط متجه فارغ وبالتالي ظهور القيمة NaN (Not a Number). لتفادي هذه المشكلة في التحليلات الحقيقية، يُفضل دائماً توحيد حالة الأحرف باستخدام دوال مثل tolower() أو toupper() قبل تطبيق الشرط.

# تطبيق احترازي لتوحيد حالة الأحرف
mean_eagles_safe <- mean(basketball_data$points[tolower(basketball_data$team) == "eagles"])

3.2 استخدام معاملات عدم المساواة والانتماء الفئوي

في كثير من الأحيان، يتطلب التحليل استبعاد فئة محددة وحساب المتوسط لكافة الفئات المتبقية، أو حساب المتوسط الشرطي لمجموعة محددة تتألف من عدة فئات مجتمعة. في السيناريو الأول، يُستخدم مشغل عدم المساواة !=، بينما يُستخدم مشغل الانتماء الفئوي %in% في السيناريو الثاني.

# حساب متوسط نقاط جميع اللاعبين باستثناء لاعبي فريق Wolves
mean_non_wolves <- mean(basketball_data$points[basketball_data$team != "Wolves"])
print(paste("متوسط نقاط باقي الفرق دون Wolves:", round(mean_non_wolves, 2)))
# حساب متوسط الدقائق الملعوبة للاعبي مركزي الحارس (Guard) والهجوم (Forward) معاً
mean_guard_forward_mins <- mean(basketball_data$minutes_played[basketball_data$position %in% c("Guard", "Forward")])
print(paste("متوسط دقائق لاعبي الحراسة والهجوم:", round(mean_guard_forward_mins, 2)))

يُعد المشغل %in% أكثر كفاءة وأقل عرضة للأخطاء البرمجية مقارنة بكتابة شروط مساواة متعددة مدمجة بأداة الربط | المنطقية. فهو يقوم باختبار عضوية كل عنصر في المتجه الأيسر ضمن المتجه المرجعي الأيمن بصورة مدمجة وسريعة، مما يجعل الشيفرة البرمجية أكثر وضوحاً وأسهل في القراءة والصيانة عند التعامل مع تصنيفات فئوية متعددة المستويات.

4. حساب المتوسط الشرطي استناداً إلى المعايير العددية ومؤشرات المقارنة

4.1 تطبيق شروط المقارنة الرياضية (الأكبر، الأصغر، والمجالات)

يتيح التحليل الشرطي القائم على المعايير الرقمية دراسة سلوك متغير تابع عندما يقع متغير كمي آخر ضمن نطاق رياضي معين. تُستخدم في هذا السياق معاملات المقارنة الرياضية القياسية: > (أكبر من)، < (أصغر من)، >= (أكبر من أو يساوي)، و <= (أصغر من أو يساوي).

# حساب متوسط النقاط للاعبين الذين شاركوا لأكثر من 30 دقيقة
mean_pts_high_mins <- mean(basketball_data$points[basketball_data$minutes_played > 30.0])
print(paste("متوسط نقاط اللاعبين الأكثر مشاركة (> 30 دقيقة):", round(mean_pts_high_mins, 2)))
# حساب متوسط التمريرات الحاسمة للاعبين الذين لعبوا بين 20 و 35 دقيقة (مجال مغلق)
in_range <- basketball_data$minutes_played >= 20.0 &a\mp; basketball_data$minutes_played <= 35.0
mean_assists_mid_mins <- mean(basketball_data$assists[in_range])
print(paste("متوسط تمريرات اللاعبين في المجال [20, 35]:", round(mean_assists_mid_mins, 2)))

تسمح هذه المقارنات العددية للباحث بعزل شرائح محددة من العينة بدقة، واختبار فرضيات مثل كفاءة اللاعبين في فترات المشاركة الطويلة مقارنة بفترات المشاركة المحدودة، مما يمنح صانع القرار رؤية تفصيلية مبنية على البيانات المقسمة رقمياً.

4.2 الشروط الذاتية المعتمدة على المتغير التابع نفسه

تنشأ في التطبيقات الإحصائية المتقدمة حاجة لحساب المتوسط الشرطي للقيم التي تحقق معياراً يرتبط بالمتغير نفسه، مثل حساب متوسط القيم التي تتجاوز المتوسط العام للعينة، أو استبعاد القيم المتطرفة (Outliers) التي تبعد عن المركز بمسافة معينة محسوبة بالانحراف المعياري.

# حساب متوسط النقاط للاعبين الذين سجلوا أعلى من المتوسط العام للنقاط
overall_mean_pts <- mean(basketball_data$points)
mean_above_average <- mean(basketball_data$points[basketball_data$points > overall_mean_pts])
print(paste("المتوسط العام للنقاط:", round(overall_mean_pts, 2)))
print(paste("متوسط النقاط للفئة المتفوقة على المتوسط العام:", round(mean_above_average, 2)))
# استبعاد القيم الشاذة: حساب متوسط الدقائق للاعبين الذين تقع مشاركاتهم ضمن ±1.5 انحراف معياري
sd_mins <- sd(basketball_data$minutes_played)
mean_mins <- mean(basketball_data$minutes_played)
clean_filter <- abs(basketball_data$minutes_played - mean_mins) <= (1.5 * sd_mins)
mean_mins_trimmed <- mean(basketball_data$minutes_played[clean_filter])
print(paste("متوسط الدقائق بعد تنقية الحدود المتطرفة:", round(mean_mins_trimmed, 2)))

تُعد هذه المقاربة الذاتية ركيزة أساسية في خوارزميات تنظيف البيانات (Data Cleaning) وهندسة الميزات (Feature Engineering)؛ حيث تسهم في تقييم مدى تركيز البيانات في الأطراف الإيجابية أو السلبية وتحديد العتبات الرقمية الديناميكية للتصنيف الإحصائي.

5. التعامل مع الشروط المركبة والمتعددة باستخدام المعاملات المنطقية

5.1 تطبيق معامل العطف المنطقي AND (&)

عندما تقتضي الدراسة الإحصائية تضييق نطاق التحليل لتحقيق معايير متعددة ومتزامنة، يتم استخدام معامل العطف المنطقي ذي العنصر الفردي & (Element-wise AND). هذا المعامل يختبر تحقق جميع الشروط في كل صف، ولا يعيد القيمة TRUE إلا إذا كانت كافة الشروط الفرعية محققة في ذلك الصف بعينه.

# حساب متوسط نقاط اللاعبين الأساسيين (starter == TRUE) الذين يلعبون في مركز الحارس (Guard)
complex_and_condition <- basketball_data$starter == TRUE &a\mp; basketball_data$position == "Guard"
mean_starter_guards_pts <- mean(basketball_data$points[complex_and_condition])
print(paste("متوسط نقاط الحراس الأساسيين:", round(mean_starter_guards_pts, 2)))

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

5.2 تطبيق معامل الفصل المنطقي OR (|) والنفي (!)

يتيح معامل الفصل المنطقي | (Element-wise OR) تجميع المشاهدات التي تحقق شرطاً واحداً على الأقل من بين مجموعة شروط مقترحة، بينما يتيح معامل النفي ! عكس النتيجة المنطقية لأي تعبير شرطي كامل.

# حساب متوسط التمريرات الحاسمة للاعبين الذين إما سجلوا أكثر من 20 نقطة أو لعبوا أكثر من 30 دقيقة
or_condition <- (basketball_data$points > 20) | (basketball_data$minutes_played > 30)
mean_assists_high_impact <- mean(basketball_data$assists[or_condition])
print(paste("متوسط تمريرات اللاعبين ذوي التأثير العالي:", round(mean_assists_high_impact, 2)))
# استخدام معامل النفي: حساب متوسط النقاط للاعبين غير الأساسيين
not_starter_condition <- !basketball_data$starter
mean_pts_bench <- mean(basketball_data$points[not_starter_condition])
print(paste("متوسط نقاط لاعبي الاحتياط:", round(mean_pts_bench, 2)))

يوضح الجدول التالي جدول الحقيقة (Truth Table) للمعاملات المنطقية داخل متجهات R لضمان سلامة بناء الفهرسة المعقدة:

الشرط أ (Condition A) الشرط ب (Condition B) العطف (A & B) الفصل (A | B) النفي (!A)
TRUE TRUE TRUE TRUE FALSE
TRUE FALSE FALSE TRUE FALSE
FALSE TRUE FALSE TRUE TRUE
FALSE FALSE FALSE FALSE TRUE

6. معالجة القيم المفقودة (NA) أثناء حساب المتوسط الشرطي

6.1 تأثير القيم المفقودة على مخرجات دالة mean()

في لغة R، ترمز القيمة NA (Not Available) إلى البيانات المفقودة. وتتبع الدالة mean() مبدأً إحصائياً صارماً؛ فإذا احتوى المتجه المدخل على قيمة مفقودة واحدة على الأقل، فإن النتيجة الحسابية الافتراضية ستكون حتماً NA، وذلك لحماية المحلل من إصدار تقديرات إحصائية مضللة دون الانتباه لوجود بيانات ناقصة.

# إنشاء متجه يحتوي على قيم مفقودة
points_with_na <- c(24, 18, NA, 29, 12, NA, 31)
# المحاولة الافتراضية لحساب المتوسط
mean(points_with_na) # النتيجة ستكون NA
# المعالجة الصحيحة بتمرير وسيطة na.rm = TRUE
mean_clean <- mean(points_with_na, na.rm = TRUE)
print(paste("المتوسط بعد استبعاد القيم المفقودة:", round(mean_clean, 2)))

تقوم الوسيطة na.rm = TRUE (NA Remove) بحذف القيم المفقودة مؤقتاً أثناء حساب المتوسط فقط دون تعديل المتجه الأصلي. ويجب التمييز هنا بدقة بين وجود الفقدان في متغير الاستجابة (Target Variable) أو في متغير الشرط (Condition Variable)؛ حيث إن وجود NA في متغير الشرط يؤدي إلى إنتاج قيم NA في المتجه المنطقي للفهرسة، مما يتطلب معالجة خاصة لتفادي استرجاع صفوف غير صالحة.

6.2 التصفية المتقدمة للقيم المفقودة باستخدام is.na() و complete.cases()

لضمان التحكم الكامل في تدفق البيانات وتجنب تسرب القيم المفقودة إلى شروط التصفية، توفر R دوالاً متخصصة مثل is.na() و complete.cases()، بالإضافة إلى دالة التصفية الأصلية الآمنة subset().

# إضافة صف يحتوي على بيانات مفقودة للتجربة
dirty_data <- basketball_data
dirty_data$points[3] <- NA
dirty_data$position[8] <- NA
# التصفية الآمنة باستخدام !is.na() المشروطة
safe_condition <- !is.na(dirty_data$points) &a\mp; !is.na(dirty_data$position) & (dirty_data$position == "Guard")
safe_mean <- mean(dirty_data$points[safe_condition])
print(paste("المتوسط الآمن لنقاط الحراس:", round(safe_mean, 2)))
# استخدام دالة subset() المدمجة للتعامل التلقائي والآمن
clean_subset <- subset(dirty_data, position == "Guard" & !is.na(points))
subset_mean <- mean(clean_subset$points)
print(paste("المتوسط باستخدام subset:", round(subset_mean, 2)))

تتعامل الدالة subset() تلقائياً مع القيم المنطقية غير المعرفة وتسقط الصفوف المقابلة لها دون التسبب في أخطاء فهرسة. ومع ذلك، يجب على المحلل الإحصائي تقييم نمط الفقدان (Missing Data Mechanism)؛ هل هو فقدان عشوائي تماماً (MCAR) أم فقدان غير عشوائي (MNAR)، حيث إن الحذف التلقائي للحالات المفقودة قد يقود إلى تحيز إحصائي (Attrition Bias) يؤثر على تعميم النتائج.

7. استخدام الدالة aggregate() لحساب المتوسطات الشرطية المجمعة

7.1 صيغة الصيغ الرياضية (Formula Syntax) في الدالة aggregate

عندما تقتضي متطلبات التحليل حساب المتوسط الشرطي لجميع مستويات متغير فئوي معين، أو عبر تقاطعات متغيرات فئوية متعددة، تصبح الفهرسة اليدوية لكل فئة على حدة عملية غير عملية وعرضة للأخطاء. تقدم دالة aggregate() المدمجة في Base R حلاً قوياً يعتمد على واجهة الصيغ الرياضية (Formula Notation) المشابهة لصيغ النمذجة الإحصائية.

# حساب متوسط النقاط لكل فريق على حدة
agg_team_pts <- aggregate(points ~ team, data = basketball_data, FUN = mean)
print("متوسط النقاط حسب الفريق:")
print(agg_team_pts)
# حساب متوسط النقاط بناءً على تفاعل الفريق ومركز اللعب (Two-way interaction)
agg_multi <- aggregate(points ~ team + position, data = basketball_data, FUN = mean)
print("متوسط النقاط حسب الفريق ومركز اللعب:")
print(agg_multi)
# حساب متوسطات أعمدة عددية متعددة في آن واحد
agg_multiple_vars <- aggregate(cbind(points, assists, minutes_played) ~ team, 
 data = basketball_data, 
 FUN = mean)
print("متوسط عدة مؤشرات حسب الفريق:")
print(agg_multiple_vars)

تسمح الوسيطة FUN بتمرير أي دالة إحصائية مرغوبة، وتتعامل دالة aggregate() بمرونة مع وسيطات الدوال الممررة مثل na.rm = TRUE عن طريق إضافتها كوسائط إضافية داخل الاستدعاء.

7.2 مقارنة كفاءة aggregate() مع طرق الفهرسة اليدوية

تتميز دالة aggregate() بإنتاج مخرجات منظمة في شكل إطار بيانات جديد (Data Frame)، يحتوي على أعمدة التصنيف متبوعة بأعمدة المتوسطات المحسوبة، مما يجعله جاهزاً مباشرة للتصدير، أو التنسيق في جداول تقارير، أو التمرير إلى دوال النمذجة والرسم البياني دون الحاجة لخطوات تحويل إضافية.

وجه المقارنة الفهرسة اليدوية المباشرة mean(df[...]) دالة التجميع aggregate()
نطاق المخرجات قيمة عددية فردية لشرط محدد إطار بيانات كامل لجميع الفئات المحتملة
قابلية التوسع للفئات المتعددة تتطلب كتابة أسطر متكررة لكل فئة سطر واحد يغطي كافة المجموعات والتفاعلات
جهد الكتابة البرمجية بسيط للشرط الواحد، معقد للمجموعات الكثيرة قصير، واضح، ومعياري في Base R
الأداء الحسابي مع البيانات الضخمة سريع للعملية الفردية متوسط الكفاءة مقارنة بالحزم المتقدمة

8. استخدام دالتي tapply() و ave() لحساب المتوسطات المشروطة

8.1 تطبيق دالة tapply() لإنشاء مصفوفات المتوسطات

تنتمي الدالة tapply() إلى عائلة دوال apply الشهيرة في R، وهي مصممة خصيصاً لتطبيق دالة معينة (مثل mean) على متجه عددي مجمع وفقاً لعامل فئوي واحد أو أكثر (Factor / Index). البناء النحوي للدالة هو:

tapply(X, INDEX, FUN, ..., default = NA, simplify = TRUE)
# حساب متوسط النقاط لكل مركز لعب باستخدام tapply
position_mean_pts <- tapply(basketball_data$points, basketball_data$position, mean)
print("مصفوفة متوسط النقاط حسب مركز اللعب:")
print(position_mean_pts)
# حساب جدول ثنائي الأبعاد يمثل تقاطع الفريق مع مركز اللعب
matrix_means <- tapply(basketball_data$points, 
 INDEX = list(basketball_data$team, basketball_data$position), 
 FUN = mean)
print("جدول تقاطع المتوسطات الشرطية:")
print(matrix_means)

تُعد tapply() خياراً ممتازاً عند الحاجة لاستخراج مصفوفات أو جداول تقاطعية سريعة (Cross-tabulations) للمتوسطات لعرضها كمدخلات لتحليلات التباين (ANOVA) أو لإنشاء خرائط حرارية بسيطة بدون الاعتماد على حزم خارجية.

8.2 إضافة المتوسط الشرطي كعمود جديد باستخدام دالة ave()

في العديد من مسارات هندسة الميزات والتحليل الإحصائي، لا نرغب في تقليص إطار البيانات إلى جدول ملخص، بل نحتاج إلى إضافة عمود جديد يكرر المتوسط الشرطي الخاص بكل فئة في كل صف من صفوف إطار البيانات الأصلي. تم تصميم دالة ave() لتنفيذ هذه المهمة الحسابية على أكمل وجه.

# حساب المتوسط الشرطي للنقاط حسب المركز وإضافته كعمود جديد
basketball_data$pos_mean_points <- ave(basketball_data$points, 
 basketball_data$position, 
 FUN = mean)
# حساب انحراف أداء كل لاعب عن متوسط مركزه (Group Mean Centering)
basketball_data$points_centered <- basketball_data$points - basketball_data$pos_mean_points
# عرض الأعمدة المستحدثة
print(basketball_data[, c("player_name", "position", "points", "pos_mean_points", "points_centered")])

تكتسب هذه التقنية، المعروفة إحصائياً بـ “تمركز المجموعة الفرعية” (Group Mean Centering)، أهمية قصوى في النماذج الخطية الهرمية (Hierarchical Linear Models) والنماذج متعددة المستويات (Multilevel Modeling)؛ حيث تسمح بفصل التأثيرات الواقعة على مستوى الفرد عن التأثيرات الواقعة على مستوى المجموعة بدقة بالغة.

9. حساب المتوسط الشرطي باستخدام حزمة dplyr التابعة لـ Tidyverse

9.1 استخدام خط الأنابيب (Pipe Operator) ودالتي group_by و summarise

أحدثت حزمة dplyr ثورة في معالجة البيانات داخل R من خلال تقديم صيغ برمجية تعتمد على أفعال البيانات (Data Verbs) واستخدام مشغل الأنابيب (Pipe Operator) سواء النمط التقليدي %>% أو النمط الأصلي المدمج في إصدارات R الحديثة |>. يتيح هذا النهج كتابة تدفقات عمل تحليلية مقروءة وسلسة تشبه الجمل اللغوية الطبيعية.

# تحميل الحزمة
library(dplyr)
# حساب المتوسط الشرطي للنقاط والتمريرات مع الانحراف المعياري حسب الفريق
team_summary <- basketball_data |>
 group_by(team) |>
 summarise(
 n_players = n(),
 mean_points = mean(points, na.rm = TRUE),
 sd_points = sd(points, na.rm = TRUE),
 mean_assists = mean(assists, na.rm = TRUE)
 )
print(team_summary)

تقوم الدالة group_by() بتقسيم إطار البيانات داخلياً إلى مجموعات منطقية تتبع المتغير المحدد، ثم تقوم الدالة summarise() بحساب المؤشرات الإحصائية المطلوبة لكل مجموعة على حدة، مع إرجاع جدول بيانات نظيف ومنسق يحتوي على النتائج النهائية ملخصة بشكل أنيق.

9.2 التصفية المباشرة داخل دالة summarise() باستخدام المعاملات الشرطية

تتيح حزمة dplyr دمج الشروط المنطقية مباشرة داخل حسابات الدوال الإحصائية ضمن summarise()، أو تطبيق دالة filter() المسبقة لعزل المشاهدات المطلوبة قبل الشروع في التجميع والتلخيص.

# الطريقة الأولى: التصفية المسبقة باستخدام filter ثم التجميع
filtered_mean_1 <- basketball_data |>
 filter(minutes_played >= 25) |>
 group_by(team) |>
 summarise(mean_pts_active = mean(points))
print("المتوسط بالتصفية المسبقة:")
print(filtered_mean_1)
# الطريقة الثانية: حساب متوسطات شرطية متباينة داخل نفس summarise
inline_conditional_summary <- basketball_data |>
 group_by(team) |>
 summarise(
 mean_all = mean(points),
 mean_starters_only = mean(points[starter == TRUE]),
 mean_high_mins = mean(points[minutes_played > 30])
 )
print("متوسطات شرطية متعددة بالتوازي:")
print(inline_conditional_summary)

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

9.3 استخدام case_when() و mutate() لتصنيف المتوسطات وحسابها

تُعد دالة case_when() الأداة المثالية لإنشاء تصنيفات شرطية معقدة متعددة الحالات، بالتعاون مع دالة mutate() التي تضيف أعمدة جديدة أو تعدل الأعمدة القائمة في إطار البيانات.

# إنشاء تصنيف شرطي لمستوى المشاركة وحساب المتوسطات لكل مستوى
categorized_data <- basketball_data |>
 mutate(
 participation_tier = case_when(
 minutes_played >= 32 ~ "High Usage",
 minutes_played >= 24 ~ "Medium Usage",
 TRUE ~ "Low Usage"
 )
 ) |>
 group_by(participation_tier) |>
 summarise(
 player_count = n(),
 mean_points = mean(points),
 mean_assists = mean(assists)
 ) |>
 arrange(desc(mean_points))
print(categorized_data)

يوفر هذا الأسلوب هيكلية واضحة ومقروءة للمشاريع التحليلية الكبرى؛ حيث يفصل بين مرحلة تعريف المنطق الشرطي (Business Logic / Categorization) ومرحلة التلخيص الحسابي الإحصائي، مما يقلل احتمالية الأخطاء ويسهل مراجعة الكود من قبل فرق العمل المشتركة.

10. حساب المتوسط الشرطي عالي الأداء باستخدام حزمة data.table

10.1 الصيغة التركيبية العامة [i, j, by] في data.table

عند التعامل مع مجموعات البيانات الضخمة (Big Data) التي تحتوي على ملايين أو عشرات الملايين من الصفوف، تصبح كفاءة الذاكرة وسرعة المعالجة متطلبين حاسمين لا غنى عنهما. توفر حزمة data.table حلاً فائق التطور عبر صياغتها الموحدة والفريدة:

DT[i, j, by]

حيث يمثل i التصفية واختيار الصفوف (المكافئ لـ WHERE في SQL)، ويمثل j الحسابات واختيار الأعمدة (المكافئ لـ SELECT)، بينما يمثل by التجميع الفئوي (المكافئ لـ GROUP BY).

# تحميل حزمة data.table وتحويل إطار البيانات
library(data.table)
setDT(basketball_data)
# حساب المتوسط الشرطي: النقاط للاعبين الذين لعبوا أكثر من 20 دقيقة مجمعين حسب الفريق
dt_result <- basketball_data[minutes_played > 20, 
 .(mean_pts = mean(points), mean_ast = mean(assists)), 
 by = team]
print("نتائج data.table فائقة السرعة:")
print(dt_result)

تعتمد data.table على فهرسة ثنائية داخلية مكتوبة بلغة C وإدارة ذكية للذاكرة، مما يجعلها قادرة على تنفيذ عمليات التصفية والتجميع بسرعة تتجاوز في كثير من الأحيان أسرع مكتبات Python لمعالجة البيانات.

10.2 التعديل في المكان (Update by Reference) باستخدام المشغل :=

أحد أقوى ابتكارات data.table هو مشغل الإسناد المرجعي :=، الذي يسمح بإضافة أو تعديل الأعمدة مباشرة في الذاكرة دون إنشاء أي نسخة إضافية من جدول البيانات في الرام (Zero-Copy Modification).

# إضافة عمود المتوسط الشرطي حسب الفريق في المكان الأصلي دون نسخ الجدول
basketball_data[, team_avg_points := mean(points), by = team]
# حساب متوسط شرطي مقيد بشرط داخلي وإسناده بالمرجع
basketball_data[starter == TRUE, starter_avg_mins := mean(minutes_played), by = team]
# عرض الجدول بعد التعديل بالمرجع
print(basketball_data[, .(player_name, team, points, team_avg_points, starter, starter_avg_mins)])

في بيئات الإنتاج والأنظمة التي تعالج تدفقات بيانات ضخمة، يمنع هذا الأسلوب حدوث أخطاء نفاد الذاكرة (Out of Memory Errors) ويقلل من زمن التنفيذ الإجمالي إلى أجزاء ضئيلة من الثانية.

11. التصور البياني للمتوسطات الشرطية باستخدام حزمة ggplot2

11.1 تمثيل المتوسطات الشرطية باستخدام الأعمدة البيانية ونقاط الخطأ

لا يكتمل التحليل الإحصائي دون تحويل المتوسطات الشرطية إلى تمثيلات بصرية واضحة تنقل الأنماط والنتائج بفعالية. توفر حزمة ggplot2 وظائف إحصائية مدمجة قوية مثل stat_summary() التي تستطيع حساب المتوسطات الشرطية وفترات الثقة ورسمها مباشرة من البيانات الخام دون الحاجة لجدولتها مسبقاً.

library(ggplot2)
# رسم بياني للأعمدة يمثل المتوسط الشرطي للنقاط حسب المركز مع أشرطة الخطأ القياسي
p1 <- ggplot(basketball_data, aes(x = position, y = points, fill = position)) +
 stat_summary(fun = mean, geom = "bar", alpha = 0.8, color = "black", width = 0.6) +
 stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.2, color = "darkred") +
 theme_minimal() +
 labs(
 title = "متوسط النقاط المشروط بمركز اللعب",
 subtitle = "الأعمدة تمثل المتوسط وأشرطة الخطأ تمثل الخطأ المعياري (SE)",
 x = "مركز اللعب",
 y = "متوسط النقاط"
 ) +
 theme(legend.position = "none")
# لحفظ الرسم البياني: ggsave("conditional_mean_bar.png", p1)

يوفر تمثيل الخطأ المعياري (Standard Error) أو فترة الثقة (Confidence Interval) بجانب المتوسط الشرطي سياقاً إحصائياً ضرورياً لفهم مدى دقة التقدير الإحصائي واستقرار التباين داخل كل فئة.

11.2 المخططات الصندوقية ومخططات الكثافة المشروطة

تتفوق المخططات الصندوقية (Boxplots) في قدرتها على إظهار المتوسط الحسابي جنباً إلى جنب مع الوسيط الإحصائي ومقاييس التشتت والربيعات، مما يكشف عن التواء التوزيع ووجود القيم الشاذة.

# رسم مخطط صندوقي مع تراكب نقاط المتوسط الحسابي الشرطي
p2 <- ggplot(basketball_data, aes(x = team, y = minutes_played, fill = team)) +
 geom_boxplot(alpha = 0.5, outlier.shape = NA) +
 geom_jitter(width = 0.1, alpha = 0.7, size = 2) +
 stat_summary(fun = mean, geom = "point", shape = 23, size = 4, fill = "yellow", color = "black") +
 theme_bw() +
 labs(
 title = "توزيع الدقائق الملعوبة مع تمثيل المتوسط الشرطي",
 subtitle = "النقطة الصفراء تمثل المتوسط الشرطي والخط الأفقي يمثل الوسيط",
 x = "الفريق",
 y = "الدقائق الملعوبة"
 )
# لحفظ الرسم البياني: ggsave("conditional_mean_box.png", p2)

يتيح هذا التراكب البصري المقارنة الفورية بين المتوسط والوسيط؛ فإذا انحرف المتوسط عن الوسيط داخل الصندوق، دل ذلك بوضوح على عدم تماثل التوزيع وتأثر المتوسط بالقيم المتطرفة في تلك الفئة المحددة.

12. الأخطاء البرمجية والإحصائية الشائعة وأفضل ممارسات التحقق

12.1 الأخطاء البرمجية الشائعة في كتابة الشروط في R وكيفية تصحيحها

يواجه المبرمجون والمحللون عدة أخطاء برمجية متكررة عند صياغة الشروط في R. من أبرز هذه الأخطاء الخلط بين مشغل الإسناد = ومشغل المساواة المنطقية ==؛ حيث يؤدي استخدام المشغل الأول داخل الفهرسة إلى حدوث خطأ نحوي يوقف تنفيذ البرنامج بالكامل.

خطأ شائع آخر يتمثل في استخدام المعاملات المنطقية ذات الرمز المزدوج && و || بدلاً من المعاملات الفردية & و |. المعاملات المزدوجة في R مصممة لتقييم عنصر فردي واحد (تُستخدم أساساً في جمل if الشرطية للتحكم في تدفق البرنامج)، وعند تطبيقها على متجهات البيانات فإنها تقيم العنصر الأول فقط وتتجاهل باقي المتجه تماماً، مما يقود إلى تصفية كارثية غير مقصودة دون إظهار أي رسالة خطأ صريحة.

بالإضافة إلى ذلك، تبرز مشاكل مطابقة النصوص الناتجة عن وجود مسافات بيضاء خفية في بداية السلاسل النصية أو نهايتها (مثل "Eagles " مقابل "Eagles"). لحل هذه الإشكالية، يجب تنظيف النصوص مسبقاً باستخدام الدالة trimws() لضمان دقة المطابقة.

# تنظيف المسافات البيضاء الزائدة قبل التصفية
clean_team_names <- trimws(basketball_data$team)
valid_rows <- clean_team_names == "Eagles"
mean(basketball_data$points[valid_rows])

12.2 المزالق الإحصائية وتفسير النتائج المشروطة

من أخطر المزالق الإحصائية التي قد يقع فيها المحلل عند التعامل مع المتوسطات الشرطية ما يعرف بـ مفارقة سيمبسون (Simpson’s Paradox)؛ وهي ظاهرة إحصائية يظهر فيها اتجاه معين عند دراسة مجموعات فرعية مشروطة، لكنه ينعكس تماماً أو يختفي عند تجميع هذه المجموعات معاً. يحدث هذا غالباً بسبب وجود متغير وسيط مربك (Confounding Variable) يوزع أوزان المشاهدات بشكل غير متكافئ بين الفئات.

كما يشكل “تحيز العينات الصغيرة” (Small Sample Bias) خطراً كبيراً عند الإفراط في تقسيم البيانات وتطبيق شروط متعددة شديدة التضييق، مما يؤدي إلى تقليص حجم المجموعة الفرعية إلى عدد ضئيل جداً من المشاهدات ((n < 5)). في هذه الحالات، تصبح المتوسطات المحسوبة غير مستقرة إحصائياً وتتأثر بشكل مفرط بأي قيمة عشوائية مفردة.

لضمان دقة التحليل وإمكانية إعادة إنتاجه (Reproducibility)، يوصى باتباع قائمة التدقيق التالية:

  • التحقق من حجم العينة الفرعية: تأكد دائماً من طباعة عدد المشاهدات المحققة للشرط sum(condition) للتأكد من كفايتها الإحصائية.
  • معالجة القيم المفقودة صراحة: حدد استراتيجيتك تجاه القيم المفقودة (حذف، استبدال، أو نمذجة) ولا تعتمد على السلوك التلقائي الصامت.
  • فحص التوزيع التكراري: افحص مقاييس التشتت (التباين والانحراف المعياري) إلى جانب المتوسط لتقييم مدى تجانس المجموعة الفرعية.
  • التوثيق البرمجي الكامل: دوّن الشروط المنطقية وأسباب اختيار العتبات الرقمية بوضوح داخل كود التحليل لضمان شفافية النتائج ومراجعتها العلمية.

خاتمة

استعرض هذا الدليل الشامل الأبعاد النظرية والتطبيقية لحساب المتوسط الشرطي في لغة R، مبيناً كيف يشكل هذا المفهوم جسراً يربط بين النظرية الإحصائية المجردة والتطبيقات العملية في علوم البيانات واتخاذ القرار. لقد رأينا كيف تتيح لغة R، بتنوع منظوماتها البرمجية من Base R إلى dplyr و data.table، مرونة لا متناهية تمكن المحلل من اختيار الأداة المثلى وفقاً لحجم البيانات، وسرعة المعالجة المطلوبة، ومستوى تعقيد الشروط المفروضة.

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

المراجع (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). https://CRAN.R-project.org/package=data.table
  • Matloff, N. (2011). The Art of R Programming: A Tour of Statistical Software Design. No Starch Press.
  • 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., François, R., Henry, L., & Müller, K. (2023). dplyr: A Grammar of Data Manipulation (R package version 1.1.2). https://CRAN.R-project.org/package=dplyr
  • Wickham, H., Çetinkaya-Rundel, M., & Grolemund, G. (2023). R for Data Science: Import, Tidy, Transform, Visualize, and Model Data (2nd ed.). O’Reilly Media. https://r4ds.hadley.nz/
  • Wickham, H. (2016). ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. https://ggplot2.tidyverse.org
  • Wooldridge, J. M. (2020). Introductory Econometrics: A Modern Approach (7th ed.). Cengage Learning.

اقتباس هذا المقال

looti, M. (2026, سبتمبر 1). كيفية حساب المتوسط الشرطي في R (مع أمثلة). عرب سايكلوجي. https://arabpsychology.com/how-to-calculate-conditional-mean-in-r-with-examples/
looti, Mohammed. “كيفية حساب المتوسط الشرطي في R (مع أمثلة).” عرب سايكلوجي, 1 سبتمبر 2026, https://arabpsychology.com/how-to-calculate-conditional-mean-in-r-with-examples/.
looti, Mohammed. “كيفية حساب المتوسط الشرطي في R (مع أمثلة).” عرب سايكلوجي. سبتمبر 1, 2026. https://arabpsychology.com/how-to-calculate-conditional-mean-in-r-with-examples/.