بايثونعلم البيانات

بانداس: كيفية ملء قيم NaN بالمتوسط الحسابي (3 أمثلة)

دليل شامل ومفصل يشرح كيفية استبدال وملء القيم المفقودة NaN بالمتوسط الحسابي في مكتبة Pandas عبر بايثون باستخدام 3 أمثلة تطبيقية عملية.

تاريخ النشر

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

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

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

1. مقدمة إلى مشكلة البيانات المفقودة في مكتبة بانداس (Pandas)

1.1 مفهوم القيم المفقودة (NaN) في هياكل بيانات بايثون

يُشير الرمز NaN، وهو اختصار للمصطلح الإنجليزي (Not a Number)، إلى قيمة عائمة خاصة تُعرّفها الجمعية الدولية لمهندسي الكهرباء والإلكترونيات وفق معيار IEEE 754 لتمثيل النتائج العددية غير المعرفة أو غير القابلة للتمثيل الحسابي، مثل ناتج قسمة الصفر على الصفر أو الجذر التربيعي لعدد سالب. في بيئة بايثون التحليلية، تعتمد مكتبة NumPy على كائن numpy.nan لتمثيل هذه الحالة الرياضية داخل المصفوفات الرقمية، ومن ثم تبنت مكتبة Pandas هذا التمثيل ليكون المعيار الموحد للفجوات البيانية داخل كائنات Series وDataFrame، حيث تتعامل معه كقيمة تطفو داخل الذاكرة دون أن تنتمي إلى أي تصنيف عددي حقيقي محدد.

تنشأ القيم المفقودة في تدفقات البيانات الحقيقية نتيجة طيف واسع من العوامل التشغيلية والفيزيائية. تشمل هذه العوامل فشل قراءة المجسات اللحظية في أجهزة إنترنت الأشياء (IoT)، وتجاوز مهلة الاستجابة (Timeouts) أثناء جلب البيانات عبر واجهات برمجة التطبيقات (APIs)، وتخطي المستخدمين لبعض الحقول الاختيارية أثناء ملء الاستبيانات الإلكترونية، فضلاً عن أخطاء الدمج والربط الخارجي (Outer Joins) بين جداول قواعد البيانات غير المتماثلة. هذا التنوع في مصادر النقص يجعل وجود قيم NaN أمراً حتمياً لا يمكن تفاديه في معظم المشاريع البرمجية التطبيقية.

يترتب على وجود قيم NaN غير المعالجة تأثيرات بالغة الخطورة على كفاءة الخوارزميات واستقرار النماذج الإحصائية ونماذج تعلم الآلة (Scikit-Learn). فالعديد من خوارزميات الانحدار، والشبكات العصبية الاصطناعية، ومحركات حساب المسافات الإقليدية مثل خوارزمية الجار الأقرب (KNN) لا تمتلك القدرة الرياضية على إجراء العمليات الجبرية عند وجود مدخل غير محدد، مما يؤدي إما إلى توقف تنفيذ البرمجية بالكامل وإطلاق استثناءات خطأ (Exceptions)، أو إلى تسرب القيمة غير المعرفة عبر كامل العمليات الحسابية المتتالية، حيث تُنتج أي عملية جمع أو ضرب تتضمن NaN قيمة NaN جديدة كنتيجة حتمية، وهو ما يُعرف بظاهرة تفشي القيم غير المعرفة في الحسابات العددية.

1.2 أهمية معالجة الفجوات البيانية قبل التحليل الاستكشافي

تُمثل مرحلة تنظيف وهندسة البيانات الخطوة التأسيسية التي تُبنى عليها كافة استنتاجات التحليل الاستكشافي للبيانات (Exploratory Data Analysis – EDA). إن ضمان استمرارية المعالجة الحسابية يتطلب معالجة استباقية للفجوات الرقمية لتفادي التوقف المفاجئ لنصوص بايثون البرمجية عند استدعاء الدوال التجميعية أو المصفوفية. تتيح المعالجة المنهجية المسبقة الانتقال بسلاسة عبر مختلف مراحل التحليل الإحصائي، وتوليد الرسوم البيانية، وحساب مصفوفات التغاير دون مواجهة رسائل تحذيرية أو أخطاء تعطل تدفق العمل.

علاوة على ذلك، تبرز مسألة الحفاظ على الحجم الفعلي للعينة الإحصائية كعامل حاسم في اتخاذ قرار المعالجة بدلاً من الحذف السريع. يؤدي اللجوء إلى حذف الصفوف التي تحتوي على قيم مفقودة (Listwise Deletion عبر دالة dropna()) إلى فقدان كميات هائلة من البيانات الصالحة المرتبطة بمتغيرات أخرى داخل السجل نفسه. فإذا كانت نسبة الفقد 5% موزعة عشوائياً عبر 20 متغيراً مختلفاً، فإن الحذف الإجمالي قد يتسبب في تدمير أكثر من 60% من حجم العينة الكلية، مما يقلل بشكل كارثي من القوة الإحصائية (Statistical Power) للدراسة ويُفرغ الاختبارات من قدرتها على اكتشاف الفروق الحقيقية ذات الدلالة.

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

1.3 نظرة عامة على منهجية التعويض بالمتوسط الحسابي (Mean Imputation)

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

تُعد هذه الطريقة مثالية ومفضلة في بيئات المعالجة السريعة، وخطوط الإنتاج البرمجية التي تتطلب سرعة فائقة في التنفيذ بزمن تعقيد خطي $O(N)$، وحالات النقص المنخفض التي لا تتجاوز 5% إلى 10% من إجمالي المتغير. كما تبرز فائدتها القصوى عندما تتبع البيانات توزيعاً طبيعياً غاوسياً (Gaussian Distribution) وتكون آلية الفقدان عشوائية بالكامل، حيث لا يؤدي التعويض بالمتوسط حينها إلى تشويه الموضع المركزي للتوزيع أو إزاحة القيمة المتوقعة للمجتمع الإحصائي قيد الدراسة.

يقدم هذا الدليل التطبيقي ثلاث طرائق محورية لتنفيذ هذه المنهجية باستخدام مكتبة Pandas:

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

2. الأسس الرياضية والإحصائية لاستبدال القيم المفقودة بالمتوسط

2.1 النزعة المركزية وتوزيع البيانات الكمية

يُعرّف المتوسط الحسابي البسيط ($\bar{x}$) لمجموعة بيانات مرصودة تتألف من $n$ من المشاهدات بالصيغة الرياضية التالية:

$$\bar{x} = \frac{1}{n} \sum_{i=1}^{n} x_i$$

