ML Learning Hub
تطبيقيمتوسط

أهمية الميزات والاختيار

اعرف الميزات التي يعتمد عليها نموذجك فعلاً — ثم ثق به أكثر (أو أقل)

أهمية التبديل مقابل أهمية عدم النقاء ونسب SHAP الموحدة — كيف تُفسر نموذجك وتكتشف أي الميزات تُحدث فعلاً فارقاً في التنبؤات.

35 min
6 مخططات
6 المفاهيم المغطاة

المتطلبات الأساسية

Random Forest
Gradient Boosting

المفاهيم المغطاة

Permutation ImportanceGini ImportanceSHAPDrop-ColumnFeature SelectionCorrelation Bias

الصيغ الرئيسية

أهمية التبديل

انخفاض الدقة عند خلط الميزة j عشوائياً — مستقل عن النموذج، يعمل بعد التدريب

أهمية شوائب جيني

تناقص الشوائب الموزون عبر جميع تقسيمات الميزة j — سريع لكن متحيز نحو الأساس

SHAP (النواة)

قيمة Shapley: المساهمة الهامشية المتوسطة لكل ميزة عبر جميع تحالفات الميزات

أهمية حذف العمود

المعيار الذهبي لكنه مكلف — إعادة تدريب مرة واحدة لكل ميزة

محاكاة تفاعلية

Loading visualization…
🎯

لماذا أهمية الميزات غير قابلة للتفاوض

motivation

نماذج التعلم الآلي غالباً ما تكون صناديق سوداء — تنتج مخرجات لكنها تخفي منطقها. تكشف أساليب أهمية الميزات عن هذا الغموض. تجيب على: ما المدخلات التي يعتمد عليها النموذج أكثر؟ يهم هذا لثلاثة أسباب: (1) التصحيح: إذا كان نموذجك يعتمد بشدة على 'bruit_aléatoire' فلديك مشكلة تسرب بيانات. (2) الثقة: يجب أن يفهم المنظمون والأطباء ومسؤولو الائتمان قرارات النموذج — تفرض المادة 22 من GDPR قابلية التفسير للقرارات الآلية. (3) اختيار الميزات: تُوجّه درجات الأهمية تخفيض الأبعاد. حذف الميزات غير المهمة يقلل تكلفة الاستدلال ويمنع الإفراط في التخصيص.

نموذج تسجيل الائتمان الذي يعتمد بشدة على الرمز_البريدي قد يبدو عادلاً على بيانات التدريب لكنه يُعدّ وكيلاً للعرق — تحليل الأهمية يكشف ذلك قبل النشر.

💡

فلسفتان: ماذا يعني 'المهم'؟

intuition

هناك مدرستان أساسيتان: (أ) الأهمية البنيوية تسأل «كم ساعدت هذه الميزة في بناء النموذج؟» — أهمية شوائب الأشجار هي المثال النموذجي، تُحسب من إحصاءات التقسيم خلال التدريب. إنها سريعة لكن لديها تحيز معروف: تُضخّم أهمية الميزات ذات الأساس الكبير كالرمز_البريدي. (ب) الأهمية الوظيفية تسأل «كم تتدهور تنبؤات النموذج إذا كسرت هذه الميزة؟» — تخلط أهمية التبديل كل ميزة باستقلالية وتقيس الانخفاض في الدقة. إنها مستقلة عن النموذج وتُسند أهمية قريبة من الصفر للميزات العشوائية. غالباً ما يختلف المقربتان — وهذا الاختلاف مفيد.

إذا قالت أهمية الشوائب أن الرمز_البريدي مهم لكن أهمية التبديل تقول شبه صفر، فالنموذج تعلّم ارتباطات زائفة من الأساس بدلاً من الإشارة.

⚙️

أهمية التبديل: خطوة بخطوة

algorithm
1

درّب نموذجك على (X_train, y_train). احسب المقياس الأساسي (مثل الدقة) على X_val.

2

لكل ميزة j في {1، …، p}: اخلط العمود j في X_val (استبدله بتبديل عشوائي)، احسب المقياس على البيانات المخلوطة، أعد العمود j.

3

أهمية j = المقياس الأساسي − المقياس المخلوط. انخفاض كبير = ميزة مهمة.

4

كرر K مرات (افتراضياً K=5 في sklearn) وحسب المتوسط لتقليل التباين من الخلطات العشوائية.

5

رتّب الميزات حسب درجة الأهمية. الميزات ذات الدرجات السالبة (يتحسن النموذج عند خلطها) تشير إلى ميزات ضارة أو مسرِّبة للبيانات.

</>

أهمية الميزات: التبديل والشوائب

code
python66 lines
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import permutation_importance
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np

