مقاييس التقييم : الجزء الثاني

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

التصنيف متعدد الفئات

هناك ثلاث طرق مختلفة لحساب هذا والتي قد تكون مربكة من وقت لآخر. لنفترض أننا مهتمون بالضبط أولاً. نحن نعلم أن الضبط يعتمد على موجب حقيقي (true positives)  و موجب كاذب (false positives) .

– متوسط الضبط الكلي (Macro averaged precision) : حساب الضبط لجميع الفئات على حدة ثم حساب متوسطها

متوسط الضبط الجزئي ( Micro averaged precision): حساب الموجب الحقيقي و الموجب السلبي لكل فئة ثم إستخدام ذلك لحساب الضبط الإجمالي 

– الضبط الموزون (Weighted precision) : مثل الضبط الكلي ولكن في هذه الحالة ، المتوسط موزون اعتمادًا على عدد العناصر في كل فئة يبدو.

قد يبدو هذا معقدًا ولكن يسهل فهمه من خلال تطبيقه في  Python. دعونا نرى كيف يتم تنفيذ كل منها.

متوسط الضبط الكلي

def macro_precision(y_true, y_pred):

    
    """
    دالة لحساب الدقة
    قائمة لحساب القيم الحقيقية : y_true
    قائمة لحساب القيم المتنبأ بها : y_pred
    إرجاع نتيجة الضبط الكلي: return
    """
    
    # إيجاد قيمة كل تصميف عن طريق
    # طول القيم الفردية في القائمة الحقيقية
    
    num_classes = (len(np.unique(y_true)))
    
    #  تهيئة الضبط بصفر
    
    precision = 0
    
    # إنشاء حلقة لكل التصانيف
    
    for class_ in range(num_classes):
        
        #جميع التصانيف ما عدا الحالية معتبره سالبه
        temp_true = [ 1 if p == class_ else 0 for p in y_true]
        temp_pred = [ 1 if p == class_ else 0 for p in y_pred]
        
        # حساب موجب حقيقي للتصنيف الحالي 
        tp = true_positive(temp_true, temp_pred)
        
        #حساب موجب سالب للتصنيف الحالي 
        fp = false_positive(temp_true, temp_pred)
        
        # حساب الضبط للتصنيف الحالي 
        temp_precision = tp / (tp + fp)
        
        # الإستمرار في إضافة الضبط لكل التصانيف 
        precision += temp_precision
    # حساب الضبط المتوسط لكل التصانيف

    precision /= num_classes
    return precision
    

  متوسط الضبط الجزئي 

def micro_precision(y_true, y_pred):

    
    """
    دالة لحساب الدقة
    قائمة لحساب القيم الحقيقية : y_true
    قائمة لحساب القيم المتنبأ بها : y_pred
    إرجاع نتيجة الضبط الجزئي: return
    """
    
    # إيجاد قيمة كل تصميف عن طريق
    # طول القيم الفردية في القائمة الحقيقية
    
    num_classes = (len(np.unique(y_true)))
    
    #  تهيئة موجب حقيقي  و موجب كاذب بصفر
    
    tp = 0
    fp = 0
    
    # إنشاء حلقة لكل التصانيف
    
    for class_ in range(num_classes):
        
        #جميع التصانيف ما عدا الحالية معتبره سالبه
        temp_true = [ 1 if p == class_ else 0 for p in y_true]
        temp_pred = [ 1 if p == class_ else 0 for p in y_pred]
        
        # حساب موجب حقيقي للتصنيف الحالي 
        #  و تحديث القيم الكلية 
        tp += true_positive(temp_true, temp_pred)
        
        #حساب موجب سالب للتصنيف الحالي 
        # و تحديث القيم الكلية
        fp += false_positive(temp_true, temp_pred)
        
        
    # حساب الضبط المتوسط لكل التصانيف

    precision = tp / (tp + fp)
    return precision
    

الضبط الموزون

