Machine Learning Academy · درس

منحنيات ROC وAUC-ROC

ارسم منحنى ROC بتغيير عتبة القرار، واحسب AUC، وفسّره باعتباره احتمال أن تتفوق نتيجة إيجابية عشوائية على نتيجة سلبية عشوائية

الدرس 2 من 413 خطوة

منحنيات ROC وAUC-ROC درس مجاني في Machine Learning Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Machine Learning Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Machine Learning Academy 4 دروس في المجموع.

حدود المقاييس ذات العتبة الثابتة

تعتمد الدقة الإيجابية والاستدعاء ودرجة F1 جميعها على عتبة قرار ثابتة (تكون عادةً 0.5 للمصنفات الثنائية). لكن العتبة المثلى تختلف باختلاف التطبيق: فقد يستخدم مرشح الرسائل المزعجة 0.9 (عتبة صارمة لتجنب الإيجابيات الكاذبة)، بينما قد يستخدم كاشف الاحتيال 0.1 (عتبة متساهلة لتجنب تفويت حالات الاحتيال). ويعطي تقييم النموذج عند عتبة واحدة صورة غير مكتملة عن قدراته. يحل منحنى ROC (خاصية تشغيل المستقبل) هذه المشكلة بعرض الأداء عند جميع العتبات الممكنة في الوقت نفسه، مما يتيح لكم فهم النطاق الكامل للمفاضلات بين الدقة الإيجابية والاستدعاء التي يستطيع النموذج تحقيقها.

from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import precision_score, recall_score

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)

clf = LogisticRegression(max_iter=10000)
clf.fit(X_tr, y_tr)
proba = clf.predict_proba(X_te)[:, 1]

for t in [0.1, 0.3, 0.5, 0.7, 0.9]:
    y_pred = (proba >= t).astype(int)
    print(f'thresh={t}: prec={precision_score(y_te,y_pred,zero_division=0):.3f}, '
          f'rec={recall_score(y_te,y_pred,zero_division=0):.3f}')

معدل الإيجابيات الحقيقية ومعدل الإيجابيات الكاذبة

يُبنى منحنى ROC من مقياسين يُحسبان عند كل عتبة: معدل الإيجابيات الحقيقية (TPR) (وهو نفسه الاستدعاء/الحساسية): TPR = TP / (TP + FN) — ما نسبة الإيجابيات الفعلية التي اكتشفناها؟ ومعدل الإيجابيات الكاذبة (FPR): FPR = FP / (FP + TN) — ما نسبة السلبيات الفعلية التي صنّفناها خطأً على أنها إيجابية؟ عند خفض العتبة، يزداد كل من TPR وFPR. ويرسم منحنى ROC قيمة TPR مقابل FPR مع تغير العتبة من 1 (عدم التنبؤ بأي حالة إيجابية) إلى 0 (التنبؤ بأن جميع الحالات إيجابية). ويصل المصنف المثالي إلى النقطة (0, 1) — أي لا إنذارات كاذبة مع اكتشاف جميع الإيجابيات الحقيقية.

import numpy as np
from sklearn.metrics import confusion_matrix

def tpr_fpr(y_true, y_pred):
    TN, FP, FN, TP = confusion_matrix(y_true, y_pred).ravel()
    tpr = TP / (TP + FN)   # Recall = sensitivity
    fpr = FP / (FP + TN)   # False positive rate = 1 - specificity
    return tpr, fpr

# Example predictions at different thresholds
y_true = np.array([1,1,1,0,0,0,0,0,0,0])

for thresh in [0.3, 0.5, 0.7]:
    # Simulated probabilities
    proba = np.array([0.9, 0.8, 0.4, 0.6, 0.5, 0.3, 0.2, 0.1, 0.05, 0.01])
    y_pred = (proba >= thresh).astype(int)
    tpr, fpr = tpr_fpr(y_true, y_pred)
    print(f'thresh={thresh}: TPR={tpr:.2f}, FPR={fpr:.2f}')