عندما تُستبدل القيم المفقودة في متغير ما بالقيمة $\bar{x}$، فإن هذا الإجراء يضمن رياضياً بقاء المجموع التراكمي المرجح وموضع مركز الثقل الإحصائي للبيانات ثابتاً دون أي انزياح جانبي. إذا كانت البيانات تتبع توزيعاً طبيعياً معيارياً متماثلاً، فإن المتوسط الحسابي يتطابق تماماً مع الوسيط والمنوال، مما يجعل التعويض بالمتوسط يحافظ على قمة المنحنى الجرسي في موضعها الأصلي دون إحداث انحراف في شكل التوزيع.

تستند هذه المنهجية على فرضية أساسية في نظرية البيانات المفقودة صاغها الإحصائي دونالد روبين، وتُعرف بآلية الفقدان العشوائي التام (Missing Completely at Random – MCAR). تعني هذه الفرضية أن احتمالية فقدان أي قيمة لا ترتبط نهائياً بالقيمة الحقيقية للمتغير نفسه، ولا ترتبط بأي متغير آخر داخل مجموعة البيانات. في ظل تحقق شرط MCAR، يمثل المتوسط الحسابي للمشاهدات المكتملة تقديراً غير متحيز لمتوسط المجتمع الإحصائي الحقيقي. أما إذا كان الفقدان يتبع آلية الفقدان العشوائي المشروط (MAR) أو الفقدان غير العشوائي (MNAR)، فإن التعويض بالمتوسط يؤدي إلى إدخال تحيزات هيكلية في التقديرات.

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

2.2 تأثير التعويض على التباين والانحراف المعياري

على الرغم من قدرة التعويض بالمتوسط على الحفاظ على النزعة المركزية، إلا أنه يُحدث أثراً سلبياً حتمياً على مقاييس التشتت، وتحديداً التباين الإحصائي ($s^2$) والانحراف المعياري ($s$). يُحسب التباين العيني الكلاسيكي بالصيغة:

$$s^2 = \frac{1}{N – 1} \sum_{i=1}^{N} (x_i – \bar{x})^2$$

عند تعويض القيم المفقودة بالقيمة $\bar{x}$، تصبح المسافة بين القيمة المعوضة والمتوسط الحسابي مساوية للصفر تماماً ($(\bar{x} – \bar{x})^2 = 0$). وبالتالي، فإن بسط معادلة التباين (مجموع مربعات الانحرافات) يظل ثابتاً دون أي زيادة، بينما يزداد المقام من $(n – 1)$ إلى $(N – 1)$ حيث $N$ يمثل الحجم الكلي للعينة بعد التعويض ($N = n + m$، حيث $m$ هو عدد القيم المفقودة المعوضة).

تؤدي هذه الظاهرة إلى ما يُعرف في الأدبيات الإحصائية بانكماش التباين (Variance Shrinkage) أو التخفيف الاصطناعي لتشتت البيانات. ينتج عن هذا الانكماش تضييق غير حقيقي لفترات الثقة (Confidence Intervals) وخفض لقيمة الخطأ المعياري (Standard Error)، مما يعطي انطباعاً زائفاً بالدقة الإحصائية ويزيد من احتمالية ارتكاب الخطأ من النوع الأول (Type I Error) في اختبارات الفرضيات، حيث يتم رفض الفرضيات الصفرية الصحيحة بسبب تضخيم دلالة النتائج المصطنعة.

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

3. تشريح الدوال البرمجية: آلية عمل fillna() و mean() في Pandas

3.1 الخصائص المعمارية لدالة fillna()

تُعد الدالة fillna() الأداة الأساسية والأكثر مرونة داخل مكتبة Pandas لمعالجة الفراغات البيانية. تمتلك هذه الدالة تركيبة معمارية متطورة تمكنها من العمل بتوافق كامل على كل من السلاسل الفردية Series وأطر البيانات المعقدة DataFrame. تأخذ الدالة عدداً من المعاملات التشغيلية التي تحدد مسار المعالجة وسلوك إدارة الذاكرة، وأبرزها المعامل value الذي يحدد القيمة الرياضية أو القاموس الحسابي المستخدم لإحلال الفراغات.

تتيح الدالة استخدام المعامل inplace كخيار منطقي (Boolean). عند ضبطه على False (وهو الوضع الافتراضي والأكثر أماناً في بايثون)، تقوم الدالة بتوليد كائن بيانات جديد كلياً في الذاكرة بعد تطبيق التعويض، تاركة إطار البيانات الأصلي دون تغيير، وهو ما يعزز مبدأ عدم القابلية للتغيير (Immutability) وتسهيل تتبع التدفق الحسابي. أما عند ضبطه على inplace=True، فإن العملية تُجري التعديل مباشرة على الكائن الأصلي داخل نطاق الذاكرة المشغول، وهي ممارسة قديمة بدأت مكتبة Pandas في التراجع عنها لتقليل الآثار الجانبية المرتبطة بالنسخ والتعديل غير المقصود.

تتعامل fillna() بذكاء فائق مع أنواع البيانات المختلفة (Data Types – Dtypes). عند تعويض قيمة مفقودة داخل عمود رقمي صحيح (Integer) بقيمة متوسط تحتوي على كسور عشرية، تقوم الدالة تلقائياً وبشكل تكيفي بترقية نوع بيانات العمود من int64 إلى float64 لمنع فقدان الدقة الحسابية، ما لم يتم إجبار الإطار على استخدام أنواع بيانات تتيح القيم الفارغة صراحة مثل Int64 المدمجة حديثاً في Pandas.

3.2 سلوك دالة mean() وتجاهل القيم المفقودة تلقائياً

تختص دالة mean() بحساب المتوسطات الرياضية عبر أبعاد هياكل البيانات المختلفة. تتميز هذه الدالة بسلوك افتراضي حاسم يتمثل في امتلاكها المعامل skipna=True بصورة مسبقة ومثبتة. يعني ذلك أن الدالة، عند استدعائها على أي عمود أو إطار بيانات، تقوم آلياً بفلترة واستبعاد كافة قيم NaN من حسابات البسط (مجموع القيم) والمقام (عدد الملاحظات)، وتقتصر في حسابها فقط على الأرقام الحقيقية المتاحة، وهو ما يضمن عدم إرجاع NaN كنتيجة للعملية الحسابية الإجمالية.

يتحدد اتجاه الحساب داخل الدالة عبر معامل المحور axis. عند ضبط المعامل على القيمة الافتراضية axis=0 (أو axis='index')، تتحرك الدالة رأسياً لتقوم بحساب المتوسط الحسابي لكل عمود على حدة عبر جميع الصفوف الممتدة. في المقابل، عند توجيهه إلى axis=1 (أو axis='columns')، تتحول العملية لتصبح أفقية، حيث تحسب المتوسط لكل صف على حدة عبر جميع الأعمدة المتقاطعة، وهو نمط نادر الاستخدام في التعويض الإحصائي المتعامد لاختلاف دلالات المتغيرات المستقلة.

