مقاييس التقييم : الجزء الأول

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

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

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

 إذا تحدثنا عن مشاكل التصنيف ، فإن المقاييس الأكثر شيوعًا المستخدمة هي: 

  •  الدقة (Accuracy)
  •  الضبط (Precision) أو (P)  
  • الإسترداد (Recall) أو (R) 
  •  درجة F1  أو (F1) 
  • المنطقة الواقعة تحت منحنى ROC و التي تعني (Receiver Operating Characteristic) أو بإختصار(AUC)  
  • خسارة اللوغاريتم (Log loss)
  • الضبط عند k أي (Precision at k) أو (P@K) 
  • متوسط الإنضباط عند k  أي (Average precision) أو  (AP@k)  
  •  متوسط  متوسط الإنضباط عند k أي (Mean average precision) أو  (MAP @ k) 

عندما يتعلق الأمر بالانحدار ، فإن مقاييس التقييم الأكثر شيوعًا هي:  

  • متوسط ​​الخطأ المطلق (Mean absolute error) أو (MAE) 
  • متوسط ​​الخطأ التربيعي  (Mean squared error ) أو (MSE)  
  • جذر متوسط ​​الخطأ التربيعي  (Root mean squared error ) أو (RMSE) 
  • جذر متوسط ​​الخطأ اللوغاريتمي التربيعي  (Root mean squared logarithmic error) أو  (RMSLE) 
  • متوسط ​​نسبة الخطأ  (Mean percentage error) أو  (MPE) 
  • متوسط ​​خطأ النسبة المئوية المطلقة  (Mean absolute percentage error ) أو  (MAPE) –
  •  R2 

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

التصنيف الثنائي

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

ونفترض أيضًا أن لدينا عددًا متساويًا من صور الأشعة السينية استرواح الصدر و الصدر السليم. لنفترض 100 لكل منهما. وبالتالي ، لدينا 100 عينة إيجابية و 100 عينة سلبية بإجمالي 200 صورة.

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

عندما يكون لدينا عدد متساوٍ من العينات الموجبة والسالبة في مقياس تصنيف ثنائي ، فإننا نستخدم الدقة و الضبط و الإسترجاع و f1 بشكل عام. 

الدقة (Accuracy)

الدقة: إحدى المقاييس الأكثر سهولة المستخدمة في التعلم الآلي. إنها تحدد مدى دقة نموذجك. بالنسبة للمشكلة الموضحة أعلاه ، إذا قمت ببناء نموذج يصنف 90 صورة بدقة ، فإن دقتك ستكون 90٪ أو 0.90. 

إذا تم تصنيف 83 صورة فقط بشكل صحيح ، فإن دقة نموذجك تبلغ 83٪ أو 0.83.  بهذه البساطة.

 كود Python لحساب الدقة بسيط للغاية أيضًا.

def accuracy(y_true, y_pred):

    """
    دالة لحساب الدقة
    قائمة لحساب القيم الحقيقية : y_true
    قائمة لحساب القيم المتنبأ بها : y_pred
    إرجاع نتيجة الدقة: return
    """

    # تهيئة عداد بسيط للتنبؤات الصحيحة

    correct_counter = 0

    # y_true إنشاء حلقة حول جميع عناصر 
    # معاً y_pred و

    for yt, yp in zip(y_true, y_pred):
        if yt == yp:
            # لو كان التنبو مساوي للحقيقة ، زيادة العداد
            correct_counter += 1

    # إرجاع نتيجة الدقة
    # و هي الدقة الحقيقية فوق عدد العينات

    return correct_counter/ len(y_true)

 يمكننا أيضًا حساب الدقة باستخدام scikit-Learn.

from sklearn import metrics

l1 = [0,1,1,1,0,0,0,1]
l2 = [0,1,0,1,0,1,0,0]

