في نافذة الطباعة اختر «حفظ كملف PDF» كوجهة.
تعلم الآلة، الأسبوع 6
أشجار القرار والغابة العشوائية
صنف المقترض بطرح الأسئلة، ثم دع أشجارا كثيرة تصوت: قروض Lending Club.
الأهداف
- ▸شرح كيف تصنف شجرة القرار (decision tree): سلسلة من أسئلة العتبة (threshold) تنتهي عند ورقة (leaf)
- ▸حساب عدم نقاء جيني (Gini impurity) لعقدة (node) وجيني الموزون (weighted Gini) لتقسيم (split) يدويا
- ▸شرح لماذا تعاني الشجرة التي تنمو حتى تصبح كل ورقة نقية فرط الملاءمة (overfitting)
- ▸شرح الغابة العشوائية (random forest): عينات bootstrap، وخصائص (features) عشوائية عند كل تقسيم، ثم التصويت
- ▸تدريب
DecisionTreeClassifierوRandomForestClassifierعلى بيانات Lending Club - ▸إدراك متى لا تعكس الدقة (accuracy) العالية إلا هدفا (target) غير متوازن، وتطبيق ذلك على مشروعك
الأسبوع 6 من الخطة
موقع الدرس من المقرر
- ▸دفتر (notebook) واحد: DecisionTrees_RandomForest_Classification، شجرة وغابة على بيانات إقراض عامة
- ▸سيناريو من الواقع: تربط Lending Club بين المقترضين والمستثمرين؛ ونتنبأ بما إذا كان المقترض قد سدد قرضه كاملا
- ▸مرحلة المشروع (project milestone): تنفيذ نموذج تعلم الآلة (Machine Learning Model Implementation)، وتستمر على بياناتك الخاصة
خطة الساعتين
| الجزء | ما نفعله | الزمن |
|---|---|---|
| 1 | فكرة الشجرة، وشجرة ننميها يدويا | 30 دقيقة |
| 2 | دفتر Lending Club: البيانات والاستكشاف | 15 دقيقة |
| 3 | شجرة قرار واحدة على القروض | 10 دقائق |
| 4 | الغابة العشوائية: يدويا، ثم على القروض | 25 دقيقة |
| 5 | الأخطاء، والمشروع، والتمارين مع الإجابات، والخلاصة | 40 دقيقة |
الجزء 1
فكرة شجرة القرار
اطرح الأسئلة حتى تتضح الإجابة
ما شجرة القرار؟
- شجرة القرار (decision tree)
- مصنف (classifier) يطرح سلسلة من الأسئلة التي يجاب عنها بنعم أو لا، ويقارن كل سؤال خاصية واحدة بـعتبة، مثل
fico ≤ 677.
- ▸الإجابة نعم ترسل العينة إلى الفرع الأيسر، والإجابة لا إلى الفرع الأيمن
- ▸ينتظر السؤال التالي في نهاية كل فرع
- ▸العقدة التي لا سؤال فيها ورقة: وصنفها هو التنبؤ
المصطلحات على بيانات القروض
| المصطلح | في بيانات Lending Club |
|---|---|
الخصائص X | البيانات الائتمانية، مثل fico (درجة الائتمان) وint.rate (سعر الفائدة) |
التسمية (label) y | not.fully.paid: 1 لم يسدد كاملا، و0 سدد كاملا |
| عقدة الجذر | السؤال الأول، ويطرح على كل مقترض |
| الورقة | عقدة بلا سؤال: تتنبأ بصنف الأغلبية فيها |
| العمق (depth) | عدد الأسئلة على أطول مسار إلى ورقة |
ما مدى اختلاط العقدة؟ عدم نقاء جيني
يدرب الدفتر باستخدام criterion='gini'
- ▸
p_0هي نسبة العقدة في الصنف0(سدد)، وp_1نسبتها في الصنف1(لم يسدد)
اختيار السؤال: جيني الموزون
- ▸يقسم السؤال
nمن الصفوف إلىn_Lعلى اليسار وn_Rعلى اليمين - ▸
G_LوG_Rهما جيني كل جانب؛ ويحسب كل جانب بحسب حجمه - ▸العتبات المرشحة هي نقاط المنتصف (midpoints) بين القيم المتجاورة
يدويا
مثال محلول: عشرة مقترضين حقيقيين
صفوف من loan_data.csv، مرتبة حسب fico. y = 1: لم يسدد كاملا. أربعة من عشرة لم يسددوا.
| المقترض | fico | int.rate | y |
|---|---|---|---|
| B1 | 647 | 0.1482 | 1 |
| B2 | 662 | 0.1507 | 0 |
| B3 | 667 | 0.1299 | 1 |
| B4 | 672 | 0.1347 | 1 |
| B5 | 682 | 0.1103 | 0 |
| المقترض | fico | int.rate | y |
|---|---|---|---|
| B6 | 687 | 0.1387 | 0 |
| B7 | 692 | 0.1284 | 0 |
| B8 | 707 | 0.1091 | 1 |
| B9 | 727 | 0.1059 | 0 |
| B10 | 757 | 0.1189 | 0 |
الخطوة 1: جيني الجذر
المقترضون العشرة كلهم: 6 سددوا، و4 لم يسددوا
الخطوة 2: جرب السؤال fico ≤ 677
677 هو نقطة المنتصف بين B4 (672) وB5 (682)
| الجانب | المقترضون | لم يسدد | سدد |
|---|---|---|---|
نعم، ≤ 677 | من B1 إلى B4 | 3 | 1 |
لا، > 677 | من B5 إلى B10 | 1 (B8) | 5 |
الخطوة 3: جيني كل جانب
الخطوة 4: جيني الموزون للتقسيم
الخطوة 5: الخاصية الأخرى
أفضل سؤال على int.rate هو int.rate ≤ 0.12915
| الجانب | المقترضون | لم يسدد | سدد |
|---|---|---|---|
| نعم، أسعار أقل | B5، B7، B8، B9، B10 | 1 | 4 |
| لا، أسعار أعلى | B1، B2، B3، B4، B6 | 3 | 2 |
الخطوة 6: يجرب البحث كل عتبة
تسع نقاط منتصف لـfico وتسع لـint.rate: ثمانية عشر سؤالا مرشحا
| عتبة fico | اليسار: لم يسدد، سدد | اليمين: لم يسدد، سدد | جيني الموزون |
|---|---|---|---|
| 654.5 | 1, 0 | 3, 6 | 0.4000 |
| 669.5 | 2, 1 | 2, 5 | 0.4190 |
| 677 | 3, 1 | 1, 5 | 0.3167 |
| 684.5 | 3, 2 | 1, 4 | 0.4000 |
| 717 | 4, 4 | 0, 2 | 0.4000 |
الخطوة 7: تنمية العقدة الابنة (child) اليسرى
من B1 إلى B4: 3 لم يسددوا، و1 سدد، G = 0.375
الخطوة 8: تنمية العقدة الابنة اليمنى
من B5 إلى B10: 1 لم يسدد (B8)، و5 سددوا، G = 0.2778
الشجرة التي بنيناها
fico <= 677 ?
|-- yes: int.rate <= 0.14945 ?
| |-- yes: leaf [3 not paid, 0 paid] -> not paid
| |-- no: leaf [0 not paid, 1 paid] -> paid
|-- no: int.rate <= 0.1097 ?
|-- yes: leaf [1 not paid, 1 paid] -> paid
|-- no: leaf [0 not paid, 4 paid] -> paidالتنبؤ بمقترضين جديدين
اتبع الأسئلة من الجذر
- ▸A:
670 ≤ 677نعم، ثم0.14 ≤ 0.14945نعم، إذن تقول الورقة لم يسدد
- ▸B:
700 ≤ 677لا، ثم0.12 ≤ 0.1097لا، إذن تقول الورقة سدد
جرب بنفسك: ابن الشجرة يدويا
الجزء 2
دفتر Lending Club
9578 قرضا حقيقيا، من 2007 إلى 2010
افتح الدفتر في Colab
https://colab.research.google.com/github/
tirthajyoti/Machine-Learning-with-Python/blob/
master/Classification/
DecisionTrees_RandomForest_Classification.ipynbتحميل البيانات وفحصها
import pandas as pd
url = ("https://raw.githubusercontent.com/"
"tirthajyoti/Machine-Learning-with-Python/"
"master/Datasets/loan_data.csv")
df = pd.read_csv(url)
df.info()- ▸9578 صفا، و14 عمودا، ولا قيم مفقودة
- ▸
fico: درجة الائتمان؛ وint.rate: سعر الفائدة في صورة نسبة - ▸
purpose: الغرض من القرض، في صورة نص - ▸التسمية
not.fully.paid:1إذا لم يسدد المقترض كاملا
العدد المهم
print(df['not.fully.paid'].value_counts())| not.fully.paid | المقترضون | النسبة |
|---|---|---|
| 0، سدد | 8045 | 84% |
| 1، لم يسدد | 1533 | 16% |
استكشف قبل أن تبني النموذج