from collections import Counter
def weighted_precision(y_true, y_pred):

    
    """
    دالة لحساب الدقة
    قائمة لحساب القيم الحقيقية : y_true
    قائمة لحساب القيم المتنبأ بها : y_pred
    إرجاع نتيجة الضبط الموزون: return
    """
    
    # إيجاد قيمة كل تصميف عن طريق
    # طول القيم الفردية في القائمة الحقيقية
    
    num_classes = (len(np.unique(y_true)))
    
    # إنشاء عدادا للتصانيف
    #سيبدو هكذا 
    # {0:20, 1:15, 2:21}
    class_counts = Counter(y_true)
    
    #  تهيئة الضبط بصفر
    
    precision  = 0
    fp = 0
    
    # إنشاء حلقة لكل التصانيف
    
    for class_ in range(num_classes):
        
        #جميع التصانيف ما عدا الحالية معتبره سالبه
        temp_true = [ 1 if p == class_ else 0 for p in y_true]
        temp_pred = [ 1 if p == class_ else 0 for p in y_pred]
        
        # حساب موجب حقيقي للتصنيف الحالي 
        tp = true_positive(temp_true, temp_pred)
        
        #حساب موجب سالب للتصنيف الحالي 
        fp = false_positive(temp_true, temp_pred)
        
        # حساب الضبط للتصنيف الحالي 
        temp_precision = tp / (tp + fp)
        
        # َضرب الضبط مع عدد العناصر في التصنيف
        weighted_precision = class_counts[class_] * temp_precision
        
        # تجميع الضبك الكلي
        precision += weighted_precision
        
        
    # حساب الضبط الكلي بالقسمو على مجموع العناصر

    overall_precision = precision / len(y_true)
    return overall_precision
    

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

In [X]: from sklearn import metrics
In [X]: y_true = [0, 1, 2, 0, 1, 2, 0, 2, 2]
In [X]: y_pred = [0, 2, 1, 0, 2, 1, 0, 0, 2]
In [X]: macro_precision(y_true, y_pred)
Out[X]: 0.3611111111111111
In [X]: metrics.precision_score(y_true, y_pred, average="macro")
Out[X]: 0.3611111111111111
In [X]: micro_precision(y_true, y_pred)
Out[X]: 0.4444444444444444
In [X]: metrics.precision_score(y_true, y_pred, average="micro")
Out[X]: 0.4444444444444444
In [X]: weighted_precision(y_true, y_pred)
Out[X]: 0.39814814814814814
In [X]: metrics.precision_score(y_true, y_pred, average="weighted")
Out[X]: 0.39814814814814814

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

وبالمثل ، يمكننا تنفيذ مقياس الاسترداد (recall metric ) لفئات متعددة. يعتمد الضبط و الإسترداد على الموجب الحقيقي و الموجب الكاذب و السلبي الكاذب ،  بينما تعتمد F1 على الضبط والاستدعاء 

لدينا هنا طريقة تنفيذ إصدار واحد من F1 لفئات متعددة ، ,وهو  المتوسط الموزون.

from collections import Counter
import numpy as np
def weighted_f1(y_true, y_pred):

num_classes = len(np.unique(y_true))


class_counts = Counter(y_true)

f1 = 0

for class_ in range(num_classes):


    temp_true = [1 if p == class_ else 0 for p in y_true]
    temp_pred = [1 if p == class_ else 0 for p in y_pred]

    p = precision(temp_true, temp_pred)
    r = recall(temp_true, temp_pred)

    if p + r != 0:

        temp_f1 = 2 * p * r / (p + r)
    else:
        temp_f1 = 0

    weighted_f1 = class_counts[class_] * temp_f1

    f1 += weighted_f1
    overall_f1 = f1 / len(y_true)
    return overall_f1

نقارن تطبيقنا مع scikit-Learn

In [X]: from sklearn import metrics
In [X]: y_true = [0, 1, 2, 0, 1, 2, 0, 2, 2]
In [X]: y_pred = [0, 2, 1, 0, 2, 1, 0, 0, 2]
In [X]: weighted_f1(y_true, y_pred)
Out[X]: 0.41269841269841273
In [X]: metrics.f1_score(y_true, y_pred, average="weighted")
Out[X]: 0.41269841269841273

 وبالتالي ، قمنا بتطبيق كل من الضبط والاستدعاء و F1 للمشاكل متعددة الفئات. يمكنك بالمثل تحويل AUC و خسارة اللوغاريتم إلى تصنيف متعدد الفئات . يُعرف هذا التحويل هذا باسم واحد مقابل الكل (one-vs-all) . لن أقوم بكتابة هذه التطبيق هنا لأنه مشابه تمامًا لما ناقشناه بالفعل. 

مصفوفة الإرتباك (confusion matrix)

في التصنيف الثنائي أو متعدد الفئات ، من الشائع أيضًا إلقاء نظرة على مصفوفة الارتباك (confusion matrix) . لا ترتبك. فهي سهله للغاية. مصفوفة الارتباك ليست سوى جدول موجب حقيقي ( TP ) و سلبي حقيقي ( FP )  و موجب كاذب ( TN ) و  سلبي كاذب (FN) .

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