metrics.accuracy_score(l1,l2)

 الآن ، لنفترض أننا قمنا بتغيير مجموعة البيانات قليلاً بحيث يكون هناك 180 صورة بالأشعة السينية للصدر والتي لا تحتوي على استرواح الصدر و 20 صورة فقط مع استرواح الصدر. 

حتى في هذه الحالة ، سنقوم بإنشاء مجموعات التدريب والتحقق بنفس النسبة من الأهداف الموجبة إلى السلبية (استرواح الصدر إلى  الصدر السليم). في كل مجموعة ، لدينا 90 صورة لصدر سليم  و 10 صور استرواح صدري. 

إذا قلت أن جميع الصور الموجودة في مجموعة التحقق لا تحتوي على استرواح الصدر ، فما هي دقتك؟ لنرى؛ لقد صنفت 90٪ من الصور بشكل صحيح. لذا ، دقتك هي 90٪. لكن انظر إليها مرة أخرى. لم تقم حتى ببناء نموذج وحصلت على دقة 90٪. هذا يبدو نوعا ما عديم الفائدة.

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

الضبط (precision)

قبل تعلم الضبط، نحتاج إلى معرفة بعض المصطلحات. لقد افترضنا هنا أن صور الأشعة السينية للصدر المصابة باسترواح الصدر هي فئة موجبة (1) وبدون استرواح الصدر هي فئة سلبية (0).

 موجب حقيقي (True positive) أو بإختصار (TP): بالنظر إلى الصورة ، إذا توقع نموذجك أن الصورة بها استرواح الصدر ، وكان الهدف الفعلي لتلك الصورة مصابًا باسترواح الصدر ، فإنه يعتبر موجب حقيقي.

 سلبي حقيقي (True negative) أو بإختصار   (TN): بالنظر إلى الصورة ، إذا توقع نموذجك أن الصورة لا تحتوي على استرواح الصدر والهدف الفعلي يقول إنها صورة غير استرواح الصدر ، فإنها تعتبر سلبية حقيقية.

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

 موجب كاذب (False positive) أو بإختصار   (FP): عند إعطاء صورة ما ، إذا كان نموذجك يتوقع استرواح الصدر وكان الهدف الفعلي لتلك الصورة هو عدم استرواح الصدر ، فهي نتيجة موجب كاذب.

 سلبي كاذب (False negative)  أو بإختصار (FN): بالنظر إلى الصورة ، إذا كان النموذج الخاص بك يتنبأ بعدم استرواح الصدر والهدف الفعلي لتلك الصورة هو استرواح الصدر ، فهي نتيجة سلبي كاذب.

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

دعونا نلقي نظرة على تطبيق هذه ، واحدًا تلو الآخر.

def true_positive(y_true, y_pred):
    tp=0
    for yt , yp in zip(y_true, y_pred):
        if yt == 1 and yp ==1 :
            tp += 1
    return tp 

def true_negative(y_true, y_pred):
    tn=0
    for yt , yp in zip(y_true, y_pred):
        if yt == 0 and yp ==0 :
            tn += 1
    return tn 

def false_positive(y_true, y_pred):
    fp=0
    for yt , yp in zip(y_true, y_pred):
        if yt == 0 and yp == 1 :
            fp += 1
    return fp 

def false_negative(y_true, y_pred):
    fn=0
    for yt , yp in zip(y_true, y_pred):
        if yt == 1 and yp ==0 :
            fn += 1
    return fn 

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

In [X]: l1 = [0,1,1,1,0,0,0,1]
 ...: l2 = [0,1,0,1,0,1,0,0]
In [X]: true_positive(l1, l2)
Out[X]: 2
In [X]: false_positive(l1, l2)
Out[X]: 1
In [X]: false_negative(l1, l2)
Out[X]: 2
In [X]: true_negative(l1, l2)
Out[X]: 3

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