رسم منحنى ROC

تحسب roc_curve() في Scikit-learn أزواج (FPR, TPR) عبر جميع العتبات باستدعاء واحد. وتنشئ RocCurveDisplay رسمًا جاهزًا للنشر. يكون منحنى ROC للمصنف العشوائي خطًا قطريًا من (0,0) إلى (1,1)، إذ لا يحقق أداءً أفضل من الصدفة عند أي عتبة. وينحني المصنف الجيد نحو الزاوية العلوية اليسرى، محققًا TPR مرتفعًا مع FPR منخفض. وكلما ابتعد المنحنى عن الخط القطري، كان المصنف أفضل. وتلخّص المساحة الواقعة تحت هذا المنحنى (AUC) الأداء في رقم واحد.

from sklearn.metrics import roc_curve, RocCurveDisplay
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)

clf = LogisticRegression(max_iter=10000)
clf.fit(X_tr, y_tr)

RocCurveDisplay.from_estimator(clf, X_te, y_te)
plt.plot([0,1],[0,1],'k--', label='Random classifier')
plt.title('ROC Curve')
plt.legend()
plt.show()

AUC-ROC: المساحة تحت المنحنى

تلخّص AUC-ROC (المساحة تحت منحنى ROC) منحنى ROC في رقم واحد يتراوح بين 0 و1. AUC = 0.5: ليس أفضل من العشوائي (خط قطري). AUC = 1.0: مصنف مثالي (لا إيجابيات كاذبة عند أي مستوى من الاستدعاء). AUC = 0.0: مصنف عكسي مثالي — كل تنبؤاته خاطئة (وهو أمر مفيد إذا عكستم التنبؤات). وتعني AUC تساوي 0.8 أن العينة الإيجابية المختارة عشوائيًا تحصل في 80% من الحالات على احتمال متنبأ به أعلى من الاحتمال الذي تحصل عليه عينة سلبية مختارة عشوائيًا. وتُعد AUC مستقلة عن العتبة — فهي تقيّم جودة ترتيب درجات الاحتمال، لا قرار تنبؤ محددًا.

from sklearn.metrics import roc_auc_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)

clf = LogisticRegression(max_iter=10000)
clf.fit(X_tr, y_tr)
proba = clf.predict_proba(X_te)[:, 1]

auc = roc_auc_score(y_te, proba)
print(f'AUC-ROC: {auc:.4f}')

# Interpretation: AUC = P(score(pos) > score(neg))
import numpy as np
pos_scores = proba[y_te == 1]
neg_scores = proba[y_te == 0]
mc_auc = np.mean([p > n for p in pos_scores for n in neg_scores])
print(f'Monte Carlo AUC: {mc_auc:.4f}')  # Should match roc_auc_score

تفسير قيم AUC عمليًا

إرشادات تفسير AUC: 0.5 = مصنف عشوائي، عديم الفائدة؛ 0.6-0.7 = ضعيف، لكنه أفضل من الصدفة؛ 0.7-0.8 = مقبول — مناسب لبعض التطبيقات؛ 0.8-0.9 = جيد — نموذج قوي للاستخدام في بيئة الإنتاج؛ 0.9-1.0 = ممتاز — ومن المرجح أن يكون قريبًا من أحدث ما توصل إليه المجال في هذه المشكلة. احذروا من تضخيم AUC: فقد يؤدي تسرب البيانات الزمنية (استخدام معلومات مستقبلية)، أو تسرب التسميات، أو عدم توازن الفئات بدرجة كبيرة إلى تضخيم AUC اصطناعيًا. تحققوا دائمًا من سلامة النتائج باستخدام منحنيات المعايرة وفحص التنبؤات على أمثلة محددة.

# AUC interpretation guide
auc_guide = [
    (0.50, 0.60, 'Random to poor'),
    (0.60, 0.70, 'Poor but predictive'),
    (0.70, 0.80, 'Fair'),
    (0.80, 0.90, 'Good'),
    (0.90, 1.00, 'Excellent'),
]

