Data ScienceR ProgrammingStatistical Computing

كيفية استخدام is.na في R (مع أمثلة)

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

تاريخ النشر

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

للتعامل مع هذه التحديات بكفاءة وموثوقية رياضية، توفر بيئة The R Project for Statistical Computing مجموعة متكاملة من الأدوات المدمجة، وتأتي في مقدمتها دالة is.na() التي تمثل حجر الزاوية في عمليات فحص، وتشخيص، وتصفية، واستبدال البيانات غير المكتملة. لا تقتصر وظيفة هذه الدالة على مجرد التحقق البسيط من الفراغات، بل تمتد لتشكل الأساس المنطقي الذي تبنى عليه خطوط معالجة البيانات المعقدة، بدءاً من استكشاف البيانات الاستطلاعي وحتى تجهيز المصفوفات للنماذج التنبؤية المتقدمة عبر حزم الحوسبة الحديثة مثل بيئة Tidyverse.

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

1. مقدمة إلى مفهوم القيم المفقودة (NA) في لغة R وأهمية دالة is.na

1.1 تعريف القيم المفقودة (NA) وطبيعتها الإحصائية في R

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

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

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

1.2 الدور الوظيفي لدالة is.na() في بيئة R البرمجية

تعمل دالة is.na() في لغة R كأداة اختبار منطقية مصممة خصيصاً للتحقق من حالة عدم توفر البيانات في أي كائن برمجي. على عكس الدوال العامة التي قد تفشل عند مواجهة المجهول، تمتلك هذه الدالة القدرة على استجواب كل عنصر من عناصر البنية البيانية على حدة، وتحديد ما إذا كان هذا العنصر يحمل الصفة الرسمية لـ NA أم أنه يحمل قيمة صالحة ومحددة.

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

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

1.3 الفروق الجوهرية بين NA و NULL و NaN و Inf في لغة R

توفر لغة R مجموعة من الرموز الخاصة لتمثيل الحالات الاستثنائية والرياضية المختلفة، ومن الضروري جداً لأي مبرمج التمييز الدقيق بينها. في حين يمثل NA غياب البيانات مع احتفاظ المتغير بمكانه ونوعه البياني، يمثل الرمز NULL الكائن الفارغ أو المعدوم تماماً؛ فهو يعبر عن غياب الكائن نفسه من الذاكرة البرمجية، وبالتالي لا يشغل طولاً (Length = 0) داخل المتجهات ولا يمكن اختباره عبر is.na() بل عبر دالة مخصصة هي is.null().

من ناحية أخرى، يشير الرمز NaN إلى العبارة Not a Number، ويظهر حصرياً كنتيجة للعمليات الحسابية غير المعرفة رياضياً، مثل قسمة الصفر على الصفر أو استخراج الجذر التربيعي لعدد سالب في فضاء الأعداد الحقيقية. والجدير بالملاحظة التقنية الدقيقة أن دالة is.na() تعتبر كل قيمة NaN قيمة مفقودة أيضاً وترجع معها TRUE، نظراً لأن النتيجة غير المعرفة هي بالتبعية قيمة غير متاحة، في حين أن العكس غير صحيح؛ فقيمة NA الحقيقية لا تُعد NaN.

أما الرمزان Inf و -Inf فيمثلان المالانهاية الموجبة والمالانهاية السالبة على التوالي، وينتجان عن العمليات الحسابية التي تتجاوز حدود التمثيل الرقمي للجهاز، مثل قسمة عدد موجب على الصفر. هذه القيم تُعد أرقاماً صالحة حسابياً من المنظور الرياضي في R ولا تُعتبر مفقودة، وبالتالي ترجع دالة is.na() معها القيمة FALSE، بينما يتم اختبارها عبر دالة مخصصة هي is.infinite().

2. البنية النحوية الأساسية (Syntax) وطريقة عمل دالة is.na

2.1 الصيغة العامة لدالة is.na() والمدخلات المدعومة

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

تدعم الدالة تمرير القيم العددية المنفردة من النوع القياسي (Scalars)، والمتجهات بمختلف أنواعها سواء كانت رقمية (Numeric)، أو نصية (Character)، أو منطقية (Logical)، أو عقدية (Complex)، فضلاً عن العوامل الفئوية (Factors). كما تدعم المصفوفات ثنائية ومتعددة الأبعاد (Arrays) وإطارات البيانات الشاملة (Data Frames) والجداول الحديثة (Tibbles) المدعومة من الحزم المتقدمة.

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

2.2 كيفية توليد المخرجات المنطقية (Boolean/Logical Outputs)

تعتمد آلية توليد النتائج في دالة is.na() على التطابق العنصري الشامل؛ فالدالة تقوم بإنشاء خريطة منطقية مطابقة في بنيتها تماماً للكائن الأصلي المدخل. إذا كان العنصر المفحوص يحتوي على القيمة NA (أو ما في حكمها مثل NaN في المتجهات الرقمية)، يتم تعيين القيمة المنطقية TRUE في الموضع المقابل، بينما يتم تعيين القيمة FALSE إذا كان العنصر يحتوي على أي بيانات فعلية وصالحة.

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

تُشكل هذه المصفوفات والمتجهات المنطقية الناتجة الأساس البرمجي لعمليات الفهرسة الشرطية (Logical Indexing/Subsetting) في R. فمن خلال استخدام هذه الأقنعة المنطقية، يستطيع المبرمج تمرير النتيجة المنطقية مباشرة داخل الأقواس المربعة لاستخراج القيم المفقودة، أو عكس الشرط لاستخلاص السجلات الصالحة، أو توجيه مسارات المعالجة الحسابية المعقدة.

2.3 آلية عمل الدالة على الكائنات البرمجية البسيطة والمركبة

