Почему одно дерево удобно, но ненадежно
Одно дерево решений приятно тем, что его легко читать. Но именно эта модель часто оказывается слишком чувствительной к конкретной выборке. Чуть изменились данные — и структура дерева уже заметно другая. Random Forest решает эту проблему не усложнением одного дерева, а идеей ансамбля. Вместо одного хрупкого решения мы берем много деревьев и усредняем их поведение.
Интуитивно это похоже на голосование группы экспертов, где каждый видел немного разную картину данных. Отдельный эксперт может ошибиться, но коллективное решение обычно устойчивее.
Как работает идея ансамбля
$$ \hat y = \frac{1}{B} \sum_{b=1}^{B} T_b(x) $$Random Forest усредняет предсказания большого числа деревьев. За счет этого шум отдельных деревьев сглаживается, а итоговый прогноз становится стабильнее.
\hat y— итоговый прогноз ансамбляB— число деревьев в лесуT_b(x)— предсказание b-го дерева для объекта x
Каждое дерево в лесу обучается не на всей выборке как есть, а на bootstrap-подвыборке. Кроме того, на каждом сплите дерево смотрит только на случайную подмножину признаков. Из-за этого деревья становятся менее похожими друг на друга. А раз их ошибки менее коррелированы, усреднение дает реальный выигрыш.
Почему это полезно в Data Science
Random Forest часто работает как сильный baseline на табличных данных. Он умеет ловить нелинейности, взаимодействия признаков и при этом не требует такой тонкой настройки, как многие более сложные методы. Еще одна сильная сторона — относительная устойчивость к масштабу признаков и неплохая интерпретируемость через feature importance.
Но лес — не серебряная пуля. Он тяжелее по памяти и скорости, чем одиночное дерево, и может проигрывать бустингу на хорошо подготовленных данных.
Как это выглядит в Python
import pandas as pd # создаем небольшой датасет для задачи классификации
from sklearn.ensemble import RandomForestClassifier # берем ансамбль деревьев вместо одного дерева
frame = pd.DataFrame({ # задаем поведенческие признаки пользователя
'sessions': [1, 2, 3, 4, 5, 6, 7, 8], # количество сессий
'avg_time': [2, 3, 3, 4, 5, 7, 8, 9], # средняя длительность активности
'tickets': [3, 2, 2, 1, 1, 1, 0, 0], # число обращений в поддержку
'target': [0, 0, 0, 0, 1, 1, 1, 1], # целевой класс
})
X = frame[['sessions', 'avg_time', 'tickets']] # собираем матрицу признаков для ансамбля
y = frame['target'] # задаем целевую переменную
forest = RandomForestClassifier(n_estimators=200, max_depth=3, random_state=42) # строим лес из 200 деревьев
forest.fit(X, y) # обучаем ансамбль на подготовленных признаках
print(forest.predict(X).tolist()) # смотрим итоговые решения леса
print(forest.feature_importances_.round(3).tolist()) # оцениваем вклад каждого признака в ансамблеГлавная мысль здесь простая: Random Forest не делает отдельное дерево умнее. Он делает итоговую систему устойчивее за счет разнообразия и усреднения.