تقييم النماذج: مصفوفة الالتباس و Precision و Recall
في الدرس السابق حصل نموذج الزهور على دقة 100%، وحذّرناك: الدقة وحدها قد تكون مضللة. تخيّل نموذجاً يكشف مرضاً خطيراً، دقته 97%. يبدو ممتازاً، أليس كذلك؟ ماذا لو عرفت أنه لم يكتشف أي مريض؟ في هذا الدرس ستتعلم كيف تقيّم النموذج تقييماً صادقاً: أين يخطئ، وأي نوع من الخطأ، وهل يمكن الوثوق برقم واحد.
بيانات أقرب للواقع
Section titled “بيانات أقرب للواقع”سنعمل على بيانات حقيقية مرفقة مع scikit-learn: قياسات مأخوذة من عينات أورام، والمطلوب تصنيف الورم: خبيث (malignant) أم حميد (benign).
from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()X = data.datay = data.target
print(X.shape)print(data.target_names)print((y == 0).sum(), (y == 1).sum())(569, 30)['malignant' 'benign']212 357569 عينة، لكل منها 30 ميزة. والتسمية 0 تعني خبيثاً (212 عينة) و 1 تعني حميداً (357 عينة).
ندرّب شجرة قرار بالخطوات التي تعرفها:
from sklearn.model_selection import train_test_splitfrom sklearn.tree import DecisionTreeClassifierfrom sklearn.metrics import accuracy_score
X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.25, random_state=42, stratify=y)model = DecisionTreeClassifier(max_depth=3, random_state=42)model.fit(X_train, y_train)predictions = model.predict(X_test)
print(len(y_test))print(f'{accuracy_score(y_test, predictions):.3f}')1430.944الجديد هنا stratify=y: تجعل نسبة الخبيث إلى الحميد في بيانات الاختبار مثل نسبتها في البيانات كلها. والدقة 94.4% على 143 عينة اختبار. جيد، لكن السؤال المهم: الأخطاء الثمانية، ما نوعها؟
مصفوفة الالتباس
Section titled “مصفوفة الالتباس”مصفوفة الالتباس (Confusion Matrix) جدول يقارن الحقيقة بالتوقع:
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_test, predictions)print(cm)[[48 5] [ 3 87]]الصفوف هي الحقيقة، والأعمدة هي توقع النموذج:
| توقّع: خبيث | توقّع: حميد | |
|---|---|---|
| الحقيقة: خبيث | 48 (أصاب) | 5 (فاته!) |
| الحقيقة: حميد | 3 (إنذار كاذب) | 87 (أصاب) |
الأرقام على القطر (48 و 87) توقعات صحيحة. والباقي نوعان من الخطأ مختلفان تماماً في خطورتهما:
- 5 أورام خبيثة قال عنها حميدة: مريض يعود لبيته مطمئناً وهو يحتاج علاجاً. خطأ قد يكلف حياة.
- 3 أورام حميدة قال عنها خبيثة: إنذار كاذب. مزعج ومقلق، لكن فحصاً إضافياً يصححه.
الدقة جمعت النوعين في رقم واحد وأخفت الفرق. مصفوفة الالتباس مثل كشف حساب مفصّل بدل الرصيد النهائي وحده.
Precision و Recall
Section titled “Precision و Recall”نختار الفئة التي تهمنا (هنا: خبيث) ونسأل سؤالين:
- الاستدعاء (Recall): من كل الأورام الخبيثة فعلاً، كم اكتشف النموذج؟
- الضبط (Precision): من كل ما قال النموذج إنه خبيث، كم كان خبيثاً فعلاً؟
from sklearn.metrics import precision_score, recall_score, f1_score
print(f'{recall_score(y_test, predictions, pos_label=0):.3f}')print(f'{precision_score(y_test, predictions, pos_label=0):.3f}')print(f'{f1_score(y_test, predictions, pos_label=0):.3f}')0.9060.9410.923pos_label=0 تحدد الفئة التي نقيسها. والحساب من المصفوفة مباشرة:
- Recall يساوي 48 ÷ (48 + 5) = 0.906: اكتشف 90.6% من الأورام الخبيثة وفاته الباقي.
- Precision يساوي 48 ÷ (48 + 3) = 0.941: حين يقول «خبيث» يكون محقاً في 94.1% من المرات.
- F1: رقم واحد يجمع الاثنين، ويكون عالياً فقط إذا كان كلاهما عالياً.
تشبيه يساعدك على التفريق: نموذجك صياد سمك. Recall: كم سمكة في البحيرة وقعت في شبكته؟ و Precision: كم مما في شبكته سمك فعلاً وليس أحذية قديمة؟
أيهما أهم؟
Section titled “أيهما أهم؟”يعتمد على ثمن كل خطأ في مشكلتك:
| المشكلة | الخطأ الأخطر | المقياس الأهم |
|---|---|---|
| تشخيص مرض خطير | تفويت مريض | Recall |
| كشف احتيال بنكي | تفويت عملية احتيال | Recall |
| فلتر الرسائل المزعجة | حذف رسالة مهمة | Precision |
| ترشيح مقاطع للأطفال | عرض مقطع غير مناسب | Precision |
والاثنان يتعاكسان غالباً: نموذج يصرخ «خبيث» عند أدنى شك يرفع Recall ويكثر الإنذارات الكاذبة، فينخفض Precision.
والدالة classification_report تطبع المقاييس كلها لكل فئة دفعة واحدة:
from sklearn.metrics import classification_report
print(classification_report(y_test, predictions, target_names=data.target_names)) precision recall f1-score support
malignant 0.94 0.91 0.92 53 benign 0.95 0.97 0.96 90
accuracy 0.94 143 macro avg 0.94 0.94 0.94 143weighted avg 0.94 0.94 0.94 143العمود support عدد العينات الحقيقية من كل فئة في بيانات الاختبار.
حين تكذب الدقة
Section titled “حين تكذب الدقة”لنرَ الفخ الذي بدأنا به الدرس. بيانات فيها 1000 معاملة بنكية، 30 منها فقط احتيال. و «نموذج كسول» يقول عن كل معاملة إنها سليمة دون أن ينظر إليها:
import numpy as npfrom sklearn.dummy import DummyClassifier
rng = np.random.default_rng(42)X_tx = rng.normal(size=(1000, 3))y_tx = np.zeros(1000, dtype=int)y_tx[:30] = 1
lazy = DummyClassifier(strategy='most_frequent')lazy.fit(X_tx, y_tx)lazy_pred = lazy.predict(X_tx)
print(f'{accuracy_score(y_tx, lazy_pred):.2f}')print(f'{recall_score(y_tx, lazy_pred):.2f}')print(confusion_matrix(y_tx, lazy_pred))0.970.00[[970 0] [ 30 0]]دقة 97%، و Recall صفر: لم يكتشف عملية احتيال واحدة من الثلاثين! DummyClassifier نموذج لا يتعلم شيئاً، ووظيفته أن يكون خط الأساس الذي تقارن به.
هل الرقم مستقر؟ التحقق المتقاطع
Section titled “هل الرقم مستقر؟ التحقق المتقاطع”دقتنا 0.944 جاءت من تقسيمة واحدة للبيانات. ماذا لو وقعت العينات السهلة في الاختبار بالصدفة؟ التحقق المتقاطع (Cross-Validation) يقسم البيانات إلى خمسة أجزاء، ويدرّب خمس مرات: في كل مرة جزء مختلف للاختبار والأربعة الباقية للتدريب:
from sklearn.model_selection import cross_val_score
scores = cross_val_score( DecisionTreeClassifier(max_depth=3, random_state=42), X, y, cv=5)print(scores.round(3))print(f'{scores.mean():.3f}')[0.912 0.895 0.939 0.956 0.894]0.919خمس نتائج تتراوح بين 89.4% و 95.6%، ومتوسطها 91.9%. هذا تقدير أصدق من رقم واحد، ويخبرك أيضاً بمقدار التذبذب. مثل الحكم على طالب من خمسة امتحانات بدل امتحان واحد قد يكون حالفه فيه الحظ.
جرّب بنفسك
Section titled “جرّب بنفسك”- درّب شجرة قرار بعمق 2 على بيانات الأورام، واطبع مصفوفة الالتباس و Recall للفئة الخبيثة.
- قارن النتيجة بنموذج
DummyClassifier(strategy='most_frequent')على البيانات نفسها. - احسب متوسط الدقة بالتحقق المتقاطع مع
cv=10. - تحدٍّ: ارجع لنموذج الزهور من الدرس السابق، واطبع
classification_reportله، وحدد أي نوعين من الزهور يخلط بينهما النموذج إن أخطأ.
أخطاء شائعة
Section titled “أخطاء شائعة”- الاكتفاء بالدقة: خصوصاً مع البيانات غير المتوازنة. اطبع مصفوفة الالتباس دائماً.
- قراءة المصفوفة بالمقلوب: في scikit-learn الصفوف للحقيقة والأعمدة للتوقع، والترتيب حسب قيم التسميات (0 ثم 1).
- التقييم على بيانات التدريب: يعطي أرقاماً وردية لا معنى لها. قيّم دائماً على بيانات لم يرها النموذج.
- الحكم من تقسيمة واحدة: تغيير
random_stateقد يغيّر الدقة عدة نقاط. استخدم التحقق المتقاطع للمقارنة بين النماذج.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
نموذج لكشف مرض خطير: أي مقياس أهم إذا كان تفويت مريض أخطر من إنذار كاذب؟
Recall يقيس نسبة المرضى الحقيقيين الذين اكتشفهم النموذج، وهو ما يهم حين يكون التفويت مكلفاً.
سؤال
بيانات فيها 99% رسائل سليمة و 1% مزعجة. نموذج يصنّف كل شيء «سليمة». ما دقته؟
يصيب في كل الرسائل السليمة فتكون دقته 99%، مع أنه لا يكتشف أي رسالة مزعجة. لهذا الدقة وحدها مضللة.
الخلاصة
Section titled “الخلاصة”- الدقة نسبة التوقعات الصحيحة، وتخدعك عندما تكون إحدى الفئات نادرة.
- مصفوفة الالتباس تفصّل الأخطاء: ما فات النموذج، وما أنذر به كذباً.
- Recall: كم اكتشف من الحالات الحقيقية. و Precision: كم صدق حين أنذر.
- اختر المقياس حسب ثمن كل خطأ، وقارن بنموذج كسول
DummyClassifier. - التحقق المتقاطع يعطي تقديراً أصدق من تقسيمة واحدة.