عند تطبيق الدالة على المتغيرات المفردة (Scalars)، يتم الاختبار بصورة فورية؛ فإذا كان المتغير الفردي يحمل قيمة مثل 10 أو “Ahmed”، تعيد الدالة FALSE، وإذا كان يحمل القيمة NA، تعيد TRUE. هذا الاختبار الفردي يمثل البنية الأساسية لبناء الجمل الشرطية الثنائية if للتحكم في تدفق تنفيذ البرامج الإحصائية المعقدة.

أما على مستوى المتجهات والمصفوفات، فتتولى الدالة عملية التوجيه المتجهي التلقائي (Vectorization). لا يحتاج المبرمج إلى كتابة حلقات تكرارية يدوية مثل for loops للمرور على عناصر المصفوفة أو المتجه؛ بل تتولى الدالة إجراء الفحص بالتوازي على مستوى الذاكرة منخفضة المستوى، مما يوفر كفاءة حوسبية قصوى ويوفر شفرة برمجية مقتضبة ومقروءة.

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

3. استخدام دالة is.na مع المتجهات الأحادية (Vectors)

3.1 الكشف عن القيم المفقودة في المتجهات الرقمية (Numeric Vectors)

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

لنفترض أن لدينا متجراً رقمياً يحتوي على القيم: 5، 12، مفقود، 8، مفقود، 20. عند تمرير هذا المتجه إلى دالة is.na()، ستقوم لغة R بتحليل العنصر الأول فتجده رقماً فتعيد FALSE، ثم الثاني فتعيد FALSE، ثم تصل إلى العنصر الثالث فتجده NA فتعيد TRUE، وهكذا لبقية العناصر. يتيح هذا التقييم المفصل للمحلل معرفة خريطة الفقدان الرقمي خطوة بخطوة.

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

3.2 التعامل مع المتجهات النصية والرمزية (Character & Factor Vectors)

في المتجهات النصية (Character Vectors)، تتبع دالة is.na() قواعد دقيقة للتمييز بين النص المفقود والنص الفارغ. القيمة NA_character_ هي القيمة المفقودة الحقيقية التي ترجع معها الدالة TRUE، في حين أن النص الفارغ الممثل بالرمز "" أو النص الذي يحتوي على مسافات بيضاء " " يعتبر نصاً حقيقياً وموجوداً من منظور R، وبالتالي ترجع الدالة معه FALSE بالرغم من خلوه من المعنى العملي.

أما عند التعامل مع العوامل الفئوية (Factors)، والتي تستخدم لتمثيل المتغيرات النوعية والتصنيفية ذات المستويات المحددة، فإن القيم المفقودة قد تظهر بطريقتين: إما كقيمة NA حقيقية لا تنتمي لأي مستوى تصنيفي، أو كقيمة تم تحويلها بشكل غير سليم إلى مستوى نصي يحمل الاسم "NA" أو "Missing". تستطيع دالة is.na() اكتشاف القيم المفقودة الحقيقية، بينما تتطلب السلاسل النصية الصريحة معالجة تحويلية مسبقة لدمجها ضمن مستويات الفقدان الرسمية.

من الممارسات البرمجية الضرورية أثناء قراءة الملفات الخارجية استبدال كافة التسميات النصية غير المعيارية، مثل نصوص “N/A” أو “null” أو علامات الاستفهام “?”، وتحويلها إلى قيم NA قياسية معترف بها في R، حتى تتمكن دالة is.na() من التعرف عليها وتصنيفها بدقة تامة ضمن مرحلة تنظيف المتغيرات النصية.

3.3 فحص المتجهات المنطقية والمتجهات الزمنية

تدعم لغة R المتجهات المنطقية ثلاثية الحالات (Three-valued Logic)، حيث يمكن للمتجه المنطقي أن يحتوي على القيم TRUE، و FALSE، بالإضافة إلى NA كحالة عدم يقين. عند تطبيق دالة is.na() على هذا النوع من المتجهات، فإنها تعيد TRUE فقط للعناصر التي تمثل حالة عدم اليقين، بينما تعيد FALSE للقيمتين الصريحتين، مما يسهل تقييم اكتمال نتائج الاختبارات المنطقية المعقدة.

وفيما يخص المتجهات الزمنية وتواريخ التقويم، والتي يتم تمثيلها عادة باستخدام الأصناف القياسية Date و POSIXct أو POSIXlt، تكتسب دالة is.na() أهمية حاسمة. فغياب البيانات الزمنية في تجارب القياس أو السجلات المالية يمثل فجوة زمنية قد تدمر النماذج الحركية ونماذج التنبؤ الزمني إذا لم يتم رصدها وتحديدها بدقة.

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

4. حساب وتعداد القيم المفقودة باستخدام sum() و mean() مع is.na

4.1 حساب العدد الإجمالي للقيم المفقودة عبر sum(is.na(x))

تعتمد لغة R على آلية تحويل الأنواع البرمجية التلقائي (Type Coercion)، حيث يتم تحويل القيم المنطقية ذاتياً إلى قيم عددية عند إدخالها في سياق حسابي؛ فتتحول كل قيمة TRUE إلى الرقم 1، وتتحول كل قيمة FALSE إلى الرقم 0. هذه الميزة الذكية تجعل من التركيبة البرمجية sum(is.na(x)) الطريقة المثالية والأكثر كفاءة لحساب العدد الإجمالي للقيم المفقودة في أي متجه.

عند تنفيذ هذه الشيفرة، تقوم دالة is.na(x) أولاً بتوليد المتجه المنطقي الذي يحتوي على TRUE لكل عنصر مفقود، ثم تأتي دالة sum() لتجمع هذه القيم المنطقية؛ وبما أن TRUE تساوي واحداً و FALSE تساوي صفراً، فإن حاصل الجمع النهائي يمثل بدقة متناهية التكرار الفعلي والعدد الإجمالي للخلايا المفقودة داخل المتجه.

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