- ▸تحت
fico 660: لا يستوفي 487 مقترضا سياسة الائتمان، ويستوفيها 2 فقط. فعتبة واحدة تفصل مجموعة - ▸لم تسدد كاملة: 27.8% من قروض
small_business، و11.6% من قروضcredit_card
تحويل عمود النص إلى أرقام
df_final = pd.get_dummies(df, ['purpose'],
drop_first=True)- ▸تصبح الأغراض السبعة ستة أعمدة قيمها 0 أو 1، مثل
purpose_credit_card - ▸يحذف
drop_first=Trueالغرضall_other: فالقيمة 0 في الأعمدة الستة كلها تعني هذا الغرض - ▸في
df_final19 عمودا
التقسيم إلى مجموعة تدريب ومجموعة اختبار
X = df_final.drop('not.fully.paid', axis=1)
y = df_final['not.fully.paid']
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.30, random_state=101)الجزء 3
شجرة قرار واحدة على القروض
دع الشجرة تنمو حتى تصبح كل ورقة نقية
تدريب الشجرة والتنبؤ
from sklearn.tree import DecisionTreeClassifier
dtree = DecisionTreeClassifier(criterion='gini', max_depth=None,
random_state=101)
dtree.fit(X_train, y_train)
predictions = dtree.predict(X_test)- ▸
criterion='gini': عدم النقاء الذي رأيناه في الجزء 1 - ▸
max_depth=None: استمر في التقسيم حتى تصبح كل ورقة نقية - ▸
random_state=101: تكسر حالات التعادل بين التقسيمات المتساوية في الجودة بالطريقة نفسها في كل تشغيل
مصفوفة الالتباس للشجرة
A: الدقة. وR_1 وP_1: الاستدعاء (recall) والضبط (precision) للصنف 1
| التنبؤ 0 (سدد) | التنبؤ 1 (لم يسدد) | |
|---|---|---|
| الفعلي 0 | 1975 | 456 |
| الفعلي 1 | 336 | 107 |
الشجرة حفظت مجموعة تدريبها
print(dtree.get_depth(), dtree.get_n_leaves())
print(dtree.score(X_train, y_train))| المقياس | القيمة |
|---|---|
| العمق | 27 |
| الأوراق | 1005 |
| الدقة على التدريب | 1.0 |
الجزء 4
الغابة العشوائية
أشجار كثيرة مختلفة، وتصويت واحد
الفكرة: أشجار كثيرة مختلفة
- 1Bootstrap: تحصل كل شجرة على
nمن الصفوف مسحوبة عشوائيا مع الإرجاع (with replacement) من صفوف التدريب البالغ عددهاn - 2خصائص عشوائية: عند كل تقسيم لا تبحث الشجرة إلا في
mمن الخصائص البالغ عددهاp، حيثm = ⌊√p⌋ - 3التصويت: تصنف كل شجرة العينة الجديدة؛ ويفوز صنف الأغلبية
يدويا
مثال محلول: عينة bootstrap واحدة
RandomForestClassifier(n_estimators=5, random_state=0) على المقترضين العشرة. ومع p = 2 يبحث كل تقسيم في خاصية عشوائية واحدة، m = 1
- ▸سحبت الشجرة 1: B4، B3، B1، B1، B3، B7، B10، B8، B4، B10
- ▸مرتين: B1، B3، B4، B10. ومرة واحدة: B7، B8
- ▸لم يسحبوا أبدا: B2، B5، B6، B9، فبقوا خارج هذه الشجرة
خمس أشجار تصوت على مقترض جديد
المقترض الجديد: fico 710، int.rate 0.11
| الشجرة | خارج عينتها | الصوت |
|---|---|---|
| 1 | B2، B5، B6، B9 | لم يسدد |
| 2 | B3، B6، B7 | سدد |
| 3 | B1، B3، B7، B10 | سدد |
| 4 | B2، B3، B7، B8، B10 | سدد |
| 5 | B1، B3، B5، B9 | لم يسدد |
جرب بنفسك: شاهد تصويت الغابة
تدريب الغابة
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(n_estimators=600, random_state=101)
rfc.fit(X_train, y_train)
rfc_pred = rfc.predict(X_test)
print(confusion_matrix(y_test, rfc_pred))
print(classification_report(y_test, rfc_pred))p = 18 يبحث كل تقسيم في m = 4 من الخصائص: فالأمر rfc.estimators_[0].max_features_ يطبع 4.مصفوفة الالتباس للغابة
A: الدقة على مقترضي الاختبار الـ2874
| التنبؤ 0 (سدد) | التنبؤ 1 (لم يسدد) | |
|---|---|---|
| الفعلي 0 | 2420 | 11 |
| الفعلي 1 | 431 | 12 |
هل تجد شيئا غريبا؟
A_0: دقة الإجابة "سدد" عن الجميع. وR_1: استدعاء الصنف 1
- ▸لا تصنف الغابة على أنهم لم يسددوا إلا 23 مقترضا، وتتفوق على "سدد للجميع" بمقترض واحد
- ▸لا يحصل أي مقترض اختبار على أكثر من 375 صوتا بـ"لم يسدد" من الأشجار الـ600
كم شجرة؟