في الحالات القصوى التي يحتوي فيها عمود رقمي بالكامل على قيم NaN دون وجود أي مدخل رقمي مفرد، فإن استدعاء mean() مع skipna=True سيعجز عن إيجاد قيم صالحة في المقام، مما يدفعه إلى إرجاع NaN كنتيجة نهائية للمتوسط نفسه. في هذا السيناريو الاستثنائي، يفشل تطبيق fillna() المباشر في تغيير حالة العمود، ويظل محتفظاً بفراغاته ما لم يتم دمج شروط منطقية دفاعية لمعالجة الأعمدة الفارغة كلياً قبل البدء في عمليات الإسناد الرياضي.

3.3 التكامل البرمجي بين المتجهات والعمليات الحسابية في Pandas

تعتمد مكتبة Pandas في جوهرها التنفيذي على مفهوم العمليات المتجهية (Vectorized Operations) المكتوبة بلغة C عبر طبقات NumPy التحتية. يتيح هذا التصميم تجنب الحلقات التكرارية البطيئة (Iterative Loops) في بايثون، وتنفيذ العمليات الحسابية والمنطقية على مصفوفات الذاكرة المتتالية بسرعات حاسوبية فائقة تستغل قدرات المعالجات الحديثة في تنفيذ التعليمات المتعددة على البيانات الأحادية (SIMD).

أثناء دمج دالة fillna() مع mean()، يحدث تكامل هندسي دقيق يُعرف بمحاذاة الفهارس التلقائية (Automatic Index and Column Alignment). عند تمرير كائن سلسلة إحصائية ناتج عن df.mean() إلى دالة df.fillna()، يقوم محرك Pandas بمطابقة أسماء الأعمدة في السلسلة الحسابية مع أسماء الأعمدة المقابلة في إطار البيانات المستهدف تلقائياً، وتوزيع قيمة المتوسط المناسبة على كل خلية مفقودة بناءً على توافق المفاتيح البنيوية دون أدنى تداخل خاطئ بين المتغيرات المختلفة.

يساعد الفهم العميق لتدفق العمليات المتجهية على تفادي واحد من أشهر التحذيرات البرمجية في مجتمع بايثون، وهو تحذير SettingWithCopyWarning. يظهر هذا التحذير عندما يحاول المبرمج تطبيق التعديل على شريحة بيانات فرعية (Slice) معزولة جزئياً بدلاً من إطار البيانات الأصلي. ويضمن الاعتماد على الصيغ البرمجية الصريحة للإسناد المتجهي، أو استخدام محددات المواقع المباشرة مثل .loc[:, :]، بقاء عمليات المعالجة آمنة وسريعة وخالية تماماً من الغموض البرمجي المتعلق بالنسخ المرجعية (Chained Indexing).

4. تجهيز بيئة العمل وبناء إطار البيانات النموذجي

4.1 استيراد المكتبات الأساسية وضبط الإعدادات

لبدء التطبيق العملي، يتعين إعداد بيئة التطوير واستيراد الحزم البرمجية الأساسية المعنية بالحساب المصفوفي وإدارة الجداول. يتم الاعتماد بشكل رئيسي على مكتبة pandas لإدارة الجداول ومكتبة numpy لتوفير الرمز الرياضي الخاص بالقيم المفقودة np.nan. يُفضل دائماً التحقق من أرقام إصدارات الحزم لضمان توافق سلوك الدوال الرياضية وتجنب التغييرات الطارئة في الإصدارات الأحدث.

يمكن تهيئة البيئة البرمجية وضبط خيارات العرض القياسية عبر الشيفرة التالية:

import pandas as pd
import numpy as np
# ضبط خيارات العرض لإظهار الأرقام العشرية بدقة محددة وتنسيق المخرجات
pd.set_option('display.max_columns', 10)
pd.set_option('display.precision', 2)
print("Pandas Version:", pd.__version__)
print("NumPy Version:", np.__version__)

يضمن ضبط الدقة العشرية عبر pd.set_option('display.precision', 2) توحيد قراءة المخرجات الحسابية في شاشات العرض الطرفية، مما يسهل مقارنة القيم الأصلية بالقيم المعوضة وملاحظة التغيرات الطفيفة في المتوسطات والانحرافات المعيارية الناتجة عن عمليات المعالجة.

4.2 إنشاء إطار بيانات اختباري يحتوي على فجوات رقمية

سنقوم ببناء إطار بيانات يحاكي سجلات الأداء الرياضي لمجموعة من لاعبي كرة السلة المحترفين. يتضمن الإطار خمسة متغيرات مختلفة تشمل اسم اللاعب كمتغير نصي تعريفي (نص)، وتقييم الأداء العام (rating)، وعدد النقاط المسجلة (points)، ومعدل التمريرات الحاسمة (assists)، وإجمالي المتابعات الدفاعية (rebounds). سنقوم بتوزيع قيم np.nan بصورة متعمدة داخل الأعمدة الرقمية لتمثيل سيناريوهات الفقدان المختلفة.

# بناء القاموس الهيكلي للبيانات التجريبية
raw_data = {
 'player': ['Tariq', 'Zaid', 'Omar', 'Kareem', 'Sami', 'Fahad', 'Bilal', 'Hassan'],
 'rating': [88.5, np.nan, 79.0, 91.5, np.nan, 84.0, 77.5, 89.0],
 'points': [24.0, 18.0, np.nan, 32.0, 15.0, np.nan, 21.0, 28.0],
 'assists': [7.0, 5.0, 8.0, np.nan, 3.0, 6.0, np.nan, 9.0],
 'rebounds': [11.0, 8.0, 6.0, 14.0, 5.0, 7.0, 4.0, 10.0]
}
# تحويل القاموس إلى إطار بيانات Pandas
df = pd.DataFrame(raw_data)
# طباعة إطار البيانات الأولي
print("--- إطار البيانات الأولي قبل المعالجة ---")
print(df)

يحتوي هذا الإطار على تنوع مقصود في مواقع الفقدان: عمود rating يحتوي على قيمتين مفقودتين، وعمود points يحتوي على قيمتين مفقودتين، وعمود assists يحتوي على قيمتين مفقودتين أيضاً، بينما يظل عمود rebounds مكتملاً بنسبة 100% ليكون معياراً مرجعياً للتحقق من عدم تأثر المتغيرات السليمة أثناء عمليات التنفيذ اللاحقة.

4.3 الفحص الاستكشافي الأولي للقيم المفقودة