4.2 حساب النسبة المئوية للفقدان عبر mean(is.na(x))

بالاستناد إلى المبدأ التحويلي نفسه بين القيم المنطقية والعددية، تأتي التركيبة البرمجية mean(is.na(x)) لتقدم حلاً إحصائياً بارعاً لحساب معدل أو نسبة الفقدان في البيانات. فدالة المتوسط الحسابي mean() تقوم بجمع القيم وقسمتها على العدد الكلي للعناصر؛ وبما أن المجموع يمثل عدد الآحاد (أي عدد القيم المفقودة)، فإن الناتج النهائي يكون النسبة العشرية للقيم المفقودة بالنسبة للحجم الكلي للعينة.

لتسهيل قراءة النتائج وتضمينها في التقارير الإحصائية ومسودات النشر العلمي، يمكن تحويل هذا المعدل إلى نسبة مئوية مباشرة عبر ضرب الناتج في مائة، بالصيغة: mean(is.na(x)) * 100. فإذا كانت النتيجة 15.5، فهذا يعني فوراً أن 15.5% من بيانات هذا المتجه مفقودة وتتطلب اتخاذ قرارات معالجة منهجية.

يساعد تقييم النسبة المئوية للفقدان في تصنيف المتغيرات وفق المعايير الإحصائية المعتمدة دولياً؛ حيث تشير أدبيات القياس المتقدمة إلى أن نسب الفقدان الأقل من 5% غالباً ما تكون غير مؤثرة إحصائياً، بينما تتطلب النسب التي تتراوح بين 5% و 20% تقنيات تعويض متقدمة، في حين تمثل النسب التي تتجاوز ذلك تهديداً حقيقياً لصلاحية الاستدلال الإحصائي.

4.3 التحقق من الوجود والشمولية باستخدام any() و all()

في بناء خطوط التحقق من جودة البيانات (Data Validation Pipelines)، يحتاج المبرمج في كثير من الأحيان إلى اختبارات منطقية سريعة تعيد إجابة حاسمة بنعم أو لا، دون الحاجة إلى تعداد تفصيلي. هنا تبرز أهمية دمج دالة is.na() مع الدالتين المنطقيتين any() و all().

تستخدم التركيبة any(is.na(x)) للتحقق مما إذا كان المتجه يحتوي على قيمة مفقودة واحدة على الأقل. تعيد هذه الصيغة القيمة TRUE في حال وجود أي فقدان، و FALSE إذا كان المتجه نقياً ومكتملاً بنسبة 100%. تُعد هذه الصيغة مثالية للاستخدام كشرط أولي داخل الجمل الشرطية لتفادي تشغيل دوال التنظيف الثقيلة عندما لا تكون هناك حاجة فعلية لها.

على الجانب الآخر، تُستخدم التركيبة all(!is.na(x)) للتأكد القاطع من الاكتمال الشامل لخلو المتجه من أي قيمة مفقودة. يتم استخدام هذه الدوال بكثافة في كتابة اختبارات الوحدة البرمجية (Unit Tests) للبيانات وفحوصات التأكيد الرياضي (Assertions)، مما يضمن عدم انتقال أي بيانات مشوهة إلى مراحل النمذجة الإحصائية النهائية.

5. تحديد مواقع ومؤشرات القيم المفقودة باستخدام which(is.na())

5.1 استخراج الفهارس الرقمية (Indices) للقيم المفقودة في المتجهات

في كثير من المهام التحليلية، لا يكتفي الباحث بمعرفة عدد القيم المفقودة فقط، بل يحتاج بدقة إلى معرفة المواقع المكانية والترتيبية لتلك القيم داخل المتجه. يتم تحقيق ذلك بكفاءة عالية عبر دمج دالة استخراج المواقع المنطقية مع دالة فحص الفقدان في الصيغة البرمجية which(is.na(x)).

تقوم دالة which() بفحص المتجه المنطقي الناتج عن is.na(x)، ثم تقوم باستخراج الأرقام التسلسلية أو الفهارس المكانية (Indices) لجميع العناصر التي حققت الشرط وكانت قيمتها TRUE. على سبيل المثال، إذا كانت القيمتان الثالثة والسابعة مفقودتين في متجه يحتوي على عشرة عناصر، فإن ناتج الدالة سيكون المتجه الرقمي c(3, 7).

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

5.2 تحديد المواقع في المصفوفات ثنائية الأبعاد باستخدام arr.ind

عند الانتقال من المتجهات الأحادية إلى المصفوفات ثنائية الأبعاد (Matrices)، يصبح تحديد موقع القيمة المفقودة بحاجة إلى إحداثيين: رقم الصف ورقم العمود. توفر لغة R خياراً متقدماً داخل دالة which() من خلال المعامل الإضافي arr.ind = TRUE.

تُكتب الشيفرة البرمجية على النحو التالي: which(is.na(my_matrix), arr.ind = TRUE). عند تنفيذ هذا الأمر، تعيد لغة R مصفوفة رقمية تتألف من عمودين يحملان الاسمين row و col؛ حيث يوضح كل صف في المصفوفة الناتجة إحداثيات موقع الفقدان بدقة، مبيناً رقم الصف ورقم العمود الذي توجد فيه القيمة المفقودة داخل المصفوفة الأصلية.

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

5.3 استخراج التسميات والمؤشرات الاسمية المرتبطة بمواقع NA

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

يمكن تحقيق ذلك بسهولة من خلال دمج استعلام الأسماء مع الفهرسة الشرطية المباشرة عبر الصيغة البرمجية: names(x)[is.na(x)] أو باستخدام الفهارس الرقمية المستخرجة عبر names(x)[which(is.na(x))]. ينتج عن هذه العملية متجه نصي يحتوي حصرياً على أسماء الحالات أو العينات التي توقفت عن الاستجابة أو فقدت قياساتها أثناء التجربة.

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