إذا فهمت TP و FP و TN و FN والدقة والاستدعاء و AUC ، يصبح من السهل جدًا فهم وتفسير مصفوفة الارتباك. دعونا نرى كيف تبدو مصفوفة الارتباك لمشكلة التصنيف الثنائي في الشكل أدناه.

 نرى أن مصفوفة الارتباك تتكون من TP و FP و FN و TN. هذه هي القيم الوحيدة التي نحتاجها لحساب الضبط و الإسترداد و نتيجة F1 و AUC. في بعض الأحيان ، يفضل الأشخاص أيضًا تسمية FP كخطأ من النوع الأول (Type-I error)  و FN كخطأ من النوع الثاني (Type-II error.) . 

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

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

لنفترض أن لدينا التصانييف الفعلية التالية:

 [0 ، 1 ، 2 ، 0 ، 1 ، 2 ، 0 ، 2 ، 2]

 وتنبؤاتنا هي:

 [0 ، 2 ، 1 ، 0 ، 2 ، 1 ، 0 ، 0 ، 2 ] 

ستبدو مصفوفة الارتباك كما هو موضح في أدناه .

 ماذا يخبرنا هذا ؟ دعونا نلقي نظرة على الفئة 0. نرى أن هناك 3 حالات من الفئة 0 في التصنيف الحقيقي. ولكن في التنبؤات، لدينا 3 حالات تنتمي إلى الفئة 0 و وحالة واحدة  تنتمي  إلى الفئة 1. 

من الناحية المثالية ، بالنسبة للفئة 0 في التصنيف الحقيقي  ، يجب ألا يكون للتبؤات في الفئتين 1 و 2  أي حالة .

 دعونا نرى الفئة 2. في  التصنيف الحقيقي ، إجمالي هذه الفئة هو 4 (1+2+1) بينما في التنبؤات فإجمالي هو 3 (0+2+1).

حالة واحدة فقط لديها عدد عينات صحيح و هي الفئة 1 .

 يجب ملء مصفوفة الارتباك المثالية فقط بشكل مائل قطري من اليسار إلى اليمين.

توفر مصفوفة الارتباك طريقة سهلة لحساب المقاييس المختلفة التي ناقشناها من قبل. تقدم Scikit-Learn طريقة سهلة ومباشرة لإنشاء مصفوفة ارتباك. 

import matplotlib.pyplot as plt 
import seaborn as sns 
from sklearn import metrics


y_true = [0, 1, 2, 0, 1, 2, 0, 2, 2]
y_pred = [0, 2, 1, 0, 2, 1, 0, 0, 2]


# الحصول على مصفوفة الإرتباك من 
cm = metrics.confusion_matrix(y_true, y_pred)

plt.figure(figsize=(10,10))
cmap = sns.cubehelix_palette(50, hue=0.05, rot=0, light=0.9, dark=0, as_cmap=True)
sns.set(font_scale=2.5)
sns.heatmap(cm, annot=True, cmap=cmap, cbar=False)
plt.ylabel('Actual Labels', fontsize=20)
plt.xlabel('Predicted Labels', fontsize=20)

 التصنيف متعدد التسميات

إذن ، حتى الآن ، لقد تناولنا مقاييس التصنيف الثنائي والمتعدد الفئات. ثم يأتي نوع آخر من مشاكل التصنيف يسمى التصنيف متعدد التسميات (multi-label classification) . في التصنيف متعدد التسميات، يمكن أن تحتوي كل عينة على  تصنيف أو أكثر مرتبطة بها. أحد الأمثلة البسيطة على هذا النوع من المشاكل هو المهمة التي يُطلب منك فيها التنبؤ بأشياء مختلفة في صورة معينة.

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

مقاييس التقييم لمثل هذا النوع من مشاكل التصنيف مختلفة بعض الشيء. بعض المقاييس المناسبة والأكثر شيوعًا هي:

  •  الضبط عند K أو Average Precision at k بإختصار (P@k)
  • متوسط الضبط عند K أو Precision at k بإختصار (AP@kِ)
  •  متوسط الضبط المتوسط عند K أو Mean Precision at k بإختصار (MAP@kِ)
  •  خسارة اللوغاريتم (Log loss) 

الضبط عند K

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

إذا كان هذا محيرًا ، فسيصبح واضحًا مع الكود.

