Kodax

Decision Trees — تعلم الآلة

أشجار القرار (Decision Trees)

شجرة القرار تعمل مثل لعبة "20 سؤالاً": سلسلة أسئلة نعم/لا تقود إلى قرار.

                الدخل ≥ 45000؟
               /              \\
            لا                 نعم
            /                    \\
    العمر ≥ 30؟              قرض سابق؟
     /      \\                 /       \\
   رفض    موافقة          موافقة     موافقة

كيف تختار السؤال؟

في كل عقدة تجرّب الشجرة كل ميزة وكل نقطة تقسيم، وتختار السؤال الذي يجعل المجموعتين الناتجتين أنقى ما يمكن (أغلبها من فئة واحدة). مقاييس النقاء:

- Gini: احتمال أن تخطئ لو اخترت عينة عشوائية وصنفتها عشوائياً حسب نسب العقدة. 0 = نقية تماماً.

- Entropy: مقدار "الفوضى" بمفهوم نظرية المعلومات.

عملياً يعطيان نتائج متقاربة.

def gini(counts):
    total = sum(counts)
    return 1 - sum((c / total) ** 2 for c in counts)

print(gini([10, 0]))   # 0.0 — نقية
print(gini([5, 5]))    # 0.5 — أسوأ حالة لفئتين
print(gini([8, 2]))    # 0.32

المميزات

- قابلة للتفسير: يمكنك طباعة القواعد وشرح القرار لإنسان (export_text).

- لا تحتاج تقييساً وتتعامل مع العلاقات غير الخطية.

- أهمية الميزات (feature_importances_): كم ساهمت كل ميزة في تحسين النقاء.

العيب الكبير: الحفظ

شجرة بلا قيود تستمر في التقسيم حتى تصبح كل ورقة عينة واحدة — دقة 100% على التدريب وأداء سيئ على الجديد. أدوات التحكم:

| المعامل | الأثر |

|---|---|

| max_depth | أقصى عمق |

| min_samples_leaf | أقل عدد عينات في الورقة |

| min_samples_split | أقل عدد عينات لتقسيم عقدة |

| ccp_alpha | تقليم بعد البناء |

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_text

X, y = load_iris(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
for depth in [1, 3, None]:
    t = DecisionTreeClassifier(max_depth=depth, random_state=0).fit(X_tr, y_tr)
    print(depth, "تدريب", round(t.score(X_tr, y_tr), 2), "اختبار", round(t.score(X_te, y_te), 2))

print(export_text(DecisionTreeClassifier(max_depth=2, random_state=0).fit(X_tr, y_tr),
                  feature_names=["sepal_len", "sepal_wid", "petal_len", "petal_wid"]))

وعيب آخر: عدم الاستقرار — تغيير بسيط في البيانات قد يغيّر الشجرة كلها. الحل في الدرس التالي: الغابات.

تمرين

في المثال الكامل اطبع القواعد بـ export_text واشرح بكلماتك لماذا رُفض أحد الطلبات. ثم أزل max_depth وقارن دقة التدريب والاختبار.

from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np

# بيانات: عمر، دخل، قرض_سابق → موافقة
X = np.array([
    [25, 30000, 0], [35, 50000, 1], [45, 70000, 1],
    [22, 25000, 0], [55, 80000, 1], [30, 40000, 0],
    [40, 60000, 1], [28, 35000, 0]
])
y = np.array([0, 1, 1, 0, 1, 0, 1, 0])  # 0=رفض، 1=موافقة

# تقسيم
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42, stratify=y)

# التدريب
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)

# الدقة
print(f"الدقة: {model.score(X_test, y_test):.2%}")

# أهمية الميزات
features = ['العمر', 'الدخل', 'قرض_سابق']
for name, importance in zip(features, model.feature_importances_):
    print(f"{name}: {importance:.2%}")

# رسم الشجرة
plt.figure(figsize=(12, 8))
plot_tree(model, feature_names=features, filled=True)
plt.show()
اختبر فهمك