Accuracy Score = (TP + TN) / (TP + TN + FP + FN

يمكننا الآن تنفيذ درجة الدقة بسرعة باستخدام TP و TN و FP و FN في python . دعنا نسميها accuracy_v2

def accuracy_v2(y_true, y_pred):
    
    tp = true_positive(y_true, y_pred)
    fp = false_positive(y_true, y_pred)
    tn = true_negative(y_true, y_pred)
    fn = false_negative(y_true, y_pred)
    accuracy_score = (tp + tn) / (tp + tn + fp + fn)
    return accuracy_score

يمكننا التحقق بسرعة من صحة هذه الوظيفة من خلال مقارنتها بتطبيقنا السابق وإصدار scikit-Learn. 

In [X]: l1 = [0,1,1,1,0,0,0,1]
 ...: l2 = [0,1,0,1,0,1,0,0]
In [X]: accuracy(l1, l2)
Out[X]: 0.625
In [X]: accuracy_v2(l1, l2)
Out[X]: 0.625
In [X]: metrics.accuracy_score(l1, l2)
Out[X]: 0.625

يرجى ملاحظة أن metrics.accuracy_score تاتي من scikit-Learn.

 عظيم. تتطابق جميع القيم. هذا يعني أننا لم نرتكب أي أخطاء في التنفيذ. 

الآن ، يمكننا الانتقال إلى مقاييس مهمة أخرى.

 أولها الضبط . تُعرَّف الضبط على أنه : 

Precision = TP / (TP + FP)

لنفترض أننا نصنع نموذجًا جديدًا على مجموعة البيانات الجديدة المنحرفة وأن نموذجنا حدد بشكل صحيح 80 حالة غير استرواح الصدر من أصل 90 و 8 استرواح صدري من أصل 10. وهكذا ، نحدد 88 من أصل 100 صورة بنجاح. وبالتالي تبلغ الدقة 0.88 أو 88٪.

ولكن ، من بين هذه العينات المائة ، تم تصنيف 10 صور لا تحتوي على استرواح الصدر بشكل خاطئ على أنها مصابة باسترواح صدري و 2 استرواح صدري تم تصنيفهما خطأ على أنهما لا يعانيان من استرواح الصدر.

 وهكذا ، لدينا: 

  •  TP: 8
  •  TN: 80
  •  FP: 10
  •  FN: 2

 إذن ، قيمة الضبط هي:

precision = 8 / (8 + 10) = 0.444

هذا يعني أن نموذجنا صحيح بنسبة 44.4٪ عندما يحاول التعرف على العينات الإيجابية (استرواح الصدر). 

الآن ، نظرًا لأننا قمنا بتطبيق TP و TN و FP و FN ، يمكننا بسهولة تطبيق الضبط في Python. 

def precision(y_true, y_pred):
    
    tp = true_positive(y_true, y_pred)
    fp = false_positive(y_true, y_pred)
    precision = tp / (tp + fp)
    
    return precision

دعونا نجرب تطبيق الدقة هذا.

In [X]: l1 = [0,1,1,1,0,0,0,1]
 ...: l2 = [0,1,0,1,0,1,0,0]
In [X]: precision(l1, l2)
Out[X]: 0.6666666666666666

 يبدو هذا جيدًا.

الإستدعاء (Recall)

 يتم تعريف الاستدعاء على النحو التالي: 

Recall = TP / (TP + FN) 

 في الحالة المذكورة أعلاه يكون الإستدعاء:

Recall = 8 / (8 + 2) = 0.80

هذا يعني أن نموذجنا قد حدد 80٪ من العينات الإيجابية بشكل صحيح

def recall(y_true, y_pred):
    tp = true_positive(y_true, y_pred)
    fn = false_negative(y_true, y_pred)
    recall = tp / (tp + fn)
    return recall

 في حالة القائمتين الصغيرتين ، يجب أن يكون لدينا استدعاء 0.5. دعونا تحقق. 

In [X]: l1 = [0,1,1,1,0,0,0,1]
 ...: l2 = [0,1,0,1,0,1,0,0]
In [X]: recall(l1, l2)
Out[X]: 0.5

وهذا يطابق القيمة المحسوبة لدينا!

 للحصول على نموذج “جيد” ، يجب أن تكون قيم الضبط (precision)  والاستدعاء (recall) عالية. نرى في المثال أعلاه أن قيمة الاستدعاء عالية جدًا. ومع ذلك ، فإن الضبط منخفضة للغاية! 

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

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

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

 قبل النظر في منحنى  الضبط-الإسترداد ، لنفترض وجود قائمتين.

y_true = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
        1, 0, 0, 0, 0, 0, 0, 0, 1, 0]