for low, high, label in auc_guide:
    print(f'AUC [{low:.2f}, {high:.2f}): {label}')

# Note: domain matters -- AUC 0.75 might be excellent
# for predicting disease 10 years in advance but poor
# for predicting email spam from clear signals

مقارنة نماذج متعددة على منحنى ROC

يتيح وضع عدة منحنيات ROC على الرسم نفسه مقارنة النماذج مباشرةً. يظهر منحنى كل نموذج وقيمة AUC الخاصة به معًا. يكون النموذج أفضل إذا كان منحنى ROC الخاص به أعلى من منحنى نموذج آخر بشكل منتظم عند كل قيمة من FPR. إذا تقاطعت المنحنيات، فلا يهيمن أي من النموذجين على الآخر — يكون أحدهما أفضل عند معدلات الإيجابيات الكاذبة المنخفضة، بينما يكون الآخر أفضل عند المعدلات المرتفعة، ويحدد سياق العمل أيهما يُفضّل. تُعد مقارنة AUC ملخصًا سريعًا، لكن احرص دائمًا على فحص المنحنيات عند نقطة التشغيل التي تنوي استخدامها فعليًا.

from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

models = [
    ('Logistic Reg', LogisticRegression(max_iter=1000)),
    ('Decision Tree', DecisionTreeClassifier(max_depth=5)),
    ('KNN', KNeighborsClassifier(n_neighbors=5)),
]

for name, model in models:
    model.fit(StandardScaler().fit_transform(X_tr) if name!='Decision Tree' else X_tr, y_tr)
    proba = model.predict_proba(X_te)[:, 1]
    fpr, tpr, _ = roc_curve(y_te, proba)
    auc = roc_auc_score(y_te, proba)
    plt.plot(fpr, tpr, label=f'{name} (AUC={auc:.3f})')

plt.plot([0,1],[0,1],'k--')
plt.legend()
plt.show()

منحنى Precision-Recall: الأفضل للبيانات غير المتوازنة

بالنسبة إلى مجموعات البيانات غير المتوازنة بدرجة كبيرة، قد يكون منحنى ROC متفائلًا على نحو مضلل. فعندما يكون عدد الحالات الإيجابية قليلًا جدًا (مثلًا، عندما يكون معدل الاحتيال 1%)، يحقق حتى النموذج الذي ينتج عددًا كبيرًا من الإيجابيات الكاذبة معدل FPR منخفضًا، لأن المقام (TN+FP) ضخم. يرسم منحنى Precision-Recall الدقة مقابل الاستدعاء عند عتبات مختلفة، ولا يتأثر بعدم توازن الفئات. وتُعد المساحة تحت منحنى PR (أي Average Precision أو AP) مقياسًا ملخصًا أفضل للمشكلات غير المتوازنة. استخدم ROC للفئات المتوازنة، ومنحنى Precision-Recall للفئات غير المتوازنة.

from sklearn.metrics import PrecisionRecallDisplay, average_precision_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)

clf = LogisticRegression(max_iter=10000)
clf.fit(X_tr, y_tr)
proba = clf.predict_proba(X_te)[:, 1]

ap = average_precision_score(y_te, proba)
print(f'Average Precision (AP): {ap:.4f}')

PrecisionRecallDisplay.from_estimator(clf, X_te, y_te)
plt.title(f'Precision-Recall Curve (AP={ap:.3f})')
plt.show()

AUC في التحقق المتقاطع

