الدرس 4 من 9

تقييم الموديل صح

أهم درس عشان متخدعش نفسك ولا تخدع مديرك.

فخ الـ Accuracy

بنك عنده ١٠٠٠٠ معاملة، منهم ٥٠ بس احتيال. لو عملت «موديل» بيقول على كل حاجة «سليمة»، هيبقى دقيق بنسبة ٩٩.٥٪! ومع ذلك مالوش أي لازمة، لأنه مامسكش ولا عملية احتيال.

accuracy_trap.py
import numpy as np
from sklearn.metrics import accuracy_score, recall_score

y_true = np.array([1] * 50 + [0] * 9950)   # 50 frauds out of 10,000
y_lazy = np.zeros(10_000)                   # "model" that always says: not fraud

print(f"Accuracy: {accuracy_score(y_true, y_lazy):.1%}")
print(f"Frauds caught: {recall_score(y_true, y_lazy):.0%}")

الـ Confusion Matrix

جدول بيوريك الموديل صاب فين وغلط فين بالظبط، مش رقم واحد مجمّع:

الموديل قال: هيمشيالموديل قال: هيفضل
فعلاً مشي✓ True Positive✗ False Negative (فاتنا)
فعلاً فضل✗ False Positive (إنذار كاذب)✓ True Negative
confusion.py
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import ConfusionMatrixDisplay

df = pd.read_csv("churn.csv")
df["yearly"] = (df["contract"] == "yearly").astype(int)
features = ["tenure", "bill", "complaints", "data_gb", "yearly"]
X_train, X_test, y_train, y_test = train_test_split(
    df[features], df["churned"], test_size=0.2,
    random_state=42, stratify=df["churned"])
model = LogisticRegression(max_iter=1000).fit(X_train, y_train)

ConfusionMatrixDisplay.from_estimator(
    model, X_test, y_test, display_labels=["stayed", "churned"], cmap="Blues")
plt.title("Churn model on test set")
plt.show()

Precision و Recall

precision من اللي قلت عليهم «هيمشوا»، كام واحد مشي فعلاً؟ بتقيس الإنذارات الكاذبة.
recall من اللي مشيوا فعلاً، مسكت كام واحد؟ بتقيس اللي فاتك.
F1 رقم واحد بيوازن بين الاتنين.
report.py
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

df = pd.read_csv("churn.csv")
df["yearly"] = (df["contract"] == "yearly").astype(int)
features = ["tenure", "bill", "complaints", "data_gb", "yearly"]
X_train, X_test, y_train, y_test = train_test_split(
    df[features], df["churned"], test_size=0.2,
    random_state=42, stratify=df["churned"])
model = LogisticRegression(max_iter=1000).fit(X_train, y_train)

print(classification_report(y_test, model.predict(X_test),
                            target_names=["stayed", "churned"]))

الموازنة: غيّر الـ threshold

لو نزّلت الحد، هتمسك ناس أكتر (recall يزيد) بس هتكلم ناس مكانوش هيمشوا (precision يقل). جرب:

threshold = 0.5
# precision = 0.68   recall = 0.42
# flagged: 44 of 300 customers

الافتراضي. إنذارات كاذبة قليلة، بس فاتنا عدد كبير من اللي مشيوا.

🩺 اختار حسب التكلفةفي تشخيص مرض خطير، recall أهم: متفوتش عيان حتى لو قلقت ناس سليمة. في فلتر spam، precision أهم: إيميل شغل مهم يروح spam أسوأ من إعلان يعدي. مفيش رقم صح لكل المشاكل، فيه رقم صح لمشكلتك.
الدرس اللي فات