def pk(y_true, y_pred, k):
    
    # تساوي صفر ، فنرجع صفر مع العلم أنه لا يجب أن يحدث هذا k لو كانت
    # 1 دائما أكبر أو تساوي  k  لأن 
    
    if k == 0:
        return 0
    # top-k نحن مهتمون فقط في تنبوات 
    y_pred = y_pred[:k]
    # تحويل التنبوات لمجموعات
    pred_set = set(y_pred)
    # تحويل القيم الحقيقية لمجموعات
    true_set = set(y_true)
    # إيجاد القيم المتساوية
    common_values = pred_set.intersection(true_set)
    
    return len(common_values) / len(y_pred[:k])

 مع الكود ، يصبح كل شيء أسهل في الفهم.

متوسط الضبط عند K

الآن ، لدينا متوسط الضبط عند K  أو AP @ k.  و التي يتم حسابها باستخدام P @ k. على سبيل المثال ، إذا كان علينا حساب AP @ 3 ، فإننا نحسب AP @ 1 و AP @ 2 و AP @ 3 ثم نقسم المجموع على 3. 

لنرى كيفية تطبيق هذا .

def apk(y_true, y_pred, k):
    
    # p@k تهيئة قائمة القيم في 
    pk_values = []
    
    # k+1 من 1 إلى  k إنشاء حلقة لكل 
    for i in range(1 , k+1):
        # و إضافتها للقائم p@i حساب 
        pk_values.append(pk(y_true, y_pred, i))
    # لو لم يكن لدينا أي قيم في القائمة أرجع صفر
    if len(pk_values) == 0:
        return 0
    
    # أو نرجع مجموع القائمة على طول القائمة 
    return sum(pk_values) / len(pk_values)

 يمكن استخدام هاتين الوظيفتين لحساب متوسط  الضبط عند k (AP @ k) لقائمتين محددتين ؛ دعونا نرى كيف.

y_true = [[1, 2, 3],[0, 2], [1],
           [2, 3], [1, 0],[] ]
y_pred = [ [0, 1, 2],[1],[0, 2, 3],
           [2, 3, 4, 0], [0, 1, 2], [0] ]

for i in range(len(y_true)):
    for j in range(1,4):
        print(f"""y_true={y_true[i]},
              y_pred={y_pred[i]},
             AP@{j}={apk(y_true[i], y_pred[i], k=j)}""")

 إذن ، هذه هي الطريقة التي يمكننا بها حساب AP @ k لكل عينة. في تعلم الألخ، نحن مهتمون بجميع العينات ، ولهذا السبب لدينا متوسط الضبط المتوسط عند K أو MAP@k  وهو مجرد متوسط ​​AP@ k ويمكن حسابه بسهولة.

def mapk(y_true, y_pred, k):
    
    apk_values = []
    
    for i in range(len(y_true)):
        apk_values.append(
        apk(y_true[i], y_pred[i], k=k)
        )
    
    return sum(apk_values) / len(apk_values)

 الآن ، يمكننا حساب MAP @ k لـk=1, 2, 3 لنفس قائمة القوائم

In [X]: y_true = [
 ...: [1, 2, 3],
 ...: [0, 2],
 ...: [1],
 ...: [2, 3],
 ...: [1, 0],
 ...: []
 ...: ]
In [X]: y_pred = [
 ...: [0, 1, 2],
 ...: [1],
 ...: [0, 2, 3],
 ...: [2, 3, 4, 0],
 ...: [0, 1, 2],
 ...: [0]
 ...: ]
In [X]: mapk(y_true, y_pred, k=1)
Out[X]: 0.3333333333333333
In [X]: mapk(y_true, y_pred, k=2)
Out[X]: 0.375
In [X]: mapk(y_true, y_pred, k=3)
Out[X]: 0.3611111111111111
In [X]: mapk(y_true, y_pred, k=4)
Out[X]: 0.34722222222222215

تتراوح كل من P @ k و AP @ k و MAP @ k من 0 إلى 1 مع كون 1 هو الأفضل.

 يرجى ملاحظة أنه في بعض الأحيان قد ترى تطبيقات مختلفة لـ P @ k و AP @ k على الإنترنت. على سبيل المثال ، دعنا نلقي نظرة على أحد هذه التطبيقات. 

def apk(actual, predicted, k=10):
    
    if len(predicted)>k:
        predicted = predicted[:k]
    
    score = 0.0
    num_hits = 0.0
    
    for i, p in enumrate(predicted):
        if p in actual and p not in predicted[:i]:
            num_hits += 1.0
            score += num_hits / (i+1.0)
    
    if not actual:
        return 0.0
    
    return score / min(len(actual), k)