قبل الشروع في أي عملية تعديل، يجب إجراء مسح تشخيصي شامل لتحديد توزيع وحجم الفجوات في كل عمود. توفر مكتبة Pandas دالتي isnull() وisna() (وهما متطابقتان تماماً في الأداء) لاكتشاف الخلايا الفارغة، وبدمجهما مع الدالة التجميعية sum() نحصل على تعداد رقمي دقيق للقيم المفقودة لكل متغير.

# فحص عدد القيم المفقودة والنسبة المئوية لكل عمود
missing_counts = df.isnull().sum()
missing_percentage = (df.isnull().sum() / len(df)) * 100
missing_summary = pd.DataFrame({
 'Missing Values': missing_counts,
 'Percentage (%)': missing_percentage
})
print("--- ملخص الفجوات البيانية ---")
print(missing_summary)
# استعراض الملخص الإحصائي الأولي للأعمدة الرقمية
print("n--- الإحصاء الوصفي قبل التعويض ---")
print(df.describe())

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

5. المثال الأول: تعويض قيم NaN بالمتوسط الحسابي في عمود واحد محدد

5.1 التحليل الموضعي لعمود النقاط (points)

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

لحساب متوسط عمود النقاط، نقوم باستدعاء الدالة على السلسلة المعزولة:

# حساب المتوسط الحسابي لعمود النقاط فقط
points_mean = df['points'].mean()
print(f"المتوسط الحسابي لعمود النقاط (points): {points_mean:.2f}")

يتألف عمود النقاط من 6 قيم صالحة: $[24.0, 18.0, 32.0, 15.0, 21.0, 28.0]$، ومجموع هذه القيم يبلغ 138.0. بقسمة المجموع على عدد المشاهدات الفعلية (6)، نحصل على متوسط حسابي قدره 23.0 نقطة تماماً. يُلاحظ أن هذا الرقم يقع في المنتصف المنطقي بين القيمة الصغرى (15.0) والقيمة العظمى (32.0)، مما يجعله بديلاً متزناً للحلول محل الملاحظات المفقودة عند اللاعبين “عمر” و”فهد”.

5.2 صياغة الشفرة البرمجية والتطبيق العملي

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

# إنشاء نسخة احتياطية من إطار البيانات للاختبار
df_example1 = df.copy()
# تعويض قيم NaN بالمتوسط الحسابي لعمود points حصرياً
df_example1['points'] = df_example1['points'].fillna(df_example1['points'].mean())
# استعراض النتيجة بعد التعديل
print("--- إطار البيانات بعد معالجة عمود points فقط ---")
print(df_example1)

تتم عملية التنفيذ الحسابي عبر قراءة السلسلة df_example1['points']، وحساب القيمة 23.0 داخلياً، ثم مسح مواقع المؤشرات الفهرسية (Indices 2 و 5) التي تحتوي على NaN واستبدالها بالقيمة 23.0، مع الحفاظ الكامل على القيم الأصلية في المواقع الفهرسية الأخرى دون تغيير.

5.3 تقييم النتائج وضمان سلامة البيانات المجاورة

عند فحص إطار البيانات df_example1 بعد تنفيذ العملية، يمكن التحقق بوضوح من تحقق الأهداف التالية بدقة متناهية:

  • تم سد الفراغات في عمود points وأصبح يحتوي على 8 مشاهدات مكتملة مع بقاء متوسطه ثابتاً عند 23.00.
  • بقيت الأعمدة الأخرى مثل rating وassists محتفظة بقيم NaN الأصلية الخاصة بها، مما يؤكد أن نطاق التأثير البرمجي كان محصوراً وموضعياً بنسبة 100%.
  • ظل نوع البيانات float64 مستقراً دون أي تشويه في البنية الهندسية للعمود.
# التحقق البرمجي من انعدام القيم المفقودة في عمود points فقط
print("القيم المفقودة المتبقية في عمود points:", df_example1['points'].isnull().sum())
print("القيم المفقودة المتبقية في عمود rating:", df_example1['rating'].isnull().sum())

يؤكد هذا الاختبار نجاح عملية العزل البرمجي، حيث تصبح القيمة المرجعة لعدد القيم المفقودة في points مساوية للصفر، بينما يظل عمود rating مسجلاً لوجود قيمتين مفقودتين كما كان في الحالة الابتدائية.

6. المثال الثاني: تعويض قيم NaN بالمتوسط الحسابي في أعمدة متعددة محددة

6.1 تحديد قائمة الأعمدة المستهدفة (rating و assists)

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

يتطلب هذا الإجراء تمرير قائمة بايثون تحتوي على أسماء الأعمدة المستهدفة: target_cols = ['rating', 'assists']. عند استدعاء df[target_cols].mean()، لا تقوم مكتبة Pandas بحساب رقم مفرد لكامل البيانات المدمجة، بل تولد كائن Series إحصائي يحمل متوسطاً مستقلاً لكل عمود مفهرساً باسمه:

# استخراج المتوسطات المنفصلة للمجموعة المحددة
target_cols = ['rating', 'assists']
subset_means = df[target_cols].mean()
print("--- المتوسطات الحسابية للأعمدة المختارة ---")
print(subset_means)

تُظهر المخرجات أن متوسط عمود rating المحسوب من قيمه الست الصالحة هو 83.25، بينما يبلغ متوسط عمود assists المحسوب من قيمه الصالحة 6.33. هذا التمايز يضمن تطبيق كل متوسط على عموده المقابل حصراً.

6.2 تطبيق الشفرة البرمجية للأعمدة المتعددة

يتم تنفيذ التعويض المتزامن عبر استغلال قوة التجهيز المصفوفي للأعمدة المتعددة في Pandas من خلال تمرير الشريحة الثنائية للطرفين الأيمن والأيسر من معادلة الإسناد:

# إنشاء نسخة احتياطية جديدة
df_example2 = df.copy()
# تطبيق التعويض المتزامن على الأعمدة المحددة
df_example2[target_cols] = df_example2[target_cols].fillna(df_example2[target_cols].mean())
# استعراض الجدول بعد التحديث المشترك
print("--- إطار البيانات بعد معالجة عمودي rating و assists معاً ---")
print(df_example2)

يقوم محرك Pandas في هذه الخطوة بمحاذاة السلسلة الناتجة عن mean() عبر المحور الأفقي للأعمدة المحددة في df_example2[target_cols]، حيث يتم استبدال قيم NaN في عمود rating بالقيمة 83.25، واستبدال قيم NaN في عمود assists بالقيمة 6.33 في عملية برمجية موحدة وذات كفاءة عالية تتفوق بمراحل على كتابة حلقات تكرارية يدوية.

