أهمية الميزات والاختيار
“اعرف الميزات التي يعتمد عليها نموذجك فعلاً — ثم ثق به أكثر (أو أقل)”
أهمية التبديل مقابل أهمية عدم النقاء ونسب SHAP الموحدة — كيف تُفسر نموذجك وتكتشف أي الميزات تُحدث فعلاً فارقاً في التنبؤات.
المتطلبات الأساسية
المفاهيم المغطاة
∑الصيغ الرئيسية
أهمية التبديل
انخفاض الدقة عند خلط الميزة j عشوائياً — مستقل عن النموذج، يعمل بعد التدريب
أهمية شوائب جيني
تناقص الشوائب الموزون عبر جميع تقسيمات الميزة j — سريع لكن متحيز نحو الأساس
SHAP (النواة)
قيمة Shapley: المساهمة الهامشية المتوسطة لكل ميزة عبر جميع تحالفات الميزات
أهمية حذف العمود
المعيار الذهبي لكنه مكلف — إعادة تدريب مرة واحدة لكل ميزة
▶محاكاة تفاعلية
لماذا أهمية الميزات غير قابلة للتفاوض
نماذج التعلم الآلي غالباً ما تكون صناديق سوداء — تنتج مخرجات لكنها تخفي منطقها. تكشف أساليب أهمية الميزات عن هذا الغموض. تجيب على: ما المدخلات التي يعتمد عليها النموذج أكثر؟ يهم هذا لثلاثة أسباب: (1) التصحيح: إذا كان نموذجك يعتمد بشدة على 'bruit_aléatoire' فلديك مشكلة تسرب بيانات. (2) الثقة: يجب أن يفهم المنظمون والأطباء ومسؤولو الائتمان قرارات النموذج — تفرض المادة 22 من GDPR قابلية التفسير للقرارات الآلية. (3) اختيار الميزات: تُوجّه درجات الأهمية تخفيض الأبعاد. حذف الميزات غير المهمة يقلل تكلفة الاستدلال ويمنع الإفراط في التخصيص.
نموذج تسجيل الائتمان الذي يعتمد بشدة على الرمز_البريدي قد يبدو عادلاً على بيانات التدريب لكنه يُعدّ وكيلاً للعرق — تحليل الأهمية يكشف ذلك قبل النشر.
فلسفتان: ماذا يعني 'المهم'؟
هناك مدرستان أساسيتان: (أ) الأهمية البنيوية تسأل «كم ساعدت هذه الميزة في بناء النموذج؟» — أهمية شوائب الأشجار هي المثال النموذجي، تُحسب من إحصاءات التقسيم خلال التدريب. إنها سريعة لكن لديها تحيز معروف: تُضخّم أهمية الميزات ذات الأساس الكبير كالرمز_البريدي. (ب) الأهمية الوظيفية تسأل «كم تتدهور تنبؤات النموذج إذا كسرت هذه الميزة؟» — تخلط أهمية التبديل كل ميزة باستقلالية وتقيس الانخفاض في الدقة. إنها مستقلة عن النموذج وتُسند أهمية قريبة من الصفر للميزات العشوائية. غالباً ما يختلف المقربتان — وهذا الاختلاف مفيد.
إذا قالت أهمية الشوائب أن الرمز_البريدي مهم لكن أهمية التبديل تقول شبه صفر، فالنموذج تعلّم ارتباطات زائفة من الأساس بدلاً من الإشارة.
أهمية التبديل: خطوة بخطوة
درّب نموذجك على (X_train, y_train). احسب المقياس الأساسي (مثل الدقة) على X_val.
لكل ميزة j في {1، …، p}: اخلط العمود j في X_val (استبدله بتبديل عشوائي)، احسب المقياس على البيانات المخلوطة، أعد العمود j.
أهمية j = المقياس الأساسي − المقياس المخلوط. انخفاض كبير = ميزة مهمة.
كرر K مرات (افتراضياً K=5 في sklearn) وحسب المتوسط لتقليل التباين من الخلطات العشوائية.
رتّب الميزات حسب درجة الأهمية. الميزات ذات الدرجات السالبة (يتحسن النموذج عند خلطها) تشير إلى ميزات ضارة أو مسرِّبة للبيانات.
أهمية الميزات: التبديل والشوائب
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: إسناد الميزات الموحد
تُوحّد SHAP (SHapley Additive exPlanations) تقنيات LIME وأهمية الميزات وآليات الانتباه تحت إطار بديهي واحد. يُحلَّل كل تنبؤ إلى مجموع مساهمات لكل ميزة (ϕ_j) زائد قيمة أساسية. بخلاف أهمية التبديل الإجمالية، تعمل SHAP محلياً — تشرح التنبؤات الفردية. تحسب TreeSHAP قيم Shapley الدقيقة لمجموعات الأشجار في وقت متعدد الحدود باستخدام خوارزمية مبنية على المسارات، مما يجعلها عملية للغابات العشوائية وXGBoost في الإنتاج.
الميزات المرتبطة تقسم الأهمية بشكل غير عادل
عندما تكون ميزتان مرتبطتان ارتباطاً وثيقاً (مثل الدخل ودرجة الائتمان)، تُقلّل أهمية التبديل من تقدير كلتيهما. خلط الدخل يترك درجة الائتمان سليمة، فيسترد النموذج معظم الإشارة. الأهمية المشتركة الحقيقية مقسّمة بينهما لكن كل أهمية فردية تبدو صغيرة. الحل: استخدم أهمية حذف العمود أو SHAP مع التجميع الواعي بالارتباطات. انتبه أيضاً أن أهمية التبديل تعتمد على مجموعة التحقق — تتغير الدرجات مع تقسيمات مختلفة.
لا تفسّر أبداً أهمية التبديل شبه الصفرية على أنها 'عديمة الفائدة' للميزات المرتبطة دون التحقق أولاً من الارتباطات الزوجية.
?اختبار المعرفة
يتم حفظ التقدم في متصفحك — لا حاجة لحساب.