الرئيسية قاعدة المعرفة أسس الذكاء الاصطناعي تقييم النماذج: كيف تعرف أن نموذجك يعمل فعلاً؟
أسس الذكاء الاصطناعي

تقييم النماذج: كيف تعرف أن نموذجك يعمل فعلاً؟

لماذا لا تكفي الدقة وحدها؟

إذا كان 99% من المنتجات سليمة و1% معيبة، فنموذج يقول "كل شيء سليم" دائماً سيحقق دقة 99% ولكنه عديم الفائدة تماماً. هذا شائع جداً في التطبيقات الصناعية حيث الأعطال والعيوب نادرة.

import numpy as np
import pandas as pd
from sklearn.metrics import accuracy_score

# محاكاة: 1000 منتج، 10 معيبة فقط
np.random.seed(42)
y_true = np.array([0] * 990 + [1] * 10)  # 0=سليم، 1=معيب

# نموذج غبي: يقول "سليم" دائماً
y_pred_dummy = np.zeros(1000)

# نموذج ذكي: يكتشف 7 من 10 عيوب
y_pred_smart = np.zeros(1000)
y_pred_smart[990:997] = 1  # اكتشف 7 عيوب
y_pred_smart[50] = 1       # إنذار كاذب واحد

print(f"دقة النموذج الغبي: {accuracy_score(y_true, y_pred_dummy):.1%}")
print(f"دقة النموذج الذكي: {accuracy_score(y_true, y_pred_smart):.1%}")
print("الدقة متقاربة لكن الفرق في القيمة العملية هائل!")

مصفوفة الالتباس: الصورة الكاملة

مصفوفة الالتباس تُظهر أربعة أنواع من النتائج:

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt

# حساب مصفوفة الالتباس للنموذج الذكي
cm = confusion_matrix(y_true, y_pred_smart)
print("مصفوفة الالتباس:")
print(f"  صحيح سلبي (TN): {cm[0][0]} - منتج سليم تم تمريره بشكل صحيح")
print(f"  إيجابي كاذب (FP): {cm[0][1]} - منتج سليم تم رفضه خطأً")
print(f"  سلبي كاذب (FN): {cm[1][0]} - منتج معيب تم تمريره خطأً")
print(f"  صحيح إيجابي (TP): {cm[1][1]} - منتج معيب تم اكتشافه بنجاح")

# رسم مصفوفة الالتباس
fig, ax = plt.subplots(figsize=(6, 5))
disp = ConfusionMatrixDisplay(cm, display_labels=['سليم', 'معيب'])
disp.plot(ax=ax, cmap='Blues')
ax.set_title('مصفوفة الالتباس - نظام فحص الجودة')
plt.tight_layout()
plt.savefig('confusion_matrix.png', dpi=150)
plt.show()

التكلفة الصناعية لكل نوع خطأ

  • إيجابي كاذب (FP): رفض منتج سليم = خسارة مادية صغيرة
  • سلبي كاذب (FN): تمرير منتج معيب = خسارة كبيرة (شكاوى عملاء، إعادة استدعاء)

الدقة والاستدعاء ومقياس F1

ثلاثة مقاييس تكمل بعضها في تقييم المصنف:

from sklearn.metrics import precision_score, recall_score, f1_score, classification_report

# بناء نموذج فحص جودة أكثر واقعية
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# بيانات فحص جودة
np.random.seed(42)
n = 2000
features = pd.DataFrame({
    'dimension_error': np.abs(np.random.normal(0, 0.1, n)),
    'surface_defects': np.random.poisson(0.3, n),
    'hardness_deviation': np.abs(np.random.normal(0, 2, n)),
    'weight_error': np.abs(np.random.normal(0, 0.05, n))
})

# المنتجات المعيبة
is_defective = (
    (features['dimension_error'] > 0.2) |
    (features['surface_defects'] > 1) |
    (features['hardness_deviation'] > 4)
).astype(int)

X_train, X_test, y_train, y_test = train_test_split(
    features, is_defective, test_size=0.3, random_state=42
)

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

# المقاييس التفصيلية
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)

print(f"الدقة (Precision): {precision:.4f}")
print(f"  من كل 100 منتج رفضناه، {precision*100:.0f} كانوا فعلاً معيبين")
print(f"\nالاستدعاء (Recall): {recall:.4f}")
print(f"  من كل 100 منتج معيب، اكتشفنا {recall*100:.0f} منهم")
print(f"\nمقياس F1: {f1:.4f}")
print(f"  المتوسط التوافقي بين الدقة والاستدعاء")

متى نركز على أي مقياس؟

print("\nدليل اختيار المقياس في الصناعة:")
print("-" * 50)
print("الاستدعاء العالي مهم عندما:")
print("  - فحص سلامة الأغذية أو الأدوية")
print("  - اكتشاف تسريبات الغاز")
print("  - فحص القطع الحرجة في الطيران")
print("\nالدقة العالية مهمة عندما:")
print("  - تكلفة إعادة الفحص عالية")
print("  - الإنذارات الكاذبة تسبب توقف الإنتاج")
print("  - طاقة الفحص اليدوي محدودة")

التحقق المتقاطع: اختبار أقوى

التقسيم العشوائي مرة واحدة قد يكون محظوظاً. التحقق المتقاطع يختبر النموذج عدة مرات:

from sklearn.model_selection import cross_val_score, StratifiedKFold