للحصول على تقدير موثوق لـ AUC لا ينحاز بسبب تقسيم واحد إلى بيانات تدريب واختبار، استخدم cross_val_score مع scoring='roc_auc'. يحسب هذا قيمة AUC على مجموعة التحقق في كل طية ويعيد درجات جميع الطيات. المتوسط هو أفضل تقدير، بينما يوضح الانحراف المعياري مدى الاستقرار. تشير قيمة متوسط AUC مرتفعة مع انحراف معياري منخفض إلى نموذج متين. أما ارتفاع AUC مع ارتفاع الانحراف المعياري فيشير إلى حساسية النموذج لنوع العينات التي تظهر في كل طية — لذا تحقّق مما إذا كانت البيانات تتضمن مجموعات طبيعية (مثل وجود عينات متعددة لكل مريض) ينبغي إبقاؤها معًا في الطيات.

from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_breast_cancer
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline

X, y = load_breast_cancer(return_X_y=True)

pipe = Pipeline([
    ('sc', StandardScaler()),
    ('clf', LogisticRegression(max_iter=1000))
])

aucs = cross_val_score(pipe, X, y, cv=10, scoring='roc_auc')
print(f'AUC per fold: {aucs.round(3)}')
print(f'Mean AUC: {aucs.mean():.4f}')
print(f'Std AUC:  {aucs.std():.4f}')

تحديد نقطة التشغيل على منحنى ROC

بعد تقييم النموذج باستخدام منحنى ROC، يجب اختيار نقطة تشغيل محددة (أي عتبة) لاستخدامها في بيئة الإنتاج. توجد ثلاث استراتيجيات: (1) إحصائية J الخاصة بـ Youden: اختر العتبة التي تزيد (TPR - FPR) إلى أقصى حد — أي النقطة الأبعد فوق القطر. (2) قيد متعلق بالعمل: حدّد الحد الأقصى المسموح به لـ FPR (مثلًا، وضع علامة على 5% كحد أقصى من المعاملات المشروعة باعتبارها معاملات احتيالية) واعثر على العتبة المقابلة. (3) تحسين التكلفة: إذا كنت تعرف تكلفة FP وFN، فاختر العتبة التي تقلل التكلفة الإجمالية إلى أدنى حد. وثّق العتبة المختارة مع النموذج لضمان نشر قابل لإعادة الإنتاج.

from sklearn.metrics import roc_curve
import numpy as np

fpr, tpr, thresholds = roc_curve(y_te, proba)

# Strategy 1: Youden's J (max TPR - FPR)
youden_j = tpr - fpr
best_idx = np.argmax(youden_j)
best_threshold = thresholds[best_idx]
print(f'Youden threshold: {best_threshold:.3f}')
print(f'TPR={tpr[best_idx]:.3f}, FPR={fpr[best_idx]:.3f}')

# Strategy 2: Max TPR with FPR <= 0.05
allowed_fpr = 0.05
mask = fpr <= allowed_fpr
idx = np.where(mask)[0][-1]  # Highest TPR satisfying FPR constraint
print(f'\nAt FPR<={allowed_fpr}: TPR={tpr[idx]:.3f}, threshold={thresholds[idx]:.3f}')

ROC-AUC متعدد الفئات

في تصنيف متعدد الفئات، يتم توسيع ROC-AUC بحساب AUC لكل فئة ضمن إعداد One-vs-Rest (OvR): اعتبر الفئة k موجبة وجميع الفئات الأخرى سالبة، ثم احسب AUC وبعد ذلك احسب المتوسط عبر الفئات. يدعم Scikit-learn ذلك باستخدام roc_auc_score مع multi_class='ovr' وaverage='macro' أو average='weighted'. ويتطلب هذا تقديرات احتمالية من predict_proba()، ولذلك يجب أن يدعم المصنّف إخراج الاحتمالات. يعامل Macro AUC جميع الفئات بالتساوي، بينما يراعي weighted AUC تواتر الفئات.

from sklearn.metrics import roc_auc_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

X, y = load_iris(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, random_state=42)

clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_tr, y_tr)
proba_all = clf.predict_proba(X_te)  # Shape: (n_samples, n_classes)

auc_macro    = roc_auc_score(y_te, proba_all, multi_class='ovr', average='macro')
auc_weighted = roc_auc_score(y_te, proba_all, multi_class='ovr', average='weighted')