y_pred = [0.02638412, 0.11114267, 0.31620708,
         0.0490937, 0.0191491, 0.17554844,
         0.15952202, 0.03819563, 0.11639273,
         0.079377, 0.08584789, 0.39095342,
         0.27259048, 0.03447096, 0.04644807,
         0.03543574, 0.18521942, 0.05934905,
         0.61977213, 0.33056815]

 إذن ، y_true هي أهدافنا ، و y_pred هي قيم الاحتمالية لعينة يتم تعيين قيمة لها بقيمة 1. 

لذا ، الآن ، ننظر إلى الاحتمالات في التنبؤ بدلاً من القيمة المتوقعة (وهي في معظم الأحيان محسوبة بحد أدنى عند 0.5). 

precisions = []

recalls = []

thresholds = [0.0490937 , 0.05934905, 0.079377,
             0.08584789, 0.11114267, 0.11639273,
             0.15952202, 0.17554844, 0.18521942,
             0.27259048, 0.31620708, 0.33056815,
             0.39095342, 0.61977213]

# لكل عتبه احسب التنبؤات  كثنائي
# قم بإضافة قيم الضبط و الإستدعاء إلى قوائمهم

for i in thresholds:
    temp_predictions = [ 1 if x>= i else 0 for x in y_pred]
    p = precision(y_true, temp_predictions)
    r = recall(y_true, temp_predictions)
    precisions.append(p)
    recalls.append(r)

الآن ، يمكننا رسم قيم  الضبط – الاسترداد هذه.

import matplotlib.pyplot as plt
plt.figure(figsize=(7, 7))
plt.plot(recalls, precisions)
plt.xlabel('Recall', fontsize=15)
plt.ylabel('Precision', fontsize=15)

يوضح الشكل أدناه  منحنى الضبط – الإسترداد  الذي نحصل عليه بهذه الطريقة.

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

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

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

 يتراوح الضبط و الإسترداد  من 0 إلى 1 وتكون القيمة الأقرب إلى 1 أفضل.

درجة F1

 درجة F1 هي مقياس يجمع بين الضبط والإسترداد . يتم تعريفه على أنه متوسط موزون للضبط و الإسترداد . إذا أشرنا إلى الضبط (precision) باستخدام P  و الإسترداد (recall) باستخدام R ، فيمكننا تمثيل درجة F1 على النحو التالي

F1 = 2PR / (P + R) 

 القليل من الرياضيات سيقودنا إلى المعادلة التالية لـ F1 بناءً على TP و FP و FN

F1 = 2TP / (2TP + FP + FN)

يمكننا برمجة هذا في بايثون كالأتي :

def f1(y_true, y_pred):
    p = precision(y_true, y_pred)
    r = recall(y_true, y_pred)
    
    score = 2* p * r / (p + r)
    
    return score

دعونا نرى نتائج هذا ونقارنه مع scikit-Learn.

In [X]: y_true = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
 ...: 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]
In [X]: y_pred = [0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
 ...: 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]
In [X]: f1(y_true, y_pred)
Out[X]: 0.5714285714285715

 ومن scikit Learn لنفس القوائم ، نحصل على: 

In [X]: from sklearn import metrics
In [X]: metrics.f1_score(y_true, y_pred)
Out[X]: 0.5714285714285715