هذا التنفيذ هو إصدار آخر من AP @ k حيث يكون الترتيب مهمًا ونوازن التوقعات. سيكون لهذا التنفيذ نتائج مختلفة قليلاً عما قدمناه سابقاً.

خسارة اللوغاريتم 

 الآن ، نصل إلى خسارة اللوغاريتم لتصنيف متعدد التسميات. هذا سهل للغاية. يمكنك تحويل الأهداف إلى تنسيق ثنائي ثم استخدام خسارة اللوغاريتم  لكل عمود.

 في النهاية ، يمكنك أن تأخذ متوسط خسارة اللوغاريتم في كل عمود. يُعرف هذا أيضًا باسم متوسط ​​خسارة اللوغاريتم بالنسبة للعمود (mean column-wise log loss). بالطبع ، هناك طرق أخرى يمكنك من خلالها تنفيذ ذلك ، ويجب أن تستكشفها عندما تصادفها.

الإنحدار (Regression)

 لقد وصلنا الآن إلى مرحلة يمكننا فيها القول إننا نعرف الآن جميع مقاييس التصنيف الثنائية ومتعددة التصانيف ومتعددة التسميات، والآن يمكننا الانتقال إلى مقاييس الانحدار.

الخطأ (Error) 

المقياس الأكثر شيوعًا في الانحدار هو الخطأ. الخطأ بسيط وسهل الفهم.

 الخطأ = القيمة الحقيقية – الخطأ المطلق 

الخطأ المطلق هو مجرد القيمة المطلقة لقيمة أعلاه. 

الخطأ المطلق = ألقيمة المطلقة (القيمة الحقيقية – القيمة المتوقعة) 

ثم لدينا الخطأ المطلق المتوسط (mean absolute error)  أو بإختصار (MAE). إنه يعني فقط كل الأخطاء المطلقة.

def mean_absolute_error(y_true, y_pred):
    
    error = 0 
    
    for yt , yp in zip(y_true, y_pred):
        
        #حساب الخطأ المطلق و إضافة الخطأ
        error += np.abs(yt - yp)
    
    return error / len(y_true)

الخطأ التربيعي

وبالمثل ، لدينا خطأ تربيعي  (squared error) و متوسط خطأ تربيعي (mean squared error) أو بإختصار (MSE). 

الخطأ التربيعي  =  تربيع (القيمة الحقيقية – القيمة المتوقعة)

ويمكن تنفيذ الخطأ التربيعي المتوسط ​​(MSE) على النحو التالي. 

def mean_squared_error(y_true, y_pred):
    
    error = 0
    
    for yt, yp, in zip(y_true, y_pred):

        #حساب الخطأ التربيعي و إضافة الخطأ        
        error += (yt - yp)**2
        
    return error / len(y_true)

يعد MSE و RMSE (خطأ متوسط ​​الجذر التربيعي) أكثر المقاييس شيوعًا المستخدمة في تقييم نماذج الانحدار

RMSE = SQRT ( MSE )

 خطأ اللوغاريتم التربيعي

 نوع آخر من الأخطاء في نفس الفئة هو خطأ اللوغاريتم التربيعي (squared logarithmic error) . يسميها بعض الأشخاص SLE ، وعندما نأخذ متوسط ​​هذا الخطأ في جميع العينات ، يُعرف باسم متوسط الخطأ اللوغاريتمي التربيعي (mean squared logarithmic error) أو بإختصار MSLE  ويتم تنفيذه على النحو التالي.

def mean_squared_log_error(y_true, y_pred):
    
    error = 0 
    
    for yt , yp in zip( y_true, y_pred):
        
        error += (np.log( 1 + yt) - np.log(1 + yp)) ** 2
        
        return error / len(y_true)

الجذر التربيعي لمتوسط الخطأ اللوغاريتمي

الجذر التربيعي لمتوسط الخطأ اللوغاريتمي  (Root mean squared logarithmic error) هو مجرد جذر تربيعي لهذا. يُعرف أيضًا باسم RMSLE.

 ثم لدينا خطأ النسبة المئوية:

 النسبة المئوية للخطأ = ((القيمة الحقيقية – القيمة المتوقعة) / القيمة الحقيقية) * 100

 يمكن تحويل نفس النسبة إلى خطأ النسبة المئوية لجميع العينات. 