6. تطبيق دالة is.na على إطارات البيانات (Data Frames)

6.1 الكشف عن القيم المفقودة على مستوى إطار البيانات الإجمالي

يمثل إطار البيانات (Data Frame) الهيكل الأكثر شيوعاً واستخداماً في تحليل البيانات داخل بيئة R، حيث يجمع بين أعمدة متعددة قد تختلف في أنواعها البيانية بين أرقام ونصوص وتواريخ. عند تمرير إطار البيانات كاملاً إلى دالة is.na(df)، فإن الدالة تتعامل مع كل عمود على حدة وتقوم بإرجاع مصفوفة منطقية تحتفظ بنفس عدد الصفوف والأعمدة لإطار البيانات الأصلي.

لحساب الحجم الإجمالي للفقدان عبر كامل قاعدة البيانات دون النظر إلى مواقعها التفصيلية، يمكن دمج الدالة في الصيغة الكلية: sum(is.na(df)). تعطي هذه النتيجة رقماً إجمالياً واحداً يوضح عدد الخلايا الفارغة في الجدول بأكمله، مما يمنح المحلل نظرة سريعة وانطباعاً أولياً عن النظافة العامة لمجموعة البيانات المدروسة.

كما يمكن دراسة النمط العام لتوزيع الفقدان من خلال حساب النسبة الإجمالية للخلايا المفقودة عبر قسمة المجموع الكلي على حاصل ضرب عدد الصفوف في عدد الأعمدة: sum(is.na(df)) / (nrow(df) * ncol(df)). يعكس هذا المؤشر الشامل مدى تماسك قاعدة البيانات وجاهزيتها للتحليلات الإحصائية المتقدمة والنمذجة الرياضية.

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

في التحليل العملي، نادراً ما تتوزع القيم المفقودة بالتساوي بين المتغيرات، بل يتركز الفقدان عادة في متغيرات معينة دون غيرها نتيجة لطبيعة الأسئلة الحساسة في الاستبيانات أو صعوبة القياس الفني لبعض المتغيرات. للتحقق من عمود فردي ومحدد، يمكن استخدام معامل الوصول إلى الأعمدة بالصيغة: is.na(df$variable_name)، أو حساب عدد القيم المفقودة فيه عبر sum(is.na(df$variable_name)).

لفحص كافة المتغيرات دفعة واحدة وبكفاءة حسابية فائقة، توفر R الدالة المدمجة الموجهة colSums()، والتي يمكن دمجها مباشرة مع دالة الفحص في الصيغة القياسية الشهيرة: colSums(is.na(df)). ينتج عن هذا السطر البرمجي المقتضب متجه مسمى يحتوي على اسم كل متغير في إطار البيانات مقابلاً للعدد الدقيق للقيم المفقودة الموجودة داخله.

وبالمثل، يمكن حساب النسبة المئوية للفقدان لكل متغير على حدة عبر استخدام دالة المتوسطات العمودية: colMeans(is.na(df)) * 100. يُعد هذا الإجراء خطوة تشخيصية جوهرية في مراجعة البيانات؛ حيث يتيح للمحلل ترتيب الأعمدة تنازلياً حسب نسبة الفقدان لاتخاذ قرارات حاسمة بشأن الإبقاء على المتغيرات أو حذفها وفق المعايير البحثية المقررة.

6.3 فحص الصفوف والسجلات وحساب الفقدان لكل حالة

مثلما تتطلب دراسة المتغيرات فحص الأعمدة، تتطلب دراسة العينات والمبحوثين فحص الصفوف والسجلات الفردية لتحديد الحالات التي تعاني من نقص حاد في الإجابات. توفر لغة R الدالة المدمجة rowSums() لتطبيق هذه المهمة عبر الصيغة البرمجية: rowSums(is.na(df)).

تُرجع هذه الدالة متجراً رقمياً يحتوي على عدد الحقول المفقودة لكل صف أو حالة في إطار البيانات. يتيح هذا للمحلل تحديد المبحوثين غير الجادين الذين تركوا أجزاء كبيرة من الاستبيان فارغة؛ على سبيل المثال، يمكن بسهولة استخراج الصفوف التي تحتوي على أكثر من 5 قيم مفقودة عبر الشرط المنطقي: which(rowSums(is.na(df)) > 5).

من أفضل الممارسات المنهجية في مرحلة المعالجة إنشاء عمود جديد داخل إطار البيانات يسجل عدد القيم المفقودة لكل صف، مثل: df$missing_count <- rowSums(is.na(df)). يتيح هذا المتغير الجديد استخدام معايير استبعاد مرنة وموثقة أثناء تصفية العينة دون فقدان التتبع الإحصائي لخصائص السجلات المستبعدة.

7. تصفية واستبعاد القيم المفقودة (Subsetting and Filtering)

7.1 استبعاد القيم المفقودة من المتجهات باستخدام المعامل المنطقي !

يمثل معامل النفي المنطقي (Logical NOT) الممثل بالرمز ! الأداة الأساسية لعكس المخرجات المنطقية في لغة R. عند تطبيق هذا المعامل على دالة الفقدان بالصيغة !is.na(x)، تتحول كل قيمة TRUE (التي كانت تدل على الفقدان) إلى FALSE، وتتحول كل قيمة FALSE (التي تدل على وجود بيانات حقيقية) إلى TRUE.

لإنشاء متجه نقي ومصفى بالكامل وخالٍ من أي قيمة مفقودة، يتم استخدام هذا القناع المنطقي المنفي داخل الأقواس المربعة للفهرسة المباشرة على النحو التالي: clean_x <- x[!is.na(x)]. تقوم R بفحص المتجه واستخراج العناصر الصالحة فقط، مستبعدة كافة الفجوات دون ترك أي أثر مكاني لها في المتجه الجديد.

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

