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

Как обучаются деревья в Random Forest?

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

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

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

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

Как обучаются деревья в Random Forest

Random Forest — это ансамбль независимо обученных деревьев, которые работают вместе через усреднение. Разберу весь процесс обучения пошагово.

Общая идея Random Forest

Вместо обучения одного идеального дерева, обучаем множество "хороших, но разных" деревьев, затем усредняем их предсказания. Этот подход снижает variance благодаря усреднению ошибок.

Одно дерево: может переобучиться
N деревьев: каждое переобучается по-разному
Усреднение: шум компенсируется, сигнал усиливается

Два источника randomness (важно!)

1. Bootstrap sampling (Bagging)

Каждое дерево обучается на случайной подвыборке данных с повторениями:

import numpy as np
from sklearn.ensemble import RandomForestClassifier

# Для каждого дерева в Random Forest:
for tree_idx in range(n_estimators):
    # Создаем Bootstrap образец (с повторениями)
    bootstrap_idx = np.random.choice(n_samples, size=n_samples, replace=True)
    X_bootstrap = X[bootstrap_idx]
    y_bootstrap = y[bootstrap_idx]
    
    # Обучаем дерево на этом образце
    tree = DecisionTree()
    tree.fit(X_bootstrap, y_bootstrap)
    trees.append(tree)

Это означает:

  • Некоторые примеры могут повторяться в одной выборке
  • Некоторые примеры могут отсутствовать (примерно 36.8% не попадут в bootstrap)
  • Каждое дерево видит немного разные данные

2. Feature randomness (Feature selection)

При каждом разбиении в дереве выбираем случайное подмножество признаков:

# На каждом узле дерева (не на каждом дереве!)
for node in tree:
    # Случайно выбираем sqrt(n_features) признаков
    n_features_to_consider = int(np.sqrt(n_features))
    random_features = np.random.choice(
        n_features, 
        size=n_features_to_consider, 
        replace=False
    )
    
    # Ищем лучшее разбиение только среди этих признаков
    best_split = find_best_split(X, y, random_features)

Параметр max_features контролирует это:

  • max_features='sqrt' — выбираем sqrt(n_features) признаков на каждое разбиение
  • max_features='log2' — выбираем log2(n_features) признаков
  • max_features=None — выбираем все признаки (без random feature selection)

Алгоритм обучения Random Forest (полный процесс)

class RandomForestClassifier:
    def __init__(self, n_estimators=100, max_depth=None, max_features='sqrt'):
        self.n_estimators = n_estimators
        self.max_depth = max_depth
        self.max_features = max_features
        self.trees = []
    
    def fit(self, X, y):
        n_samples = X.shape[0]
        
        # Шаг 1: Обучаем n_estimators деревьев
        for i in range(self.n_estimators):
            # Шаг 1a: Bootstrap sampling
            indices = np.random.choice(
                n_samples, 
                size=n_samples, 
                replace=True
            )
            X_bootstrap = X[indices]
            y_bootstrap = y[indices]
            
            # Шаг 1b: Обучаем дерево на bootstrap выборке
            tree = DecisionTreeClassifier(
                max_depth=self.max_depth,
                max_features=self.max_features,
                random_state=None  # Разные random_state для разных деревьев
            )
            tree.fit(X_bootstrap, y_bootstrap)
            self.trees.append(tree)
    
    def predict(self, X):
        # Шаг 2: Предсказания от всех деревьев
        predictions = np.array([
            tree.predict(X) 
            for tree in self.trees
        ])  # Shape: (n_estimators, n_samples)
        
        # Шаг 3: Усреднение
        # Для классификации: большинством голосов (mode)
        return mode(predictions, axis=0)
    
    def predict_proba(self, X):
        # Для вероятностей: усредняем вероятности
        proba = np.array([
            tree.predict_proba(X) 
            for tree in self.trees
        ])
        return proba.mean(axis=0)

Пример на реальных данных

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Создаем данные
X, y = make_classification(
    n_samples=1000, 
    n_features=20, 
    n_informative=10,
    random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# Обучаем Random Forest
rf = RandomForestClassifier(
    n_estimators=100,        # 100 деревьев
    max_depth=10,            # Максимальная глубина каждого дерева
    max_features='sqrt',     # sqrt(20) ≈ 4-5 признаков на разбиение
    min_samples_leaf=5,      # Минимум 5 примеров в листе
    random_state=42
)
rf.fit(X_train, y_train)

# Предсказания
y_pred = rf.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")

# Важность признаков
feature_importance = rf.feature_importances_
print(f"Top 5 features: {np.argsort(feature_importance)[-5:][::-1]}")

Параметры обучения

n_estimators — количество деревьев

  • Больше деревьев = лучше (но медленнее)
  • Обычно 100-1000
  • После 500 улучшения минимальны

max_depth — максимальная глубина

  • None = деревья растут до полного разделения
  • Меньше глубина = быстрее, но может быть bias
  • Обычно 10-20

max_features — признаки на разбиение

  • 'sqrt' — sqrt(n_features) (самый популярный)
  • 'log2' — log2(n_features)
  • None — все признаки (нет feature randomness)

min_samples_leaf — минимум примеров в листе

  • Больше значение = проще модель
  • Снижает переобучение

min_samples_split — минимум примеров для разбиения

  • Больше значение = большие листья

Out-of-Bag (OOB) оценка

Важная особенность Random Forest — OOB ошибка:

# Для каждого примера примерно 36.8% деревьев не видели его
# (потому что не попал в bootstrap выборку)
# Можем оценить качество на этих деревьях

rf = RandomForestClassifier(
    n_estimators=100,
    oob_score=True  # Вычислить OOB ошибку
)
rf.fit(X_train, y_train)

print(f"OOB Score: {rf.oob_score_:.4f}")
# OOB Score часто очень близка к test ошибке
# Экономит валидационный набор!

Параллелизм

rf = RandomForestClassifier(
    n_estimators=1000,
    n_jobs=-1  # Использовать все процессорные ядра
)
# С n_jobs=-1 обучение параллелизируется
# Значительное ускорение на многоядерных машинах

Итог

Deревья в Random Forest обучаются:

  1. Независимо — каждое на своей bootstrap выборке
  2. С feature randomness — разные признаки на разных узлах
  3. Параллельно — все деревья обучаются друг от друга не зависят
  4. Усредняются — финальное предсказание = среднее от всех деревьев

Это позволяет получить модель с низким variance и хорошей обобщаемостью.

Как обучаются деревья в Random Forest? | PrepBro