print(f'Macro AUC (OvR):    {auc_macro:.4f}')
print(f'Weighted AUC (OvR): {auc_weighted:.4f}')

AUC لمجموعات البيانات غير المتوازنة: تحذير

قد تكون AUC-ROC متفائلة على نحو مضلل في مجموعات البيانات غير المتوازنة بشدة. فعندما لا تتجاوز المعاملات الاحتيالية 0.1%، يحقق حتى النموذج الذي يكتشف 80% من حالات الاحتيال مع وضع علامة على 5% من المعاملات المشروعة قيمة AUC تقترب من 0.9 — لكن وضع علامة على 5% من ملايين المعاملات المشروعة يسبب تكلفة تشغيلية هائلة من الناحية المطلقة. في مثل هذه الحالات، تكون AUC-PR (المساحة تحت منحنى Precision-Recall) أكثر إفادة، لأنها تركز فقط على أداء الفئة الإيجابية ولا تتضخم بسبب العدد الكبير من الحالات السلبية الحقيقية. عند عدم التوازن الشديد (معدل إيجابيات <1%)، أبلغ دائمًا عن AUC-PR إلى جانب AUC-ROC.

from sklearn.metrics import roc_auc_score, average_precision_score
from sklearn.linear_model import LogisticRegression
import numpy as np

np.random.seed(42)
# Extremely imbalanced: 1% positive rate
n_neg, n_pos = 9900, 100
X = np.vstack([np.random.randn(n_neg, 5),
               np.random.randn(n_pos, 5) + 1.5])
y = np.array([0]*n_neg + [1]*n_pos)

clf = LogisticRegression(class_weight='balanced', max_iter=1000)
clf.fit(X, y)
proba = clf.predict_proba(X)[:, 1]

auc_roc = roc_auc_score(y, proba)
auc_pr  = average_precision_score(y, proba)

print(f'AUC-ROC: {auc_roc:.4f} (looks great!)')
print(f'AUC-PR:  {auc_pr:.4f} (more honest about minority class)')

اختبار سريع

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

مراجعة الدرس

تعلمت في هذا الدرس أن منحنى ROC يرسم TPR مقابل FPR عبر جميع العتبات ويعرض النطاق الكامل للمفاضلة بين الدقة والاستدعاء، وأن AUC-ROC تلخص جودة الترتيب في رقم واحد، حيث تمثل 0.5 نتيجة عشوائية و1.0 نتيجة مثالية، وأنه بالنسبة إلى الفئات غير المتوازنة، يُستخدم منحنى Precision-Recall وAverage Precision بدلًا من ذلك. ننتقل بعد ذلك إلى استكشاف مقاييس الانحدار، بما في ذلك MAE وMSE وRMSE وR-squared.

البدء مجانًا

تعلم Python مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
30
الدروس
120

الأسئلة الشائعة

هل درس «منحنيات ROC وAUC-ROC» مجاني؟

نعم — نص درس «منحنيات ROC وAUC-ROC» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Machine Learning Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Machine Learning Academy 4 دروس في المجموع.

ماذا ستتعلم في «منحنيات ROC وAUC-ROC»؟

ارسم منحنى ROC بتغيير عتبة القرار، واحسب AUC، وفسّره باعتباره احتمال أن تتفوق نتيجة إيجابية عشوائية على نتيجة سلبية عشوائية تتمرن على Machine Learning Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Machine Learning Academy؟

لا تُشترط خبرة سابقة. Machine Learning Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «منحنيات ROC وAUC-ROC»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Machine Learning Academy هذا؟

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

جميع الدروس في هذه الدورة

  1. مقاييس التصنيف: Accuracy وPrecision وRecall وF1
  2. منحنيات ROC وAUC-ROC
  3. مقاييس الانحدار: MAE وMSE وRMSE وR-Squared
  4. اختيار المقياس المناسب لمشكلتكم التجارية
← العودة إلى Machine Learning Academy