7.2 تصفية السجلات الخالية من NA في إطارات البيانات

عند الرغبة في تصفية إطار البيانات بالكامل بناءً على اكتمال متغير رئيسي ومحدد (مثل المتغير التابع في النماذج الإحصائية)، يتم استخدام المعامل المنفي مع تطبيق قواعد الفهرسة الثنائية (الصف، العمود) داخل الأقواس المربعة بالصيغة: clean_df <- df[!is.na(df$target_variable), ].

توضح الفاصلة الموجودة داخل الأقواس المربعة أن التصفية الشرطية تنطبق حصرياً على الصفوف، مع الإبقاء على كافة الأعمدة دون نقصان. كما تتيح لغة R دمج شروط متعددة تجمع بين نفي is.na() لعدة متغيرات باستخدام المعامل المنطقي & (AND) لضمان اكتمال حقول متعددة في آن واحد، مثل: clean_df <- df[!is.na(df$var1) & !is.na(df$var2), ].

من الضروري عند إجراء هذه التصفية الانتباه إلى ترقيم الصفوف المتبقية؛ حيث تحتفظ R تلقائياً بأرقام الصفوف الأصلية. ولإعادة تعيين أرقام الصفوف بشكل تسلسلي متناسق بعد استبعاد السجلات التالفة، يوصى برمجياً بتنفيذ السطر: rownames(clean_df) <- NULL لضمان جمالية واتساق الكائن المخرج.

7.3 مقارنة !is.na() بالدوال المدمجة complete.cases() و na.omit()

توفر بيئة R دوال مدمجة متقدمة تسهل تصفية السجلات المكتملة دون الحاجة إلى كتابة شروط يدوية طويلة لكل عمود. الدالة الأولى هي complete.cases()، والتي تأخذ إطار بيانات أو مصفوفة وتعيد متجراً منطقياً يكون TRUE فقط للصفوف التي لا تحتوي على أي قيمة مفقودة في أي عمود من أعمدتها، وتُستخدم بالصيغة: df[complete.cases(df), ].

أما الدالة الثانية فهي na.omit()، وهي دالة تنفيذية تقوم تلقائياً باستبعاد كافة الصفوف غير المكتملة بضربة واحدة: clean_df <- na.omit(df). والفرق التقني المهم أن na.omit() تقوم بإرفاق سمة وصفية (Attribute) إضافية داخل الكائن المخرج تسمى na.action، تسجل أرقام الصفوف التي تم حذفها، وهو أمر مفيد لتوثيق إجراءات المعالجة لاحقاً.

على الرغم من سهولة na.omit() و complete.cases()، إلا أن استخدام !is.na() اليدوي يظل الخيار المفضل والموصى به عندما يرغب المحلل في تصفية البيانات بناءً على أعمدة محددة فقط، متفادياً بذلك الاستبعاد الجائر وغير المبرر لصفوف قد تحتوي على قيم مفقودة في متغيرات جانبية غير ذات صلة بالتحليل المستهدف، وهو ما يتماشى مع إرشادات المنظمات البحثية مثل American Psychological Association في الحفاظ على أحجام العينات.

8. استبدال وتعديل القيم المفقودة باستخدام دالة is.na

8.1 تعويض القيم المفقودة بقيم عددية أو نصية ثابتة

لا تقتصر دالة is.na() على الفحص والاستبعاد فقط، بل تلعب دوراً محورياً في عمليات التعديل والاستبدال المباشر (Direct Imputation). يعتمد هذا الإجراء على استخدام الدالة في الجانب الأيسر من معامل التعيين (Assignment Operator <-) لتحديد مواضع الفقدان وإسناد قيم جديدة لها بشكل فوري.

في المتجهات الرقمية، يشيع في بعض التطبيقات المحاسبية استبدال القيم المفقودة بالرقم صفر، ويتم تنفيذ ذلك عبر الشيفرة البسيطة والأنيقة: x[is.na(x)] <- 0. تقوم R باكتشاف كافة الفهارس التي تحمل TRUE وتستبدل محتواها فوراً بالقيمة الصفرية المحددة، مع الحفاظ الكامل على بقية القيم الأصلية دون أي تعديل.

أما في المتغيرات النصية والتصنيفية، فيمكن استبدال الفجوات بنصوص دالة مثل “غير محدد” أو “Unknown” عبر الصيغة: df$status[is.na(df$status)] <- "غير محدد". يجب هنا مراعاة الحذر البرمجي عند التعامل مع المتجهات الرقمية لتجنب تمرير نصوص إليها، منعاً لحدوث تحويل قسري غير مقصود (Coercion) يحول كامل المتجه الرقمي إلى متجه نصي تالف.

8.2 التعويض بالمقاييس الإحصائية المركزية (Mean/Median Imputation)

يُعد التعويض بالمقاييس الإحصائية المركزية من أكثر الاستراتيجيات التقليدية شيوعاً في التعامل مع البيانات الرقمية المفقودة. عند استخدام المتوسط الحسابي كبديل لـ NA، يجب أولاً حساب المتوسط مع تفعيل خيار تجاهل الفقدان na.rm = TRUE، ثم إسناد هذه القيمة المحسوبة إلى مواضع الفقدان المحددة بواسطة is.na().

تتم هذه العملية بالصيغة البرمجية التالية: x[is.na(x)] <- mean(x, na.rm = TRUE). في حالة المتغيرات التي تعاني من التواء إحصائي شديد (Skewed Distributions) أو وجود قيم شاذة متطرفة (Outliers)، يُفضل استبدال المتوسط الحسابي بالوسيط الإحصائي عبر دالة median(): x[is.na(x)] <- median(x, na.rm = TRUE) لضمان عدم تأثر البديل بالانحرافات المتطرفة.

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