def mean_percentage_error(y_true, y_pred):
    
    error = 0 
    
    for yt, yp in zip(y_true, y_pred):
        
        error +=( yt - yp ) / yt
        
    return error / len(y_true)

وتُعرف النسخة المطلقة من نفس الإصدار (والإصدار الأكثر شيوعًا) بمتوسط نسبة الخطأ المطلق (mean absolute percentage error) أو MAPE. 

def mean_abs_percentage_error(y_true, y_pred):
    
    error = 0 
    
    for yt, yp in zip(y_true, y_pred):
        
        error = np.abs( yt - yp ) / yt
        
    return error / len(y_true)

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

أر تربيع 

دعنا نتحدث عن مقياس انحدار آخر يُعرف باسم R2  أو (R-squared) ، والمعروف أيضًا باسم معامل التحديد (coefficient of determination).

 بكلمات بسيطة ، يوضح R-squared مدى ملاءمة نموذجك للبيانات. يوضح R-squared الأقرب من 1.0 أن النموذج يناسب البيانات جيدًا ، بينما يعني الأقرب 0 أن النموذج ليس جيدًا. يمكن أن يكون R-squared أيضًا سالبًا عندما يقوم النموذج بعمل تنبؤات سخيفة. 

تظهر صيغة R-squared أدناه ،

 ولكن كما هو الحال دائمًا ، فإن تطبيق Python يجعل الأمور أكثر وضوحًا. 

def r2(y_true, y_pred):
    
    mean_true_value = np.mean(y_true)
    
    numerator = 0
    denominator = 0
    
    for yt , yp in zip(y_true, y_pred):
        
        numerator += (yt - yp ) ** 2 
        denominator += ( yt - mean_true_value)**2
        
    ratio = numerator / denominator
        
    return 1 - ratio

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

def mae_np(y_true, y_pred):
    return np.mean(np.abs(y_true - y_pred))

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

 ثم هناك بعض المقاييس المتقدمة. 

كابا الموزون من الدرجة الثانية (quadratic weighted kappa)

واحد منهم يستخدم على نطاق واسع هو كابا الموزون من الدرجة الثانية ، والمعروف أيضًا باسم QWK. يُعرف أيضًا باسم كوهين كابا. 

QWK يقيس “الاتفاق” بين “تصنيفين”. يمكن أن تكون التصنيفات أي أرقام حقيقية في 0 إلى N. والتنبؤات أيضًا في نفس النطاق. يمكن تعريف الاتفاقية على أنها مدى قرب هذه التصنيفات من بعضها البعض.

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

يتمتع Cohen’s kappa بتطبيق جيد في scikit-Learn ،

In [X]: from sklearn import metrics
In [X]: y_true = [1, 2, 3, 1, 2, 3, 1, 2, 3]
In [X]: y_pred = [2, 1, 3, 1, 2, 3, 3, 1, 2]
In [X]: metrics.cohen_kappa_score(y_true, y_pred, weights="quadratic")
Out[X]: 0.33333333333333337
In [X]: metrics.accuracy_score(y_true, y_pred)
Out[X]: 0.4444444444444444

يمكنك أن ترى أنه على الرغم من أن الدقة عالية ، إلا أن QWK أقل. يعتبر QWK الأكبر من 0.85 جيدًا جدًا!

معامل ارتباط ماثيو (Matthew’s Correlation Coefficient )

من المقاييس المهمة معامل ارتباط ماثيو (MCC).و الذي يتراوح  من -1 إلى 1. 1 هو توقع مثالي ، و -1 هو تنبؤ غير كامل ، و 0 هو توقع عشوائي. صيغة MCC بسيطة للغاية.

نرى أن MCC يأخذ في الاعتبار TP و FP و TN و FN  وبالتالي يمكن استخدامه للمشكلات التي تكون فيها الفئات منحرفة . يمكنك تنفيذه بسرعة في Python باستخدام ما نفذناه بالفعل.

def mcc(y_true, y_pred):
    
    tp = true_positive(y_true, y_pred)
    tn = true_negative(y_true, y_pred)
    fp = false_positive(y_true, y_pred)
    fn = false_negative(y_true, y_pred)
    
    numerator = (tp * tn ) - (fp * fn)
    
    denominator = (
        (tp + fp) *
        (fn + tn) *
        (fp + tn) *
        (tp + fn) 
    )
    
    denominator = denominator ** 0.5
    
    return numerator/denominator

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

إضافة تعليق