بدلاً من النظر إلى الضبط والإسترداد  بشكل فردي ، يمكنك أيضًا إلقاء نظرة على درجة F1. كما هو الحال بالنسبة للضبط (precision) و الإسترداد (recall)  والدقة (accuracy) ، تتراوح درجة F1 أيضًا من 0 إلى 1 ، ونموذج التنبؤ المثالي له F1 تساوي 1.

عند التعامل مع مجموعات البيانات التي تحتوي على أهداف منحرفة ، يجب أن ننظر إلى F1 (أو الضبط و الإسترداد) بدلاً من الدقة. 

ثم هناك مصطلحات أخرى مهمة يجب أن نعرفها. 

معدل موجب حقيقي (True Positive Rate)

معدل موجب حقيقي أو بإختصار (TPR)   وهو مشابه للإسترداد : 

TPR = TP / (TP + FN

على الرغم من أنه مشابه للإسترداد ، سنقوم بعمل دالة بيثون لاستخدامها لاحقاً 

def tpr(y_true, y_pred):

    return recall(y_true, y_pred)

. يُعرف TPR أيضًا بالحساسية (sensitivity).

معدل موجب خاطى (False Positive Rate)

معدل موجب خاطى أو بإختصار (FPR)   يعرف على أنه : 

FPR = FP / (TN + FP)

def fpr(y_true, y_pred):
    fp = false_positive(y_true, y_pred)
    tn = true_negative(y_true, y_pred)
    return fp / (tn + fp)

 و 1 – FPR  يعرف بالنوعية (specificity) أو المعدل السلبي الحقيقي (True Negative Rate)  أو TNR. 

هناك الكثير من المصطلحات ، ولكن أهمها فقط TPR و FPR. 

لنفترض أن لدينا 15 عينة فقط وأن قيمها المستهدفة ثنائية (binary) : 

الأهداف الفعلية: [0 ، 0 ، 0 ، 0 ، 1 ، 0 ، 1 ، 0 ، 0 ، 1 ، 0 ، 1 ، 0 ، 0 ، 1 ، 0 ، 1] 

نقوم بتدريب نموذج مثل الغابة العشوائية (random forest,) ، ويمكننا الحصول على الاحتمال عندما تكون العينة إيجابية. 

الاحتمالات المتوقعة لـ 1: [0.1 ، 0.3 ، 0.2 ، 0.6 ، 0.8 ، 0.05 ، 0.9 ، 0.5 ، 0.3 ، 0.66 ، 0.3 ، 0.2 ، 0.85 ، 0.15 ، 0.99]

لو إخترنا  العتبة نموذجية> = 0.5 ، يمكننا تقييم كل القيم العلوية للدقة و استدعاء / TPR و  F1 و FPR. 

ولكن يمكننا أن نفعل الشيء نفسه إذا اخترنا أن تكون قيمة العتبة 0.4 أو 0.6. في الواقع ، يمكننا اختيار أي قيمة بين 0 و 1 وحساب جميع المقاييس الموضحة أعلاه. دعونا نحسب قيمتين فقط : TPR و FPR. 

tpr_list = []
fpr_list = []

# القيم الحقيقية
y_true = [0, 0, 0, 0, 1, 0, 1,
         0, 0, 1, 0, 1, 0, 0, 1]

# الإحتمالات المتنبأ لكون القيمة تساوي 1

y_pred = [0.1, 0.3, 0.2, 0.6, 0.8, 0.05,
 0.9, 0.5, 0.3, 0.66, 0.3, 0.2,
 0.85, 0.15, 0.99]

# العتبه المختارة 
thresholds = [0, 0.1, 0.2, 0.3, 0.4, 0.5,
 0.6, 0.7, 0.8, 0.85, 0.9, 0.99, 1.0]

for thresh in thresholds:
    # حساب التبنؤات للعتبة المختارة
    temp_pred = [1 if x >= thresh else 0 for x in y_pred]
    
    # tpr حساب
    temp_tpr = tpr(y_true, temp_pred)
    
    #fpr حساب
    temp_fpr = fpr(y_true, temp_pred)
    
    #إضافة القيم إلى القوائم
    fpr_list.append(temp_fpr)
    tpr_list.append(temp_tpr)

يمكننا بالتالي الحصول على قيمة tpr و fpr لكل عتبة. 

إذا رسمنا الجدول كما هو موضح في الجدول  ، أي إذا كان لدينا TPR على المحور y و FPR على المحور x ، فسنحصل على منحنى كما هو موضح في الرسم 

plt.figure(figsize=(7, 7))
plt.fill_between(fpr_list, tpr_list, alpha=0.4)
plt.plot(fpr_list, tpr_list, lw=3)
plt.xlim(0, 1.0)
plt.ylim(0, 1.0)
plt.xlabel('FPR', fontsize=15)
plt.ylabel('TPR', fontsize=15)
plt.show()

المنطقة الواقعة تحت منحنى ROC

هذا المنحنى معروف أيضًا بإسم (Receiver Operating Characteristic) أو بإختصار (ROC). وإذا قمنا بحساب المنطقة الواقعة أسفل منحنى ROC هذا ، فإننا نحسب مقياسًا آخر يتم استخدامه كثيرًا عندما يكون لديك مجموعة بيانات بها أهداف ثنائية منحرفة.

 يُعرف هذا المقياس بالمنطقة الواقعة تحت منحنى ROC أو المنطقة الواقعة تحت المنحنى أو ببساطة AUC. 

هناك العديد من الطرق لحساب المنطقة الواقعة أسفل منحنى ROC. لهذا الغرض بالذات ،سنقوم بإستخدام scikitlearn.

In [X]: from sklearn import metrics
In [X]: y_true = [0, 0, 0, 0, 1, 0, 1,
 ...: 0, 0, 1, 0, 1, 0, 0, 1]
In [X]: y_pred = [0.1, 0.3, 0.2, 0.6, 0.8, 0.05,
 ...: 0.9, 0.5, 0.3, 0.66, 0.3, 0.2,
 ...: 0.85, 0.15, 0.99]
In [X]: metrics.roc_auc_score(y_true, y_pred)
Out[X]: 0.8300000000000001

 تتراوح قيم AUC من 0 إلى 1.

  •  AUC = 1 تعني أن لديك نموذجًا مثاليًا. في معظم الأحيان ، يعني هذا أنك ارتكبت خطأً ما في التحقق ويجب عليك إعادة النظر في معالجة البيانات وخط أنابيب التحقق الخاص بك. إذا لم ترتكب أي أخطاء ، فتهانينا ، فلديك أفضل نموذج يمكن للمرء الحصول عليه لمجموعة البيانات التي بنيت عليها.
  •  AUC = 0 تعني أن نموذجك سيء جدًا (أو جيد جدًا!). حاول عكس احتمالات التنبؤات ، على سبيل المثال ، إذا كان احتمال الفئة الإيجابية هو p ، فحاول استبدالها بـ 1-p. قد يعني هذا النوع من AUC أيضًا أن هناك بعض المشكلات في عملية التحقق أو معالجة البيانات. 
  •  AUC = 0.5 تعني أن توقعاتك عشوائية. لذلك ، بالنسبة لأي مشكلة تصنيف ثنائي ، إذا توقعت أن تكون جميع الأهداف 0.5 ، فسوف أحصل على AUC من 0.5. 

تشير قيم AUC بين 0 و 0.5 إلى أن نموذجك أسوأ من العشوائي. في معظم الأحيان ، يكون ذلك بسبب عكسك للتصانيف. إذا حاولت عكس توقعاتك ، فقد تصبح AUC الخاصة بك أكثر من 0.5. تعتبر قيم AUC الأقرب من 1 جيدة.

 لكن ماذا تخبرنا AUC عن نموذجنا؟

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

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

في حالة التصنيف الثنائي ، يمكنك القيام بشيء من هذا القبيل.

 التنبؤ = الاحتمالية> = العتبه

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

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

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

 دعونا نرى كيف تؤثر هذه العتب على القيم موجب حقيقي و موجب خاطى . 

tp_list =  []
fp_list = []

# القيم الحقيقية
y_true = [0, 0, 0, 0, 1, 0, 1,
         0, 0, 1, 0, 1, 0, 0, 1]

# الإحتمالات المتنبأ لكون القيمة تساوي 1

y_pred = [0.1, 0.3, 0.2, 0.6, 0.8, 0.05,
 0.9, 0.5, 0.3, 0.66, 0.3, 0.2,
 0.85, 0.15, 0.99]

# العتبه المختارة 
thresholds = [0, 0.1, 0.2, 0.3, 0.4, 0.5,
 0.6, 0.7, 0.8, 0.85, 0.9, 0.99, 1.0]

for thresh in thresholds:
    # حساب التبنؤات للعتبة المختارة
    temp_pred = [1 if x >= thresh else 0 for x in y_pred]
    
    # tpr حساب
    temp_tp = tpr(y_true, temp_pred)
    
    #fpr حساب
    temp_fp = fpr(y_true, temp_pred)
    
    #إضافة القيم إلى القوائم
    fp_list.append(temp_fp)
    tp_list.append(temp_tp)

باستخدام هذا ، يمكننا إنشاء الجدول التالي .

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

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

خسارة اللوغاريتم (log loss)

 مقياس آخر مهم يجب أن تتعلمه بعد تعلم AUC هو خسارة اللوغاريتم. في حالة وجود مشكلة في التصنيف الثنائي ، نحدد خسارة اللوغاريتم على النحو التالي:

Log Loss = – 1.0 * ( target * log(prediction) + (1 – target) * log(1 – prediction) )

 حيث يكون الهدف إما 0 أو 1 والتنبؤ هو احتمال لعينة تنتمي إلى الفئة 1.

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

import numpy as np

def log_loss(y_true, y_pred):
    
    #تعريف قيمة الإيبسلون 
    # يمكن أن تكون قيمة مدخل
    # أو يمكن ان تكون قيمة قطع
    epsilon = 1e-15
    
    # تهيئة قوائم فارغة
    # من أجل حفظ الخسارات الفردية
    
    loss = []
    
    for yt , yp in  zip(y_true, y_pred):
        # تعديل الإحتمالات
        # 1e-15 يتم تحويل قيمة 0 إلى  
        # 1-1e-15 يتم تحويل قيمة 1 إلى  
        yp = np.clip(yp, epsilon, 1 - epsilon)
        # حساب الخسارة لعينة واحدة
        
        temp_loss = - 1.0 * ( 
                    yt * np.log(yp)
                    + ( 1-yt) * np.log(1-yp)
        )
        # إضافة لقائمة الخسارة
        loss.append(temp_loss)
    #إرجاع متوسط الخسارة لكل العينات
    return np.mean(loss)

لنر تطبيقنا 

In [X]: y_true = [0, 0, 0, 0, 1, 0, 1,
 ...: 0, 0, 1, 0, 1, 0, 0, 1]
In [X]: y_proba = [0.1, 0.3, 0.2, 0.6, 0.8, 0.05,
 ...: 0.9, 0.5, 0.3, 0.66, 0.3, 0.2,
 ...: 0.85, 0.15, 0.99]
In [X]: log_loss(y_true, y_proba)
Out[X]: 0.49882711861432294

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

 على سبيل المثال ، إذا كنت متأكدًا بنسبة 51٪ من عينة تنتمي إلى الفئة 1 ، فسيكون خسارة اللوغاريتم:

– 1.0 * ( 1 * log(0.51) + (1 – 1) * log(1 – 0.51) ) = 0.67

وإذا أنت متأكد بنسبة 49 ٪ من عينة تنتمي إلى الفئة 0 ، سيكون خسارة اللوغاريتم:

 – 1.0 * (0 * سجل (0.49) + (1 – 0) * سجل (1 – 0.49)) = 0.67

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

إضافة تعليق