8.3 التعويض المشروط للقيم المفقودة بناءً على متغيرات أخرى

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

يتم تنفيذ التعويض المشروط من خلال دمج شروط منطقية مزدوجة داخل الفهرسة؛ على سبيل المثال: df$income[is.na(df$income) & df$education == "PhD"] <- mean(df$income[df$education == "PhD"], na.rm = TRUE). تضمن هذه الصيغة توجيه عملية الاستبدال حصرياً للمواضع التي تجتمع فيها حالة الفقدان مع شرط المؤهل التعليمي المحدد.

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

9. دمج دالة is.na مع حزمة dplyr ومجموعة Tidyverse

9.1 تصفية البيانات باستخدام filter() مع !is.na()

أحدثت مجموعة حزم Tidyverse، وبخاصة حزمة dplyr، ثورة حقيقية في طرق كتابة ومعالجة البيانات في R عبر تقديم مفهوم سلاسل الأنابيب (Pipe Operators سواء التقليدي %>% أو الأصلي |>). يتكامل استخدام دالة is.na() بسلاسة فائقة داخل دالة التصفية الشهيرة filter().

لاستبعاد الصفوف التي تحتوي على قيم مفقودة في متغير معين داخل سلسلة معالجة متصلة، تُكتب الشيفرة بأسلوب ناصع الوضوح: df %>% filter(!is.na(variable_name)). تتيح هذه الصياغة الأنيقة دمج عملية تصفية الفقدان ضمن خط إنتاج برمجي يشمل الترتيب، واختيار الأعمدة، وحساب المتغيرات الجديدة دون الحاجة لإنشاء كائنات وسيطة في الذاكرة.

كما توفر حزمة dplyr دمج الدالة مع محددات الأعمدة الشاملة مثل across() لتصفية السجلات بناءً على خلو مجموعة محددة من الأعمدة من الفقدان في سطر واحد، مثل: df %>% filter(if_all(c(var1, var2, var3), ~ !is.na(.)))، مما يوفر مرونة برمجية فائقة تزيد من كفاءة ونظافة الشيفرة البرمجية في المشاريع المعقدة.

9.2 تعديل واستبدال NA داخل mutate() باستخدام if_else() و case_when()

عند الحاجة إلى تعديل القيم المفقودة أو إعادة ترميزها داخل إطار عمل dplyr، تُستخدم دالة mutate() بالاشتراك مع الدوال الشرطية المتجهة مثل if_else() و case_when() بالتناغم التام مع دالة is.na().

تتيح دالة if_else() صياغة استبدال مباشر عالي الكفاءة والصرامة في فحص الأنواع، كأن نكتب: df %>% mutate(score_imputed = if_else(is.na(score), 0, score)). وإذا كانت شروط الاستبدال متعددة ومعقدة، تبرز دالة case_when() بوصفها الأداة المثالية لكتابة شروط متسلسلة تعتمد على is.na() في تقرير البدائل المناسبة لكل حالة سياقية على حدة.

بالإضافة إلى ذلك، توفر حزمة tidyr الشقيقة دالة مخصصة هي replace_na()، والتي تتيح تمرير قائمة بالقواعد البديلة لكل عمود. ومع ذلك، يظل استخدام is.na() داخل case_when() الخيار الأقوى والأكثر مرونة عندما تتداخل شروط التعويض مع متغيرات منطقية ورياضية أخرى داخل إطار البيانات.

9.3 حساب ملخصات الفقدان التجميعية عبر summarise() و group_by()

يُعد فهم كيفية توزيع القيم المفقودة عبر المجموعات والتصنيفات المختلفة أحد أهم أركان التحليل الإحصائي الاستكشافي المتقدم. من خلال الجمع بين دالتي group_by() و summarise() مع sum(is.na()) و mean(is.na())، يمكن توليد تقارير تجميعية فائقة الدقة.

على سبيل المثال، يمكن للمحلل حساب عدد ونسبة القيم المفقودة لمتغير الاستجابة داخل كل فرع من فروع الدراسة أو فئة عمرية عبر الشيفرة: df %>% group_by(region) %>% summarise(missing_count = sum(is.na(sales)), missing_pct = mean(is.na(sales)) * 100). ينتج عن هذا الاستعلام جدول تلخيصي يوضح بجلاء أي الفئات الجغرافية تعاني من ضعف توثيق البيانات.

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

10. التعامل مع الحالات الخاصة والمتقدمة المرتبطة بـ is.na

10.1 الفروق التقنية الدقيقة بين is.na() و is.nan() وكيفية عزلهما

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

لتحديد واكتشاف قيم NA الحقيقية فقط واستبعاد قيم NaN من المخرجات، يتم استخدام التركيبة المنطقية الاحترافية: is.na(x) & !is.nan(x). في هذه الحالة، تفحص الدالة المتجه؛ فإذا كان العنصر NaN، فإن is.nan(x) ستكون TRUE وبالتالي نفيها سيكون FALSE، مما يؤدي إلى إبطال شرط & وإرجاع FALSE للعمليات الرياضية غير المعرفة، وحصر النتيجة TRUE في قيم الفقدان الحقيقي فقط.

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

10.2 التعامل مع الكائنات المعقدة والقوائم المتداخلة (Nested Lists)

في بيئات العمل المعقدة، مثل استهلاك واجهات برمجة التطبيقات (APIs) أو استيراد ملفات JSON، غالباً ما يتم تخزين البيانات في شكل قوائم شجرية متداخلة (Nested Lists) أو أعمدة قائمة (List-columns) داخل إطارات البيانات. عند تطبيق is.na() مباشرة على هذه القوائم، قد لا تنفذ الدالة إلى المستويات الداخلية العميقة بالشكل المطلوب.