class="tok-comment"># ── Synthetic tabular dataset ──────────────────────────────────────────────────
np.random.seed(class="tok-num">42)
n = class="tok-num">1000
X = pd.DataFrame({
    class="tok-str">"income":         np.random.normal(class="tok-num">50, class="tok-num">15, n),
    class="tok-str">"age":            np.random.randint(class="tok-num">18, class="tok-num">70, n),
    class="tok-str">"credit_score":   np.random.normal(class="tok-num">650, class="tok-num">80, n),
    class="tok-str">"loan_amount":    np.random.normal(class="tok-num">20, class="tok-num">8, n),
    class="tok-str">"employment_yrs": np.random.exponential(class="tok-num">5, n),
    class="tok-str">"num_accounts":   np.random.poisson(class="tok-num">3, n),
    class="tok-str">"random_noise":   np.random.randn(n),           class="tok-comment"># truly useless
    class="tok-str">"zip_code":       np.random.randint(class="tok-num">0, class="tok-num">10000, n), class="tok-comment"># high-cardinality noise
})
y = (
    class="tok-num">0.4 * (X[class="tok-str">"income"] > class="tok-num">55)
    + class="tok-num">0.3 * (X[class="tok-str">"credit_score"] > class="tok-num">660)
    + class="tok-num">0.2 * (X[class="tok-str">"age"] > class="tok-num">35)
    + class="tok-num">0.1 * np.random.rand(n)
) > class="tok-num">0.5

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=class="tok-num">0.2, random_state=class="tok-num">42)

class="tok-comment"># ── class="tok-num">1. Train Random Forest ─────────────────────────────────────────────────────
rf = RandomForestClassifier(n_estimators=class="tok-num">100, random_state=class="tok-num">42)
rf.fit(X_train, y_train)

class="tok-comment"># ── class="tok-num">2. Impurity (Gini) importance — fast, built-in ────────────────────────────
impurity_imp = pd.Series(rf.feature_importances_, index=X.columns)
print(class="tok-str">"Impurity importance:")
print(impurity_imp.sort_values(ascending=False).round(class="tok-num">3))
class="tok-comment"># WARNING: zip_code (high cardinality) may appear inflated here

class="tok-comment"># ── class="tok-num">3. Permutation importance — model-agnostic, honest ───────────────────────
perm = permutation_importance(
    rf, X_val, y_val,
    n_repeats=class="tok-num">10,          class="tok-comment"># shuffle class="tok-num">10 times, take mean ± std
    scoring=class="tok-str">"accuracy",
    random_state=class="tok-num">42,
    n_jobs=-class="tok-num">1
)
perm_imp = pd.DataFrame({
    class="tok-str">"mean": perm.importances_mean,
    class="tok-str">"std":  perm.importances_std,
}, index=X.columns).sort_values(class="tok-str">"mean", ascending=False)

print(class="tok-str">"\nPermutation importance:")
print(perm_imp.round(class="tok-num">3))
class="tok-comment"># random_noise and zip_code will be near zero or negative

class="tok-comment"># ── class="tok-num">4. Compare the two methods ────────────────────────────────────────────────
comparison = pd.DataFrame({
    class="tok-str">"impurity": impurity_imp,
    class="tok-str">"permutation": perm.importances_mean,
}).sort_values(class="tok-str">"permutation", ascending=False)
print(class="tok-str">"\nComparison (sorted by permutation):")
print(comparison.round(class="tok-num">3))

class="tok-comment"># ── class="tok-num">5. Feature selection using permutation importance ────────────────────────
selected = perm_imp[perm_imp[class="tok-str">"mean"] > class="tok-num">0.01].index.tolist()
print(fclass="tok-str">"\nSelected features ({len(selected)}): {selected}")

SHAP: إسناد الميزات الموحد

math

تُوحّد SHAP (SHapley Additive exPlanations) تقنيات LIME وأهمية الميزات وآليات الانتباه تحت إطار بديهي واحد. يُحلَّل كل تنبؤ إلى مجموع مساهمات لكل ميزة (ϕ_j) زائد قيمة أساسية. بخلاف أهمية التبديل الإجمالية، تعمل SHAP محلياً — تشرح التنبؤات الفردية. تحسب TreeSHAP قيم Shapley الدقيقة لمجموعات الأشجار في وقت متعدد الحدود باستخدام خوارزمية مبنية على المسارات، مما يجعلها عملية للغابات العشوائية وXGBoost في الإنتاج.

ضمانات SHAP: Σϕⱼ = f(x) − E[f(X)] ؛ TreeSHAP بتعقيد O(TLD²)
⚠️

الميزات المرتبطة تقسم الأهمية بشكل غير عادل

pitfall

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

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

?اختبار المعرفة

يتم حفظ التقدم في متصفحك — لا حاجة لحساب.

تحتاج مهندس ذكاء اصطناعي أو عالم بيانات؟

أبني نماذج تعلم آلي مخصصة، ووكلاء ذكاء اصطناعي، ورؤية حاسوب، وأتمتة — من الفكرة إلى الإنتاج.