انتقل إلى المحتوى الرئيسي

الوحدة 9 — المراقبة: انحراف البيانات والمفهوم

نموذج التسرّب في الإنتاج منذ أسبوعين. كلّ شيء يعمل تقنيًّا: الخدمة تستجيب، لا أخطاء 500. لكنّ فريق التسويق يشتكي: التوقّعات تبدو خاطئة، الحملات لا تؤتي ثمارها. ما الذي فاتنا؟ الجواب في المراقبة: لا مراقبة، لا مشكلة مرئيّة، ثم فجأة كارثة صامتة.

نوعان مختلفان من الانحراف

نُميّز نوعين لا يجب الخلط بينهما:

  • انحراف البيانات (data drift): توزيع مُدخلات النموذج تغيّر. مثال: 60 بالمائة من المشتركين الجدد في مارس تحت 30 سنة، مقابل 35 بالمائة وقت التدريب. الميزات نفسها، توزيعها مختلف.
  • انحراف المفهوم (concept drift): العلاقة بين المدخلات والهدف تغيّرت. مثال: قبل ستّة أشهر، مشتركو الباقة الرخيصة كانوا الأكثر تسرّبًا. اليوم، منافس أطلق عرضًا يستهدف الباقة الغالية، فأصبح مشتركو الباقة الغالية هم الأكثر تسرّبًا. المتغيّرات نفسها بنفس القيم، لكنّ استنتاج النموذج عليها خاطئ الآن.

انحراف البيانات تُكشَف مبكّرًا وتلقائيًّا لأنّها تحدث في المدخلات، وهذه متوفّرة لحظيًّا. انحراف المفهوم تُكشَف متأخّرًا لأنّها تحتاج ملاحظة الهدف الحقيقي (هل تسرّب المشترك فعلًا؟)، وهذا لا يُعرف قبل أسابيع.

اختبارات إحصائية لكلّ متغيّر

الطريقة القياسية لكشف انحراف البيانات: نقارن توزيع كلّ متغيّر في نافذة حديثة مع مرجع (بيانات التدريب أو نافذة قديمة مستقرّة). أدوات الاختبار الشائعة:

  • Kolmogorov-Smirnov للمتغيّرات المستمرّة: يقارن الدالّتين التراكميّتين ويُنتج قيمة p.
  • Chi-squared للمتغيّرات الاسميّة: يقارن الترددات الفعلية بالمتوقّعة.
  • PSI (Population Stability Index): مقياس عمليّ في الصناعة المصرفيّة. قيمة تحت 0,1 مستقرّ، بين 0,1 و0,25 تنبّه، فوق 0,25 انحراف صريح.
  • Wasserstein distance: مسافة قابلة للتفسير («كم يجب أن أزحف كتلة» من توزيع إلى آخر).

مثال بسيط:

from scipy.stats import ks_2samp

for col in numeric_cols:
stat, p_value = ks_2samp(reference[col], recent[col])
if p_value < 0.01:
alert(f"انحراف على {col}: p = {p_value:.4f}")

القاعدة: لا تختبر إلّا المتغيّرات المهمّة. اختبار مئة متغيّر بمستوى ثقة 99 بالمائة يُنتج تنبيهًا خاطئًا كلّ نهار (نصف عشوائيًّا). ركّز على العشرين متغيّرًا الأكثر أهمّية في النموذج.

انحراف الهدف: مراقبة أعمق

المتغيّرات المُدخَلة ليست كلّ شيء. المتغيّر الأكثر إخبارًا هو الهدف نفسه، حين نستطيع ملاحظته. في التسرّب: نسبة المشتركين الذين تسرّبوا فعلًا في الشهر الماضي.

إن ارتفعت هذه النسبة من 3 بالمائة إلى 8 بالمائة، هذا لا يعني أنّ النموذج «سيّئ»، بل أنّ العالم تغيّر. مؤشّرات النموذج نفسه (AUC، Precision، Recall) على البيانات الحديثة تُقاس بمقارنة توقّعاته بالحقيقة، وتَكشف انحراف المفهوم مباشرة.

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

التنبيه المُفيد ضدّ الضوضاء

خطأ شائع: تنبيهات كثيرة تُصبح ضجيجًا. مبدأ توجيهي: كلّ تنبيه يجب أن يُنشئ عملًا واضحًا لدى مَن يستقبله. تنبيه «PSI الميزة X = 0,12» بلا سياق ولا خطوة تالية سيُتجاهل بعد أسبوع.

نصائح عملية:

  • مستوى ثقة عالٍ قبل الإطلاق: p < 0,001، وليس 0,05. الأخير يعطي ضجيجًا.
  • حجم الحدث المكتشف مهم: انحراف إحصائي مؤكّد لكنّه صغير جدًّا (0,2 بالمائة تغيّر في المتوسّط) ليس دليلًا كافيًا للتنبيه.
  • نافذة مقارنة معقولة: مقارنة يوم واحد بيوم واحد تُنتج تنبيهات موسمية. مقارنة أسبوع مع أسبوع، أو استعمال يوم من الأسبوع نفسه، تُلغي هذا الضجيج.
  • تصعيد متدرّج: إشعار خفيف أوّلًا، ثمّ تصعيد إذا استمرّ الانحراف عبر عدّة نوافذ.

تقارير Evidently

مكتبة Evidently (مفتوحة المصدر) تُقدّم اختبارات مسبَقة الصنع، تقارير HTML قابلة للتشارك، وإرسال المقاييس إلى Prometheus أو Grafana:

from evidently.report import Report
from evidently.metric_preset import DataDriftPreset, TargetDriftPreset

report = Report(metrics=[DataDriftPreset(), TargetDriftPreset()])
report.run(reference_data=reference, current_data=current)
report.save_html("drift_report.html")

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

مقاييس تقنيّة، ليست فقط إحصائيّة

المراقبة لا تقتصر على انحراف البيانات. نُتابع أيضًا:

  • زمن الاستجابة: p50، p95، p99 لكلّ مسار من API. تصاعد p99 قد يُنذر بمشكلة قبل أن تنعكس على المتوسّط.
  • معدّل الخطأ: نسبة استجابات 5xx. أيّ تصاعد يعني خللًا تقنيًّا (نموذج يُلقي استثناء، اعتماد فشل).
  • الاستهلاك: CPU، ذاكرة، عدد استدعاءات في الثانية. القفزات المفاجئة تعني إمّا هجومًا، إمّا استعمالًا جديدًا لم يُخطّط له.
  • معدّل قبول التوصيات: إذا كان تطبيقنا يقترح شيئًا على المستخدم، هل يقبله؟ هبوط في القبول قد يُنذر بمشكلة قبل أيّ انحراف إحصائي.

Prometheus لجمع المقاييس، Grafana للعرض، Alertmanager للتنبيه: هذا التكديس معياريّ.

تنبيه انحراف قد يكون خطأ في السحب

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

في الخلاصة

  • انحراف البيانات (توزيع المدخلات) وانحراف المفهوم (العلاقة بالهدف) نوعان مختلفان يحتاجان أدوات كشف مختلفة.
  • اختبارات إحصائية على المتغيّرات المهمّة (KS، Chi²، PSI) مع نافذة مرجعية ومستوى ثقة صارم، لا على المئة.
  • التنبيه المفيد يقتضي حجم أثر مقبولًا، عتبة صارمة، نافذة مقارنة معقولة، وعملًا واضحًا لمن يستقبله.
  • المقاييس التقنيّة (زمن، خطأ، استهلاك، قبول) لا تقلّ أهمّية عن الإحصائية؛ Prometheus وGrafana وEvidently تركيبة معياريّة.