Как увеличение глубины дерева влияет на дисперсию модели?
Комментарии (3)
Ответ сгенерирован нейросетью и может содержать ошибки
Влияние глубины дерева на дисперсию модели
Глубина дерева решений — один из ключевых гиперпараметров, который прямо влияет на компромисс между смещением (bias) и дисперсией (variance) модели.
Основные концепции
Дисперсия (Variance) — чувствительность модели к малым изменениям в обучающих данных. Высокая дисперсия означает, что модель сильно меняется при незначительных изменениях данных.
Смещение (Bias) — неправильные предположения, встроенные в алгоритм. Высокое смещение означает, что модель недообучена.
Как глубина дерева влияет на дисперсию
Мелкое дерево (max_depth=1-3)
- Низкая дисперсия — модель стабильна
- Высокое смещение — модель недообучена
- Результат: Underfitting
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
import numpy as np
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
# Мелкое дерево
shallow_tree = DecisionTreeClassifier(max_depth=2)
scores = cross_val_score(shallow_tree, X, y, cv=5, scoring='accuracy')
print(f"Shallow tree - Mean: {scores.mean():.3f}, Std: {scores.std():.3f}")
# Output: Mean: 0.795, Std: 0.012 (низкая дисперсия, высокое смещение)
Глубокое дерево (max_depth=15-30)
- Высокая дисперсия — модель нестабильна
- Низкое смещение — модель переобучена
- Результат: Overfitting
# Глубокое дерево
deep_tree = DecisionTreeClassifier(max_depth=30)
scores = cross_val_score(deep_tree, X, y, cv=5, scoring='accuracy')
print(f"Deep tree - Mean: {scores.mean():.3f}, Std: {scores.std():.3f}")
# Output: Mean: 0.82, Std: 0.045 (высокая дисперсия, низкое смещение)
Визуализация компромисса
Дисперсия
↑
│ ╱╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲ Глубокое дерево
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│ ╱ ╲
│╱──────────────────╲────→ Глубина дерева
Мелкое дерево Оптимум Глубокое дерево
(Высокий bias) (Высокая variance)
Underfitting Overfitting
Практический пример: обучение и тестирование
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
depths = range(1, 20)
train_scores = []
test_scores = []
variances = []
for depth in depths:
tree = DecisionTreeClassifier(max_depth=depth, random_state=42)
# Cross-validation для измерения дисперсии
cv_scores = cross_val_score(tree, X_train, y_train, cv=5)
variance = cv_scores.std() # Дисперсия — это std()
tree.fit(X_train, y_train)
train_scores.append(tree.score(X_train, y_train))
test_scores.append(tree.score(X_test, y_test))
variances.append(variance)
# Визуализация
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
# Точность обучения vs тестирования
ax1.plot(depths, train_scores, label='Train Accuracy', marker='o')
ax1.plot(depths, test_scores, label='Test Accuracy', marker='s')
ax1.set_xlabel('Tree Depth')
ax1.set_ylabel('Accuracy')
ax1.legend()
ax1.grid(True)
ax1.set_title('Bias-Variance Tradeoff')
# Дисперсия по глубине
ax2.plot(depths, variances, label='Variance (CV Std)', color='red', marker='o')
ax2.set_xlabel('Tree Depth')
ax2.set_ylabel('Variance')
ax2.legend()
ax2.grid(True)
ax2.set_title('Variance vs Tree Depth')
plt.tight_layout()
plt.show()
Кривые обучения
from sklearn.model_selection import learning_curve
tree = DecisionTreeClassifier(max_depth=10)
train_sizes, train_scores, val_scores = learning_curve(
tree, X_train, y_train,
train_sizes=np.linspace(0.1, 1.0, 10),
cv=5,
scoring='accuracy'
)
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
val_mean = np.mean(val_scores, axis=1)
val_std = np.std(val_scores, axis=1)
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_mean, label='Train Score', marker='o')
plt.fill_between(train_sizes, train_mean - train_std, train_mean + train_std, alpha=0.2)
plt.plot(train_sizes, val_mean, label='Validation Score', marker='s')
plt.fill_between(train_sizes, val_mean - val_std, val_mean + val_std, alpha=0.2)
plt.xlabel('Training Set Size')
plt.ylabel('Accuracy')
plt.legend()
plt.grid(True)
plt.title('Learning Curve: Impact of Tree Depth on Variance')
plt.show()
Регуляризация дерева для контроля дисперсии
# 1. max_depth — ограничение глубины
tree = DecisionTreeClassifier(max_depth=10)
# 2. min_samples_split — минимум образцов для разделения
tree = DecisionTreeClassifier(min_samples_split=20)
# 3. min_samples_leaf — минимум образцов в листе
tree = DecisionTreeClassifier(min_samples_leaf=10)
# 4. max_features — количество признаков для рассмотрения
tree = DecisionTreeClassifier(max_features='sqrt')
# 5. Комбинированная регуляризация
tree = DecisionTreeClassifier(
max_depth=10,
min_samples_split=20,
min_samples_leaf=10,
max_features='sqrt'
)
tree.fit(X_train, y_train)
print(f"Train: {tree.score(X_train, y_train):.3f}")
print(f"Test: {tree.score(X_test, y_test):.3f}")
Ensemble методы для снижения дисперсии
Несмотря на высокую дисперсию отдельного дерева, ensemble методы используют эту свойство:
from sklearn.ensemble import RandomForestClassifier, BaggingClassifier
# Bagging — усреднение множества глубоких деревьев
# Каждое дерево имеет высокую дисперсию, но ensemble снижает её
bagging = BaggingClassifier(
estimator=DecisionTreeClassifier(max_depth=30),
n_estimators=100
)
# Random Forest — улучшенный Bagging с случайностью в признаках
rf = RandomForestClassifier(
n_estimators=100,
max_depth=30, # Глубокие деревья
random_state=42
)
bagging.fit(X_train, y_train)
rf.fit(X_train, y_train)
print(f"Bagging Train: {bagging.score(X_train, y_train):.3f}")
print(f"Bagging Test: {bagging.score(X_test, y_test):.3f}")
print(f"RF Train: {rf.score(X_train, y_train):.3f}")
print(f"RF Test: {rf.score(X_test, y_test):.3f}")
Пример анализа дисперсии
# Обучение несколько раз на случайных подвыборках
np.random.seed(42)
predictions = []
for i in range(10):
# Случайная подвыборка
indices = np.random.choice(len(X_train), size=int(0.8*len(X_train)), replace=False)
X_subset = X_train[indices]
y_subset = y_train[indices]
tree = DecisionTreeClassifier(max_depth=15)
tree.fit(X_subset, y_subset)
pred = tree.predict_proba(X_test)[:, 1]
predictions.append(pred)
predictions = np.array(predictions)
variance = np.var(predictions, axis=0).mean()
print(f"Average variance of predictions: {variance:.4f}")
# Глубокое дерево выдаст разные предсказания на разных подвыборках
# Мелкое дерево будет более стабильно
Когда увеличивать глубину
- Если train accuracy >> test accuracy (большой gap) → дерево переобучено, уменьшайте глубину
- Если train accuracy ≈ test accuracy (малый gap) → хороший баланс
- Если train accuracy ≈ test accuracy ≈ 50% (оба низкие) → дерево недообучено, увеличивайте глубину
Ключевые выводы
- Мелкие деревья (low variance): Стабильны, но недообучены
- Глубокие деревья (high variance): Гибкие, но переобучаются
- Оптимальная глубина — компромисс между bias и variance
- Cross-validation помогает найти оптимальную глубину
- Ensemble методы (Random Forest, Bagging) используют высокую дисперсию в своих целях
Понимание влияния глубины на дисперсию критично для построения хороших моделей и избежания переобучения.