← Назад к вопросам

Как оценишь достаточность заданной глубины дерева?

2.3 Middle🔥 61 комментариев
#Машинное обучение

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оценка достаточности глубины дерева решений

Глубина дерева (max_depth) — это критический гиперпараметр, влияющий на сложность модели, переобучение и время обучения. Оценка достаточности требует комплексного анализа нескольких метрик и подходов.

Основной метод: Кривые обучения (Learning Curves)

Идея: смотрим, как меняются ошибки train и validation при увеличении глубины.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report

depths = range(1, 21)
train_errors = []
val_errors = []

for depth in depths:
    model = DecisionTreeClassifier(max_depth=depth, random_state=42)
    model.fit(X_train, y_train)
    train_pred = model.predict(X_train)
    val_pred = model.predict(X_val)
    train_errors.append(1 - accuracy_score(y_train, train_pred))
    val_errors.append(1 - accuracy_score(y_val, val_pred))

plt.figure(figsize=(10, 6))
plt.plot(depths, train_errors, 'o-', label='Train Error', linewidth=2)
plt.plot(depths, val_errors, 's-', label='Validation Error', linewidth=2)
plt.axvline(x=np.argmin(val_errors) + 1, color='r', linestyle='--', label='Optimal depth')
plt.xlabel('Tree Depth')
plt.ylabel('Error')
plt.legend()
plt.grid(True)
plt.show()

optimal_depth = np.argmin(val_errors) + 1
print(f'Оптимальная глубина: {optimal_depth}')

Интерпретация:

  • Недообучение: train_error и val_error одинаково высокие — глубину надо увеличить
  • Оптимум: val_error минимальна, train_error ненамного ниже — текущая глубина хороша
  • Переобучение: train_error низкая, val_error растёт — глубину надо уменьшить

Критерий останова: Gap между train и validation

gap = np.array(val_errors) - np.array(train_errors)

for depth, g in zip(depths, gap):
    status = 'GOOD' if abs(g) < 0.10 else 'OVERFITTING' if g > 0.10 else 'UNDERFITTING'
    print(f'Depth {depth}: Gap {g:.3f} - {status}')

recommended_depths = [d for d, g in zip(depths, gap) if abs(g) < 0.05]
print(f'Рекомендуемые глубины: {recommended_depths}')

Cross-Validation для надёжной оценки

from sklearn.model_selection import cross_validate

scoring = {
    'accuracy': 'accuracy',
    'f1': 'f1_macro',
    'precision': 'precision_macro',
    'recall': 'recall_macro'
}

best_depth = None
best_score = -np.inf

for depth in range(1, 21):
    model = DecisionTreeClassifier(max_depth=depth, random_state=42)
    scores = cross_validate(model, X_train, y_train, cv=5, scoring=scoring)
    mean_acc = scores['test_accuracy'].mean()
    std_acc = scores['test_accuracy'].std()
    print(f'Depth {depth}: Accuracy {mean_acc:.4f} ± {std_acc:.4f}')
    
    if mean_acc > best_score:
        best_score = mean_acc
        best_depth = depth

print(f'Оптимальная глубина (CV): {best_depth}')

Анализ важности признаков (Feature Importance)

model = DecisionTreeClassifier(max_depth=optimal_depth, random_state=42)
model.fit(X_train, y_train)

importances = model.feature_importances_
feature_names = X_train.columns

top_features = pd.DataFrame({
    'feature': feature_names,
    'importance': importances
}).sort_values('importance', ascending=False)

print(top_features.head(10))

if top_features.iloc[0]['importance'] < 0.1:
    print('ВНИМАНИЕ: Главный признак имеет низкий вес. Глубину нужно увеличить.')

Проверка через GridSearch

from sklearn.model_selection import GridSearchCV

param_grid = {
    'max_depth': range(1, 21),
    'min_samples_split': [2, 5, 10],
    'min_samples_leaf': [1, 2, 4]
}

grid = GridSearchCV(
    DecisionTreeClassifier(random_state=42),
    param_grid,
    cv=5,
    scoring='f1_macro',
    n_jobs=-1
)

grid.fit(X_train, y_train)
print(f'Лучшая глубина: {grid.best_params_["max_depth"]}')
print(f'Лучший скор: {grid.best_score_:.4f}')

Практические критерии

МетрикаИдеальноПроблемаДействие
Val accuracyМаксимум за 5 folds< 70%Увеличить глубину
Gap train/val< 5%> 15%Уменьшить глубину
Feature importanceTop 3 > 50%РавномерноеПроверить данные
СложностьO(2^depth) OKСлишком высокийУменьшить глубину
Время обучения< 1 сек> 10 секУменьшить глубину

Эмпирические рекомендации

recommended_max_depth = int(np.log2(len(X_train)))
print(f'Рекомендуемая глубина: {recommended_max_depth}')

# Диапазоны по задачам:
# Простые задачи: 3-5
# Стандартные: 5-15
# Сложные: до 25-30 с регуляризацией

Итог

Достаточность оценивается через:

  1. Кривые обучения — визуальный анализ gap
  2. Cross-validation — надёжная оценка
  3. Сбалансированность gap — не более 5-10%
  4. GridSearch — автоматический поиск оптимума
  5. Feature importance — модель видит важные признаки

Оптимальная глубина обычно 5-15 в зависимости от размера датасета.