للتعامل مع هذا التعقيد، يتم اللجوء إلى عائلة دوال التطبيق الوظيفي مثل lapply() و sapply() أو دالة map() من حزمة purrr. تتيح هذه الأدوات تطبيق دالة is.na() تكرارياً على كل عنصر فرعي داخل القائمة المتداخلة، مثل: lapply(my_nested_list, function(sub_element) sum(is.na(sub_element))).

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

10.3 القيم المفقودة في بيانات السلاسل الزمنية (Time Series)

تمتلك بيانات السلاسل الزمنية (مثل كائنات ts و xts و zoo) خصوصية فريدة؛ فالفقدان فيها لا يقتصر على مجرد قيمة ناقصة، بل يمثل انقطاعاً في التواتر والتسلسل الزمني المنتظم للظاهرة المدروسة. ويؤدي حذف القيم المفقودة في السلاسل الزمنية باستخدام na.omit() إلى تدمير البنية الزمنية وخلخلة المسافات الفاصلة بين الفترات المتتابعة.

هنا تبرز دالة is.na() كأداة تشخيص أساسية لتحديد الفجوات دون حذفها، مما يمهد الطريق لتطبيق تقنيات الاستيفاء الرياضي (Interpolation) أو الإسقاط بالقيم السابقة واللاحقة (Last Observation Carried Forward – LOCF). عبر الصيغة which(is.na(ts_data))، يتم تحديد الإحداثيات الزمنية الدقيقة التي تحتاج إلى معالجة استيفائية.

بعد تحديد الفجوات، يتم استخدام خوارزميات الاستيفاء الخطي أو التكعيبي (Spline Interpolation) لملء الفراغات المحددة بواسطة is.na()، مما يحافظ على التباعد الزمني المنتظم للسلسلة ويسمح بنمذجة التراجع الذاتي والمتوسطات المتحركة (ARIMA) بكفاءة إحصائية متناهية ودون أي تشويه هيكلي للبيانات.

11. الأخطاء الشائعة وأفضل الممارسات البرمجية عند استخدام is.na

11.1 مخاطر استخدام معامل المساواة التقليدي (x == NA)

يقع العديد من المبتدئين في لغة R في خطأ برمجي شائع وخطير للغاية، وهو محاولة الكشف عن القيم المفقودة باستخدام معامل المساواة المنطقي التقليدي المزدوج: x == NA. هذا الاستخدام خاطئ تماماً من الناحية البرمجية والرياضية في لغة R، ولا يعطي أبداً النتيجة التي يتوقعها المبرمج.

السبب المنطقي وراء هذا السلوك يعود إلى مبدأ انتشار عدم اليقين؛ فعندما تسأل الحاسوب: “هل هذه القيمة المجهولة تساوي قيمة مجهولة أخرى؟”، تكون الإجابة المنطقية الوحيدة الممكنة هي: “لا أعلم” (أي NA). وبالتالي، فإن التعبير x == NA سيعيد متجراً مليئاً بقيم NA بالكامل لجميع العناصر الصالحة والمفقودة على حد سواء، ولن يعيد أبداً المتجه المنطقي الصريح TRUE/FALSE.

تؤدي هذه المشكلة إلى أخطاء برمجية خفية وصعبة التتبع عند استخدام هذا التعبير داخل الجمل الشرطية if أو التصفية؛ حيث تؤدي مواجهة NA داخل الشروط إلى توقف التنفيذ البرمجي أو استبعاد كافة البيانات بشكل صامت. لذا، يجب ترسيخ القاعدة البرمجية الصارمة: يُمنع استخدام == NA نهائياً، ويجب الاعتماد الحصري والمطلق على دالة is.na() لإجراء أي فحص أو مقارنة للفقدان.

11.2 إدارة الأداء والكفاءة الحاسوبية مع مجموعات البيانات الضخمة (Big Data)

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

على الرغم من أن دالة is.na() محسنة للغاية ومكتوبة بلغة منخفضة المستوى، فإن تطبيقها لإنشاء نسخ منطقية متعددة من إطارات البيانات الضخمة قد يضاعف استهلاك الذاكرة. في هذه البيئات الضخمة، يُنصح بالاعتماد على حزمة data.table فائقة الأداء، والتي توفر آليات فحص واستبدال داخلي مباشر في الذاكرة (Update by Reference) عبر المعامل := دون الحاجة إلى إنشاء نسخ مكررة من البيانات في الذاكرة المؤقتة.

كما يُنصح باجتناب الحلقات التكرارية اليدوية نهائياً عند فحص واستبدال NA، والاعتماد المطلق على المتجهات المنطقية والدوال المجمعة مثل colSums(is.na())، مع الحرص على التخلص من الكائنات المؤقتة عبر استدعاء دالة تنظيف الذاكرة gc() عند الانتهاء من فحص وتنظيف الملفات الضخمة.

11.3 توثيق آليات معالجة NA لضمان إمكانية إعادة الإنتاج العلمي (Reproducibility)

تُمثل قابلية إعادة الإنتاج العلمي والشفافية المنهجية حجر الزاوية في الأبحاث الأكاديمية والتحليلات المؤسسية الموثوقة. لا يكفي مجرد تنظيف البيانات والتخلص من NA، بل يجب توثيق كل خطوة إجرائية توثيقاً برمجياً دقيقاً ومفصلاً داخل الشيفرة المصدرية.

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

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

12. أمثلة تطبيقية وحالات عملية متكاملة باستخدام دالة is.na

12.1 حالة عملية 1: تنظيف ومعالجة استبيان نفسي يحتوي على استجابات ناقصة