6.3 التحقق من دقة النتائج الإحصائية للأعمدة المستهدفة

للتحقق من سلامة البنية الحسابية بعد التحديث، نقوم بفحص مصفوفة الفراغات والتأكد من استقلالية التعديلات:

# فحص الفجوات المتبقية عبر كامل الإطار
print("--- فحص الفجوات المتبقية بعد المثال الثاني ---")
print(df_example2.isnull().sum())

توضح المخرجات البرمجية أن كلاً من rating وassists أصبحا خاليين تماماً من أي قيم مفقودة (0 قيم مفقودة)، في حين ظل عمود points محتفظاً بفجوتيه الأصليتين (2 قيم مفقودة) لأنه لم يكن مدرجاً ضمن قائمة target_cols. يوضح ذلك المرونة المطلقة في التحكم بالأبعاد المستهدفة بدقة متناهية دون المساس بباقي فروع قاعدة البيانات.

7. المثال الثالث: تعويض قيم NaN بالمتوسط الحسابي لجميع أعمدة إطار البيانات

7.1 التعويض الشامل عبر كامل إطار البيانات

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

الصيغة الكلاسيكية المباشرة لتنفيذ هذا الإجراء هي:

# تطبيق التعويض الشامل بافتراض تجانس الأعمدة الرقمية
# ملاحظة: سنطبق هذا الإجراء أولاً على الأعمدة الرقمية فقط لبيان المفهوم
df_example3 = df.copy()
# استخراج المتوسطات لكافة الأعمدة الرقمية تلقائياً
numeric_means = df_example3.mean(numeric_only=True)
print("--- المتوسطات الحسابية لجميع الأعمدة الرقمية ---")
print(numeric_means)
# ملء الفراغات عبر كامل الإطار باستخدام المتجهات المحسوبة
df_example3 = df_example3.fillna(numeric_means)
print("n--- إطار البيانات النهائي بعد التعويض الشامل ---")
print(df_example3)

في هذا التنفيذ، تقوم df.mean(numeric_only=True) بحساب متجه كامل يضم المتوسطات الخاصة بجميع الأعمدة الرقمية المتاحة (rating: 83.25, points: 23.00, assists: 6.33, rebounds: 8.38). عند تمرير هذا المتجه إلى df_example3.fillna()، تتولى الدالة تلقائياً مطابقة كل عمود مع متوسطه الخاص وسد كافة الفجوات المنتشرة في الجدول في خطوة برمجية واحدة.

7.2 تتبع مخرجات التنفيذ خطوة بخطوة

بعد إتمام عملية التعويض الشامل، نقوم بإجراء فحص قطعي باستخدام التعبير المنطقي df.isnull().values.any() للتأكد رياضياً من خلو المصفوفة الإجمالية من أي قيمة مفقودة على الإطلاق:

# التحقق القطعي من خلو إطار البيانات بالكامل من NaN
has_any_nan = df_example3.isnull().values.any()
total_nan_count = df_example3.isnull().sum().sum()
print(f"هل توجد أي قيم مفقودة متبقية في الإطار؟ {has_any_nan}")
print(f"إجمالي عدد الفجوات المتبقية: {total_nan_count}")

تُرجع هذه الأوامر القيمة False للسؤال الأول والرقم 0 للإجمالي، مما يعطي تأكيداً حاسماً على اكتمال نظافة إطار البيانات بنسبة 100%، حيث أصبحت كافة السجلات الرياضية للاعبين الثمانية ممتلئة بالقيم التقديرية المتوازنة إحصائياً والجاهزة للاستخدام في العمليات اللاحقة.

7.3 المخاطر المحتملة للتعويض الشامل الأعمى

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

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

المنهجية البرمجية نطاق الاستخدام الأمثل أبرز المزايا المخاطر والعيوب الرئيسية
عمود واحد منفرد
df['col'].fillna(...)
المتغيرات الحرجة وهندسة الميزات الموجهة بدقة عزل تام، أمان عالي، تحكم كامل في نوع البيانات تكرار الشيفرة البرمجية عند الحاجة لمعالجة أعمدة عديدة
أعمدة متعددة محددة
df[cols].fillna(...)
حزم المتغيرات الرقمية المتجانسة ذات التوزيع الطبيعي كفاءة متجهية، وضوح برمجي، استثناء الأعمدة الحساسة تتطلب تحديداً يدوياً مسبقاً لأسماء الأعمدة المناسبة
التعويض الشامل
df.fillna(df.mean())
النماذج الأولية السريعة والبيانات الرقمية المتجانسة تماماً تنفيذ شامل وسريع بسطر واحد، أتمتة كاملة للمصفوفة خطر تشويه المتغيرات المنفصلة والتصنيفية ومخاطر كسر التنفيذ

8. التعامل مع الأعمدة غير الرقمية (Non-Numeric) وتفادي أخطاء التنفيذ

8.1 مشكلة استدعاء mean() على البيانات النصية والتصنيفية

في الإصدارات القديمة من مكتبة Pandas، كان استدعاء df.mean() على إطار بيانات يحتوي على أعمدة نصية (Strings) أو كائنات (Objects) يمر بهدوء عبر استبعاد النصوص تلقائياً في الخلفية. ومع ذلك، وبدءاً من إصدارات Pandas 2.0 والإصدارات اللاحقة، طرأ تحول جذري في المعمارية البرمجية للمكتبة نحو فرض قيود صارمة على الأنواع لتفادي السلوكيات غير المتوقعة.

أصبح استدعاء df.mean() الافتراضي على إطار بيانات يتضمن نصوصاً (مثل عمود player في مثالنا السابق) يُطلق استثناء خطأ صريح من نوع TypeError: can only concatenate str (not "float") to str أو TypeError: Could not convert string to numeric، مما يؤدي إلى انهيار تنفيذ خط المعالجة بالكامل وتوقف الأنابيب البرمجية في بيئات الإنتاج. يتطلب السلوك الحديث تعيين المعامل numeric_only=True بشكل صريح داخل دالة mean() لإجبار المحرك الحسابي على تجاهل الأعمدة النصية والتصنيفية بصورة آمنة.

8.2 استخدام select_dtypes لعزل الأعمدة الرقمية بأمان

تُعد أفضل الممارسات الهندسية لعزل المتغيرات ومعالجتها دون التعرض لمفاجآت تغير سلوك الدوال في الإصدارات البرمجية هي استخدام الدالة المعمارية select_dtypes(). تتيح هذه الدالة فلترة إطار البيانات واستخلاص أسماء الحقول المتوافقة مع أنواع عددية محددة بدقة بالغة:

# عزل كافة الأعمدة الرقمية (أعداد صحيحة وعشرية) بدقة وأمان
numeric_columns = df.select_dtypes(include=[np.number]).columns
print("الأعمدة الرقمية المكتشفة تلقائياً:", list(numeric_columns))
# تطبيق التعويض الحسابي حصرياً على المتغيرات المستخلصة
df_safe = df.copy()
df_safe[numeric_columns] = df_safe[numeric_columns].fillna(df_safe[numeric_columns].mean())
print("n--- إطار البيانات المعالج بأمان عبر select_dtypes ---")
print(df_safe)

تضمن هذه الاستراتيجية الدفاعية استقرار النظام البرمجي بنسبة 100%؛ فمهما تمت إضافة أعمدة نصية، أو حقول تواريخ (Datetime)، أو متغيرات منطقية (Booleans) جديدة إلى تدفق البيانات الخام مستقبلاً، فإن الشيفرة ستعزل الأرقام الحقيقية تلقائياً وتطبق عليها التعويض بالمتوسط الحسابي دون أن تتأثر الحقول غير الرقمية أو تتسبب في إطلاق أخطاء تشغيلية.

8.3 استراتيجيات هجينة لمعالجة أطر البيانات المختلطة

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

يمكن بناء خط أنابيب معالجة هجين ومتكامل يتعامل تلقائياً وبشكل تكيفي مع مختلف أنواع الحقول عبر الدالة المعيارية المخصصة التالية:

def hybrid_imputer(dataframe):
 """
 دالة معالجة هجينة تقوم بتعويض الفجوات الرقمية بالمتوسط الحسابي
 وتعويض الفجوات التصنيفية والنصية بالمنوال الأكثر تكراراً.
 """
 df_imputed = dataframe.copy()
 
 # 1. معالجة الأعمدة الرقمية بالمتوسط
 num_cols = df_imputed.select_dtypes(include=[np.number]).columns
 for col in num_cols:
 if df_imputed[col].isnull().any():
 mean_val = df_imputed[col].mean()
 df_imputed[col] = df_imputed[col].fillna(mean_val)
 
 # 2. معالجة الأعمدة غير الرقمية بالمنوال
 cat_cols = df_imputed.select_dtypes(exclude=[np.number]).columns
 for col in cat_cols:
 if df_imputed[col].isnull().any():
 # استخراج القيمة الأكثر تكراراً (المنوال الأول)
 mode_val = df_imputed[col].mode()[0]
 df_imputed[col] = df_imputed[col].fillna(mode_val)
 
 return df_imputed
# تجربة الأنبوب الهجين على بيانات تحتوي على نقص نصي ورقمي
mixed_data = df.copy()
mixed_data.loc[0, 'player'] = np.nan # إدخال نقص نصي اختباري
clean_mixed_df = hybrid_imputer(mixed_data)
print("--- نتيجة خط الأنابيب الهجين المخصص ---")
print(clean_mixed_df)

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

9. الآثار الإحصائية المترتبة على التعويض بالمتوسط الحسابي

9.1 تشويه العلاقات الارتباطية والتباين المشترك (Covariance)

إن الأثر الإحصائي الأكثر حساسية لاستبدال الفجوات بالمتوسط الحسابي يكمن في تشويه التباين المشترك ($Cov(X, Y)$) وتخفيض قيمة معاملات ارتباط بيرسون ($r_{xy}$) بين المتغيرات. يُعرّف الارتباط الخطي بين متغيرين $X$ و $Y$ بالمعادلة التالية:

$$r_{xy} = \frac{\sum (x_i – \bar{x})(y_i – \bar{y})}{\sqrt{\sum (x_i – \bar{x})^2 \sum (y_i – \bar{y})^2}}$$

عندما تكون الملاحظة $x_i$ مفقودة ويتم استبدالها بالمتوسط $\bar{x}$، فإن حد الانحراف الخاص بها يصبح مساوياً للصفر: $(x_i – \bar{x}) = 0$. ويترتب على ذلك أن حاصل الضرب التبادلي $((x_i – \bar{x})(y_i – \bar{y}))$ في بسط المعادلة يصبح صفراً مطلقاً، مما يحرم العلاقة الارتباطية من المساهمة التراكمية الحقيقية التي كانت ستضيفها تلك المشاهدة لو تم رصدها فعلياً في الواقع.

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

# مقارنة مصفوفة الارتباط قبل التعويض وبعده
print("--- مصفوفة الارتباط للبيانات الأصلية (تجاهل المشاهدات المفقودة) ---")
print(df.corr(numeric_only=True))
print("n--- مصفوفة الارتباط بعد التعويض بالمتوسط الحسابي ---")
print(df_example3.corr(numeric_only=True))

يُلاحظ بوضوح عند تدقيق المصفوفات أن قيم الارتباط بين المتغيرات تنخفض في مصفوفة البيانات المعوضة مقارنة بالمصفوفة الأصلية المحسوبة عبر الاقتران الزوجي (Pairwise Deletion)، مما يؤكد نظرياً وعملياً الأثر المثبط للتعويض بالمتوسط على الروابط البينية.

9.2 التأثير على نماذج التعلم الإشرافي (Supervised Learning)

عند استخدام مجموعات البيانات المعالجة بالمتوسط لتغذية خوارزميات التعلم الإشرافي (مثل الانحدار اللوجستي، وأشجار القرار، والانحدار الخطي المتعدد)، تبرز مجموعة من التحديات الهيكلية. فبما أن التعويض بالمتوسط يقلص التباين الداخلي للميزات المستقلة، فإن الخوارزميات قد تعاني في تقدير معاملات الانحدار ($\beta$ coefficients) الحقيقية، وغالباً ما تتجه نحو التقليل من وزن الميزات التي تعرضت لمستويات عالية من التعويض.

علاوة على ذلك، ينشأ خطر جسيم في هندسة تعلم الآلة يُعرف بـ تسرب البيانات (Data Leakage). يحدث هذا التسرب عندما يقوم المطور بحساب المتوسط الحسابي الإجمالي لكامل مجموعة البيانات (بما في ذلك بيانات التدريب وبيانات الاختبار معاً) قبل تقسيم البيانات (Train-Test Split). يؤدي هذا الخطأ المنهجي إلى تسريب معلومات إحصائية من مجموعة الاختبار المستقبلية إلى مرحلة تدريب النموذج، مما ينتج عنه تقييمات مفرطة في التفاؤل تفشل تماماً عند نشر النموذج في بيئات الإنتاج الحية الفعلية.

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

10. مقارنة منهجية بين التعويض بالمتوسط والبدائل الإحصائية الأخرى

10.1 المتوسط الحسابي (Mean) مقابل الوسيط الإحصائي (Median)

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

