Loading
Loading
Decision Trees mimic human thinking — they ask a series of binary questions to reach a final decision.
The goal: each question should maximize Information Gain — reduce impurity as much as possible.
An unconstrained tree memorizes training data (100% training accuracy, 65% test accuracy). Solution: Pruning via max_depth, min_samples_leaf, min_samples_split.
Pros: Interpretable, no scaling needed, handles mixed data types.
Cons: Prone to overfitting, sensitive to small data changes. Solution: Random Forest.
import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_text
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import accuracy_score, classification_report
from sklearn.datasets import load_breast_cancer
print("=" * 55)
print("Decision Trees: كشف سرطان الثدي")
print("=" * 55)
# بيانات طبية حقيقية (مدمجة في sklearn)
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target
print(f"عدد العينات: {len(y)}")
print(f"الفئات: {dict(zip(data.target_names, np.bincount(y)))}")
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
# ─────────────────────────────────────────
# 1. شجرة بدون قيود — Overfitting
# ─────────────────────────────────────────
tree_full = DecisionTreeClassifier(random_state=42)
tree_full.fit(X_train, y_train)
train_acc = accuracy_score(y_train, tree_full.predict(X_train))
test_acc = accuracy_score(y_test, tree_full.predict(X_test))
print("\n1. شجرة كاملة (بدون قيود):")
print(f" Training Accuracy = {train_acc:.3f}")
print(f" Test Accuracy = {test_acc:.3f}")
print(f" عمق الشجرة = {tree_full.get_depth()}")
print(f" Overfitting gap = {train_acc - test_acc:.3f}")
# ─────────────────────────────────────────
# 2. شجرة مقلّمة — Pruning
# ─────────────────────────────────────────
tree_pruned = DecisionTreeClassifier(
max_depth=5,
min_samples_leaf=10,
min_samples_split=20,
random_state=42
)
tree_pruned.fit(X_train, y_train)
train_acc_p = accuracy_score(y_train, tree_pruned.predict(X_train))
test_acc_p = accuracy_score(y_test, tree_pruned.predict(X_test))
print("\n2. شجرة مقلّمة (max_depth=5):")
print(f" Training Accuracy = {train_acc_p:.3f}")
print(f" Test Accuracy = {test_acc_p:.3f}")
print(f" عمق الشجرة = {tree_pruned.get_depth()}")
print(f" Overfitting gap = {train_acc_p - test_acc_p:.3f} ✅ أفضل!")
# ─────────────────────────────────────────
# 3. Cross-Validation
# ─────────────────────────────────────────
cv_scores = cross_val_score(tree_pruned, X, y, cv=5, scoring="accuracy")
print(f"\n3. Cross-Validation (5 folds):")
print(f" Scores: {cv_scores.round(3)}")
print(f" Mean: {cv_scores.mean():.3f} ± {cv_scores.std():.3f}")
# ─────────────────────────────────────────
# 4. أهمية الميزات
# ─────────────────────────────────────────
importances = pd.Series(
tree_pruned.feature_importances_,
index=data.feature_names
).sort_values(ascending=False)
print("\n4. أهم الميزات الطبية:")
for feat, imp in importances.head(5).items():
bar = "█" * int(imp * 50)
print(f" {feat[:30]:30s}: {imp:.3f} {bar}")
# ─────────────────────────────────────────
# 5. قراءة الشجرة
# ─────────────────────────────────────────
print("\n5. هيكل الشجرة (أول 3 مستويات):")
tree_text = export_text(tree_pruned,
feature_names=list(data.feature_names),
max_depth=3)
print(tree_text[:800])