- ▸يمر الدفتر في حلقة على 5 إلى 100 شجرة، مع
min_samples_split=10، ونضيفrandom_state=101لكل غابة - ▸0.8239 مع 5 أشجار، ثم 0.8455 إلى 0.8473 من 30 شجرة فصاعدا
- ▸زيادة الأشجار تجعل التصويت أكثر ثباتا، لكن المنحنى يستقر عند مستوى "سدد للجميع"
قبل التمارين
الأخطاء الشائعة
- ▸قراءة
loan_data.csvفي Colab من مجلد لا يحتويه - ▸نسيان
random_state، ثم مقارنة أرقام من تقسيمين مختلفين - ▸الثقة بـالنتيجة المثالية على التدريب لشجرة نمت باستخدام
max_depth=None - ▸الحكم على نموذج بالدقة وحدها حين يكون أحد الصنفين نادرا
- ▸طباعة تقرير
predictionsوأنت تقصدrfc_pred - ▸تمرير عمود نصي مثل
purposeدون متغيرات وهمية (dummy variables)
مشروع فريقك
مرحلة المشروع: تنفيذ النموذج
- 1خذ الخصائص والهدف من الأسبوع الماضي؛ وحول الأعمدة النصية إلى متغيرات وهمية
- 2قسم البيانات مع قيمة ثابتة لـ
random_state - 3درب
DecisionTreeClassifier: وقارن نتيجته على التدريب بنتيجته على الاختبار - 4درب
RandomForestClassifier: واعرض مصفوفة الالتباس (confusion matrix) وclassification_report - 5قارن الشجرة والغابة وKNN على مجموعة الاختبار نفسها، باستخدام استدعاء كل صنف
الجزء 5
التمارين: دورك
نحو 30 دقيقة، والإجابات تلي كل مهمة
نحو 10 دقائق
التمرين 1: اختيار السؤال الأول
ثمانية مقترضين حقيقيين آخرين، y = 1: لم يسدد
| المقترض | fico | int.rate | y |
|---|---|---|---|
| P1 | 647 | 0.1482 | 1 |
| P2 | 667 | 0.1343 | 0 |
| P3 | 677 | 0.1734 | 1 |
| P4 | 682 | 0.1197 | 0 |
| المقترض | fico | int.rate | y |
|---|---|---|---|
| P5 | 692 | 0.1287 | 0 |
| P6 | 697 | 0.1316 | 1 |
| P7 | 742 | 0.1114 | 0 |
| P8 | 747 | 0.0751 | 0 |
- ▸احسب جيني الجذر
- ▸احسب
G_wللسؤالfico ≤ 679.5وللسؤالint.rate ≤ 0.13015 - ▸أي السؤالين يفوز، وبكم تنخفض قيمة جيني؟
الإجابات
التمرين 1: الإجابة
| السؤال | جيني الموزون |
|---|---|
fico ≤ 679.5 | G_w = 0.375 × 0.4444 + 0.625 × 0.32 ≈ 0.3667 |
int.rate ≤ 0.13015 | G_w = 0.5 × 0 + 0.5 × 0.375 = 0.1875 |
نحو 5 دقائق
التمرين 2: قراءة مصفوفة الغابة
الغابة ذات الأشجار الـ600: [[2420, 11], [431, 12]]
نحو 5 دقائق
التمرين 3: إنتروبيا التقسيم الأول
يدرب الدفتر أيضا باستخدام criterion='entropy'، أي الإنتروبيا (entropy)
نحو 10 دقائق
التمرين 4: في Colab، على القروض
- 1بعد التقسيم مع
random_state=101، دربDecisionTreeClassifier(max_depth=5, random_state=101) - 2اطبع مصفوفة الالتباس الخاصة به، ودقته على الاختبار وعلى التدريب؛ وقارنها مع
max_depth=None - 3أعد تشغيل الحلقة على عدد الأشجار مع
max_depth=5وrandom_state=101في كل غابة
| الشجرة | مصفوفة الالتباس | الاختبار | التدريب |
|---|---|---|---|
max_depth=5 | [[2396, 35], [431, 12]] | 0.8379 | 0.845 |
max_depth=None | [[1975, 456], [336, 107]] | 0.724 | 1.0 |
الخلاصة
- 1تصنف الشجرة بسلسلة من أسئلة العتبة؛ وتتنبأ الورقة بصنف الأغلبية فيها
- 2كل سؤال هو صاحب أقل قيمة لجيني الموزون عبر كل خاصية وكل عتبة
- 3الشجرة التي تنمو حتى تصبح كل ورقة نقية تحفظ مجموعة تدريبها
- 4تجري الغابة العشوائية تصويتا بين أشجار نمت على عينات bootstrap مع خصائص عشوائية
- 5حين يكون أحد الصنفين نادرا، اقرأ استدعاءه، لا الدقة وحدها
افتح هذا الدرس
Mahmoud Abas|أشجار القرار والغابة العشوائية