إذا أظهرت الرسوم البيانية وفحوصات الالتواء (مثل df.skew()) أن معامل الالتواء يتجاوز النطاق الطبيعي ($\pm 1.0$)، يصبح استخدام الوسيط إلزامياً من الناحية الإحصائية. يتم تطبيق التعويض بالوسيط برمجياً في Pandas باستبدال استدعاء دالة المتوسط بدالة الوسيط بكل سلاسة:

# تطبيق التعويض بالوسيط الإحصائي
df_median_imputed = df.copy()
numeric_cols = df_median_imputed.select_dtypes(include=[np.number]).columns
df_median_imputed[numeric_cols] = df_median_imputed[numeric_cols].fillna(df_median_imputed[numeric_cols].median())

يوفر هذا التحول البسيط حماية للنموذج من تأثيرات القيم المتطرفة ويضمن بقاء القيم المعوضة متوافقة مع التوزيع الحقيقي المشاهد للبيانات الميدانية الملتوية.

10.2 التعويض بالمتوسط مقابل أساليب الاستيفاء المتقدمة (KNN و MICE)

ينتمي التعويض بالمتوسط إلى فئة طرائق التعويض أحادي المتغير (Univariate Imputation)، حيث يُعالج كل عمود بمعزل تام عن المتغيرات الأخرى. في المقابل، توفر علوم البيانات الحديثة تقنيات التعويض متعدد المتغيرات (Multivariate Imputation) التي تستغل العلاقات التشابكية بين كافة الأعمدة لتقدير القيمة المفقودة بأعلى دقة ممكنة.

من أبرز هذه التقنيات المتقدمة:

  • تعويض الجار الأقرب (KNN Imputer): يبحث عن السجلات الأكثر شبهاً بالسجل الذي يحتوي على القيمة المفقودة بالاعتماد على حساب المسافات الإقليدية عبر المتغيرات الأخرى المكتملة، ثم يقوم بملء الفجوة بمتوسط قيم تلك المشاهدات المجاورة القريبة فقط بدلاً من متوسط المجتمع بأكمله.
  • التعويض المتعدد عبر المعادلات المتسلسلة (MICE / Iterative Imputer): يعتمد على بناء نماذج انحدار تسلسلية تدور على كل متغير مفقود بوصفه متغيراً تابعاً ومحاولة التنبؤ بقيمته باستخدام بقية المتغيرات كعوامل مستقلة، مع تكرار هذه الدورة الحسابية عدة مرات حتى تقارب التقديرات نحو الاستقرار الرياضي.

تحافظ هذه التقنيات متعددة المتغيرات على تباين البيانات وعلاقات الارتباط البينية، لكنها تتطلب تكلفة حاسوبية أعلى وزمن معالجة أطول بكثير مقارنة بالسرعة اللحظية للتعويض بالمتوسط الحسابي في Pandas.

10.3 مصفوفة اتخاذ القرار لاختيار أسلوب المعالجة الأمثل

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

الخاصية الإحصائية / الشرط الأسلوب الموصى به المبرر المنهجي
بيانات متصلة متماثلة، نسبة الفقد < 5%، الحاجة للسرعة المتوسط الحسابي (Mean Imputation) أبسط الطرق، تكلفة حاسوبية شبه منعدمة، لا يغير المركز
بيانات ملتومة بشدة، وجود قيم شاذة (Outliers) الوسيط الإحصائي (Median Imputation) مقاوم للقيم الشاذة ويحافظ على الموضع المركزي الحقيقي
بيانات فئوية أو نصية أو تصنيفية (Categorical) المنوال الأكثر تكراراً (Mode Imputation) الحل الرياضي الوحيد المناسب للمقاييس الاسمية والرتبية
ارتباطات قوية بين المتغيرات، نسبة الفقد 5% – 20% خوارزمية KNN Imputer يحافظ على التغاير والارتباطات الطبيعية بين السمات
أبحاث أكاديمية استدلالية، متطلبات نمذجة صارمة التعويض المتعدد (MICE / Iterative) يأخذ في الاعتبار عدم اليقين الرياضي المرتبط بالفقد

11. أفضل الممارسات البرمجية وتحسين الأداء الحاسوبي في مجموعات البيانات الضخمة

11.1 إدارة استهلاك الذاكرة وسرعة المعالجة

عند التعامل مع مجموعات البيانات الضخمة (Big Data) التي تتجاوز ملايين الصفوف، تصبح كفاءة إدارة الذاكرة وزمن التنفيذ عاملاً حاسماً في استقرار البنية التحتية البرمجية. يمثل الاعتماد على العمليات المتجهية الصرفة المكتوبة بلغة C داخل محرك Pandas الضمان الأساسي للوصول إلى أقصى سرعة تنفيذ ممكنة.

يجب الامتناع التام والنهائي عن استخدام الحلقات التكرارية اليدوية مثل for index, row in df.iterrows() للمرور على الخلايا واستبدال قيم NaN. إن استخدام مثل هذه الحلقات في بايثون يُسقط ميزات التجهيز المصفوفي ويزيد زمن التنفيذ بمئات بل بآلاف المرات، في حين تنفذ الدالة المتجهية df.fillna(df.mean()) المهمة في أجزاء من الثانية بفضل توجيه التعليمات المباشر عبر الذاكرة العشوائية.

علاوة على ذلك، يُنصح بتجنب الاعتماد الأعمى على inplace=True في مجموعات البيانات الكبيرة، حيث إنه لا يضمن توفير الذاكرة بالضرورة في البنية الحديثة لـ Pandas، بل قد يُنشئ نسخاً خفية في الذاكرة تؤدي إلى تضاعف البصمة التخزينية (Memory Footprint)، ويُستعاض عنه بإعادة الإسناد المباشر والصريح.

11.2 دمج عمليات التعويض داخل Scikit-Learn Pipelines

في بيئات تعلم الآلة المتقدمة والموجهة للإنتاج الصناعي، يُعد دمج عمليات تنظيف البيانات وتعويض الفجوات داخل كائنات التدفق المنظم (Pipeline) المعيار القياسي لضمان قابلية التكرار ومنع تسرب البيانات تماماً. توفر مكتبة Scikit-Learn الفئة SimpleImputer لتنفيذ هذا الإجراء بكفاءة واحترافية:

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Ridge
# بناء خط أنابيب معالجة متكامل
pipeline = Pipeline(steps=[
 ('imputer', SimpleImputer(strategy='mean')), # التعويض بالمتوسط
 ('scaler', StandardScaler()), # المعايرة المعيارية
 ('model', Ridge()) # نموذج التعلم الآلي
])
# تطبيق التدفق على مصفوفات التدريب
# يتم حساب المتوسط على X_train وتطبيقه تلقائياً على X_test دون تسرب
# pipeline.fit(X_train, y_train)
# predictions = pipeline.predict(X_test)