في دراسة نفسية وسلوكية واقعية، تم تطبيق مقياس ليكرت خماسي الدرجات (من 1 إلى 5) على عينة تتألف من 500 مبحوث عبر 20 فقرة استبيانية. عند استيراد مصفوفة الاستجابات، تبين وجود تفاوت كبير في معدلات إكمال الأسئلة بين الأفراد، مما استدعى خطة تنظيف محكمة تعتمد على دالة is.na() في بيئة R.

تمثلت الخطوة الأولى في تقييم جودة استجابة كل مبحوث على حدة؛ حيث تم حساب معدل الفقدان الفردي لكل صف عبر المعادلة: rowMeans(is.na(survey_data)). وبناءً على البروتوكول المنهجي المعتمد، تم تحديد عتبة استبعاد صارمة قدرها 20%؛ فتم عزل واستبعاد جميع المبحوثين الذين تركوا أكثر من 4 أسئلة دون إجابة عبر الفهرسة الشرطية: valid_survey <- survey_data[rowMeans(is.na(survey_data)) <= 0.20, ]، مما أدى إلى الاحتفاظ بالعينة الجادة فقط.

وفي الخطوة الثانية، تم التعامل مع الاستجابات الفردية القليلة المتبقية في العينة المصفاة؛ حيث تم حساب وسيط الإجابات لكل فقرة استبيانية مع تفعيل na.rm = TRUE، ثم تم تعويض الخلايا المفقودة في كل عمود بدقة باستخدام is.na(): valid_survey$Q1[is.na(valid_survey$Q1)] <- median(valid_survey$Q1, na.rm = TRUE) وتكرار ذلك عبر بقية الفقرات، مما نتج عنه مصفوفة بيانات نفسية مكتملة، نقية، وخالية تماماً من التحيزات الحسابية وجاهزة للتحليل العاملي وحساب معامل ألفا كرونباخ للثبات.

12.2 حالة عملية 2: تجهيز مصفوفة تجريبية لنماذج الانحدار الخطي

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

بدأت المعالجة بعزل الحالات التي تعاني من فقدان المتغير التابع (سعر البيع)، حيث تحظر الأدبيات الإحصائية تعويض المتغير التابع اصطناعياً في النماذج التنبؤية لتجنب إدخال ضوضاء في دالة الهدف. تم تطبيق تصفية حاسمة بالصيغة: housing_clean <- housing_raw[!is.na(housing_raw$price), ]، لضمان أن كل صف في التحليل يحتوي على سعر بيع فعلي وحقيقي مسجل في السجلات الرسمية.

بعد ذلك، تم فحص المتغيرات المستقلة المتبقية؛ فوجد أن متغير “عمر البناء” يحتوي على 3% من القيم المفقودة، فتم استخدام is.na() لتعويضها بمتوسط عمر المباني في الحي الجغرافي نفسه. وعند بناء نموذج الانحدار الخطي عبر دالة lm(price ~ area + rooms + age, data = housing_clean)، عمل النموذج بسلاسة تامة دون فقدان أي درجات حرية إضافية بصورة غير متحكم بها، وجاءت تقديرات المعالم الإحصائية مستقرة وذات دلالة معنوية عالية مقارنة بتشغيل النموذج على البيانات الخام غير المعالجة.

12.3 حالة عملية 3: بناء دالة مخصصة لإنشاء تقرير تشخيصي شامل لجودة البيانات

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

تعتمد الدالة المخصصة في جوهرها الحسابي على تشغيل متوازٍ لدالة is.na() عبر أعمدة الكائن؛ حيث تقوم باحتساب التكرار الفعلي للفقدان عبر colSums(is.na(data))، وحساب النسبة المئوية الدقيقة عبر colMeans(is.na(data)) * 100، ثم استخراج النوع البياني لكل عمود عبر دالة sapply(data, class)، وتجميع هذه المؤشرات داخل إطار بيانات جديد ومرتب تنازلياً حسب المتغيرات الأكثر تضرراً.

تتضمن الدالة أيضاً خاصية فرز تحذيرية؛ حيث تضع علامة تنبيهية حمراء “CRITICAL” بجانب أي متغير تتجاوز نسبة الفقدان فيه حاجز الـ 40% لتنبيه المحلل إلى ضرورة الحذر أو الاستبعاد. يمثل هذا التطبيق البرمجي دليلاً ساطعاً على كيفية تحويل دالة بسيطة مثل is.na() إلى نواة برمجية صلبة لأدوات تدقيق وحوكمة البيانات في المنظومات الإحصائية المؤسسية الحديثة.

خاتمة

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

لقد استعرضنا عبر هذا الدليل الشامل الأبعاد النظرية والرياضية للقيم المفقودة، وكيفية توظيف is.na() في استخراج الإحصاءات التلخيصية، وتحديد الفهارس والمواقع المكانية، وتصفية السجلات واستبعاد التالف منها، فضلاً عن تقنيات الاستبدال والتعويض الإحصائي المباشر والمشروط. كما أبرزنا التكامل البرمجي الرفيع بين الدالة وحزم الحوسبة الحديثة مثل dplyr و tidyverse، وكيفية التعامل مع الحالات الهندسية الدقيقة مثل التفريق بين NA و NaN ومعالجة السلاسل الزمنية والقوائم المعقدة.

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

References

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

looti, M. (2026, سبتمبر 1). كيفية استخدام is.na في R (مع أمثلة). عرب سايكلوجي. https://arabpsychology.com/statistics/how-to-use-is-na-in-r-with-examples/
looti, Mohammed. “كيفية استخدام is.na في R (مع أمثلة).” عرب سايكلوجي, 1 سبتمبر 2026, https://arabpsychology.com/statistics/how-to-use-is-na-in-r-with-examples/.
looti, Mohammed. “كيفية استخدام is.na في R (مع أمثلة).” عرب سايكلوجي. سبتمبر 1, 2026. https://arabpsychology.com/statistics/how-to-use-is-na-in-r-with-examples/.