# التحقق المتقاطع 5 طيات مع الحفاظ على نسبة الفئات
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

# تقييم عدة مقاييس
for metric in ['accuracy', 'precision', 'recall', 'f1']:
    scores = cross_val_score(model, features, is_defective, cv=cv, scoring=metric)
    print(f"{metric:12s}: {scores.mean():.4f} (+/- {scores.std():.4f})")

# مقارنة خوارزميات مختلفة
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC

models_to_compare = {
    'شجرة القرار': DecisionTreeClassifier(max_depth=5, random_state=42),
    'الغابة العشوائية': RandomForestClassifier(n_estimators=100, random_state=42),
}

print("\nمقارنة شاملة بالتحقق المتقاطع (F1):")
print("-" * 45)
for name, mdl in models_to_compare.items():
    scores = cross_val_score(mdl, features, is_defective, cv=cv, scoring='f1')
    print(f"  {name:20s}: {scores.mean():.4f} (+/- {scores.std():.4f})")

الإفراط في التعلم: عندما يحفظ النموذج بدلاً من أن يتعلم

الإفراط في التعلم (Overfitting) يعني أن النموذج حفظ بيانات التدريب بدلاً من تعلم الأنماط العامة:

from sklearn.model_selection import learning_curve

# رسم منحنى التعلم لكشف الإفراط
train_sizes, train_scores, test_scores = learning_curve(
    RandomForestClassifier(n_estimators=50, max_depth=10, random_state=42),
    features, is_defective, cv=5,
    train_sizes=np.linspace(0.1, 1.0, 10),
    scoring='f1'
)

plt.figure(figsize=(10, 5))
plt.plot(train_sizes, train_scores.mean(axis=1), 'o-', label='أداء التدريب')
plt.plot(train_sizes, test_scores.mean(axis=1), 'o-', label='أداء الاختبار')
plt.fill_between(train_sizes,
                 test_scores.mean(axis=1) - test_scores.std(axis=1),
                 test_scores.mean(axis=1) + test_scores.std(axis=1),
                 alpha=0.1)
plt.xlabel('حجم بيانات التدريب')
plt.ylabel('مقياس F1')
plt.title('منحنى التعلم: كشف الإفراط في التعلم')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('learning_curve.png', dpi=150)
plt.show()

علامات الإفراط في التعلم

  • فجوة كبيرة بين أداء التدريب وأداء الاختبار
  • أداء التدريب قريب من 100% لكن الاختبار أقل بكثير

علاج الإفراط في التعلم

# مقارنة عمق الشجرة وتأثيره على الإفراط
print("تأثير عمق الشجرة على الأداء:")
print(f"{'العمق':<10} {'تدريب F1':<15} {'اختبار F1'}")
print("-" * 40)

for depth in [2, 4, 6, 10, 20, None]:
    mdl = RandomForestClassifier(n_estimators=50, max_depth=depth, random_state=42)
    mdl.fit(X_train, y_train)
    train_f1 = f1_score(y_train, mdl.predict(X_train))
    test_f1 = f1_score(y_test, mdl.predict(X_test))
    label = str(depth) if depth else 'بلا حد'
    print(f"  {label:<10} {train_f1:.4f}{'':<9} {test_f1:.4f}")

مثال عملي: تقييم نموذج فحص جودة

سنبني ونقيّم نظام فحص جودة شامل:

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import classification_report, f1_score
import matplotlib.pyplot as plt

# بيانات فحص 5000 قطعة مع 8 قياسات
np.random.seed(42)
n = 5000
inspection = pd.DataFrame({
    'length': np.random.normal(100, 0.2, n),
    'width': np.random.normal(50, 0.15, n),
    'height': np.random.normal(25, 0.1, n),
    'weight': np.random.normal(200, 2, n),
    'roughness': np.random.exponential(0.3, n),
    'roundness': np.random.normal(0.98, 0.01, n),
    'crack_score': np.random.exponential(0.1, n),
    'color_delta': np.random.exponential(0.5, n)
})

# تصنيف: معيب إذا تجاوز أي قياس الحدود
defective = (
    (inspection['roughness'] > 0.8) |
    (inspection['crack_score'] > 0.4) |
    (inspection['roundness'] < 0.96)
).astype(int)

print(f"نسبة المعيب: {defective.mean()*100:.1f}%")

X_train, X_test, y_train, y_test = train_test_split(
    inspection, defective, test_size=0.25, random_state=42, stratify=defective
)

# بناء وتقييم النموذج
model = RandomForestClassifier(n_estimators=200, max_depth=8, random_state=42)
model.fit(X_train, y_train)

# تقرير شامل
y_pred = model.predict(X_test)
print("\n" + "=" * 50)
print("تقرير التقييم الشامل")
print("=" * 50)
print(classification_report(y_test, y_pred, target_names=['سليم', 'معيب']))

# التحقق المتقاطع
cv_scores = cross_val_score(model, inspection, defective, cv=5, scoring='f1')
print(f"F1 بالتحقق المتقاطع: {cv_scores.mean():.4f} (+/- {cv_scores.std():.4f})")
print(f"النموذج {'مستقر' if cv_scores.std() < 0.03 else 'غير مستقر'} عبر الطيات")

الخلاصة

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

evaluation accuracy recall confusion-matrix cross-validation overfitting تقييم النماذج الدقة الاستدعاء مصفوفة الالتباس التحقق المتقاطع الإفراط في التعلم