تضمن هذه البنية الموحدة حساب المتوسطات الحسابية حصراً أثناء استدعاء التابع fit() على بيانات التدريب، وتخزين تلك القيم كمعاملات داخلية يتم تطبيقها تلقائياً عند استدعاء predict() أو transform() على البيانات الجديدة، وهو ما يوفر حماية معمارية كاملة لخط المعالجة البرمجي.

11.3 كتابة شيفرات برمجية قابلة للصيانة ومقاومة للأخطاء (Robust Code)

تتطلب كتابة الشيفرات البرمجية الاحترافية تضمين اختبارات تحقق قطعية (Defensive Assertions) والتأكد من التعامل السليم مع الحالات الشاذة والحافة (Edge Cases). ومن أبرز هذه الحالات معالجة الأعمدة التي تكون كافة مدخلاتها فارغة بالكامل (All-NaN columns)، حيث ينتج عن حساب متوسطها قيمة NaN تفشل في ملء العمود.

يوضح النموذج البرمجي التالي كيفية بناء دالة تعويض برمجية مقاومة للأخطاء وقابلة للصيانة والتكامل مع أنظمة المراقبة البرمجية:

def robust_mean_imputation(df, target_columns=None):
 """
 دالة تعويض دفاعية بالمتوسط الحسابي مع فحوصات أمان وتحقق شاملة.
 """
 # 1. التحقق من صحة المدخلات
 if not isinstance(df, pd.DataFrame):
 raise TypeError("المدخل يجب أن يكون من نوع pandas DataFrame.")
 
 df_clean = df.copy()
 
 # 2. تحديد الأعمدة المستهدفة
 if target_columns is None:
 target_columns = df_clean.select_dtypes(include=[np.number]).columns
 else:
 # التأكد من أن الأعمدة المحددة موجودة ورقمية
 for col in target_columns:
 if col not in df_clean.columns:
 raise KeyError(f"العمود {col} غير موجود في إطار البيانات.")
 if not np.issubdtype(df_clean[col].dtype, np.number):
 raise TypeError(f"العمود {col} ليس عموداً رقمياً صالحاً لحساب المتوسط.")
 
 # 3. معالجة الحالات الخاصة وتطبيق التعويض
 for col in target_columns:
 if df_clean[col].isnull().all():
 # حالة خاصة: العمود فارغ كلياً، يتم التعويض بقيمة صفرية افتراضية
 df_clean[col] = df_clean[col].fillna(0.0)
 else:
 col_mean = df_clean[col].mean()
 df_clean[col] = df_clean[col].fillna(col_mean)
 
 # 4. اختبار التحقق الدفاعي (Assertion)
 assert df_clean[target_columns].isnull().sum().sum() == 0, "فشلت المعالجة: لا تزال هناك قيم مفقودة!"
 
 return df_clean
# اختبار الدالة الدفاعية
verified_df = robust_mean_imputation(df, target_columns=['rating', 'points', 'assists'])
print("--- تم التحقق من نجاح المعالجة الدفاعية بنجاح ---")

تُسهم كتابة الشيفرات بهذا المستوى من الانضباط والتوثيق والتحقق الصارم في حماية الأنظمة المؤسسية من التوقفات غير المتوقعة وتضمن بقاء البرمجيات قابلة للصيانة والتطوير لسنوات طويلة.

12. خلاصة الدليل وخارطة طريق عملية للتعامل مع NaN في Pandas

12.1 مراجعة شاملة للطرق الثلاث المنفذة

استعرض هذا الدليل ثلاث طرائق رئيسية ومتدرجة لتطبيق استراتيجية التعويض بالمتوسط الحسابي داخل مكتبة Pandas:

  1. الصيغة الفردية الموضعية: df['col'] = df['col'].fillna(df['col'].mean())، وتُستخدم لمعالجة عمود رقمي محدد بدقة وتحكم كامل في نوع البيانات وعزل تام عن باقي المتغيرات.
  2. صيغة الحزمة المحددة: df[cols] = df[cols].fillna(df[cols].mean())، وتُطبق لمعالجة مجموعة متجانسة من الأعمدة الرقمية بالتوازي وبكفاءة متجهية عالية تضمن عدم المساس بالأعمدة المستثناة.
  3. صيغة التعويض المقيد الآمن: df[num_cols] = df[num_cols].fillna(df[num_cols].mean()) عبر select_dtypes، وتُعد الصيغة الشاملة المثلى لاكتساح كافة المتغيرات الرقمية في الجدول مع حماية الحقول النصية والتصنيفية من أخطاء التنفيذ والانهيار البرمجي.

12.2 قائمة تدقيق نهائية لمهندس وعالم البيانات

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

  • فحص آلية الفقدان: التأكد من أن آلية غياب البيانات تقترب من الفقدان العشوائي التام (MCAR) لتجنب التحيزات الهيكلية في التقديرات.
  • تقييم الالتواء والقيم الشاذة: فحص معامل الالتواء للعمود؛ فإذا كان التوزيع ملتوياً بشدة أو محاطاً بقيم متطرفة، يجب التحول فوراً إلى الوسيط الإحصائي (Median).
  • عزل الأعمدة غير الرقمية: التأكد من استخدام numeric_only=True أو تطبيق select_dtypes لتفادي استثناءات الخطأ من نوع TypeError.
  • حماية خطوط تعلم الآلة: تطبيق التعويض داخل كائنات Pipeline وحساب المتوسط على بيانات التدريب فقط لمنع تسرب البيانات (Data Leakage).
  • توثيق التغيرات الإحصائية: تسجيل وتوثيق أثر التعويض على التباين والانحراف المعياري ومصفوفة الارتباط ضمن التقارير التحليلية المصاحبة للمشروع.

References

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

looti, M. (2026, أغسطس 30). بانداس: كيفية ملء قيم NaN بالمتوسط الحسابي (3 أمثلة). عرب سايكلوجي. https://arabpsychology.com/statistics/pandas-fill-nan-values-mean-examples/
looti, Mohammed. “بانداس: كيفية ملء قيم NaN بالمتوسط الحسابي (3 أمثلة).” عرب سايكلوجي, 30 أغسطس 2026, https://arabpsychology.com/statistics/pandas-fill-nan-values-mean-examples/.
looti, Mohammed. “بانداس: كيفية ملء قيم NaN بالمتوسط الحسابي (3 أمثلة).” عرب سايكلوجي. أغسطس 30, 2026. https://arabpsychology.com/statistics/pandas-fill-nan-values-mean-examples/.