Деревья решений и кросс-валидация
Дерево решений — модель, которая принимает решение серией простых вопросов, как в игре «да/нет»: «доход больше 50 тысяч?» → «да» → «есть просрочки?» → «нет» → выдать кредит. Её легко объяснить человеку, и она не требует масштабирования признаков.
Как дерево учится
На каждом шаге дерево перебирает признаки и пороги и выбирает вопрос вида «признак ≤ порог?», который лучше всего разделяет объекты на однородные группы. Затем то же повторяется для каждой группы. Порог ставится посередине между соседними значениями признака.
from sklearn.tree import DecisionTreeClassifier, export_text
X = [[25, 0], [40, 1], [60, 0], [80, 1], [90, 0], [30, 1]] # доход, просрочки
y = ["нет", "нет", "да", "нет", "да", "нет"]
tree = DecisionTreeClassifier(max_depth=2, random_state=0).fit(X, y)
print(tree.predict([[70, 0]]))
print(export_text(tree, feature_names=["income", "late"]))
export_text печатает дерево вопросов — можно увидеть, как модель рассуждает.
random_state нужен, потому что при одинаково хороших вопросах дерево выбирает случайно; с фиксированным random_state результат повторяется.
Глубина и переобучение
Без ограничений дерево растёт, пока каждый лист не станет «чистым», — и выучивает обучающую выборку наизусть вместе со случайным шумом. На новых данных такое дерево ошибается сильнее.
Рост ограничивают параметрами:
max_depth— максимальное число вопросов от корня до ответа;min_samples_leaf— минимальное число объектов в листе.
Маленькая глубина — модель слишком простая (недообучение), большая — переобучение. Лучшее значение подбирают, проверяя качество на данных, которых модель не видела.
Регрессия деревом
DecisionTreeRegressor устроен так же, только в листе хранится не класс, а среднее значение ответа объектов, попавших в лист:
from sklearn.tree import DecisionTreeRegressor
model = DecisionTreeRegressor(max_depth=3, random_state=0).fit(X_train, y_train)
Важность признаков
После обучения в feature_importances_ лежит вклад каждого признака: насколько вопросы по нему уменьшили ошибку. Сумма важностей равна 1, признак, по которому не задано ни одного вопроса, получает 0.
import pandas as pd
imp = pd.Series(model.feature_importances_, index=X_train.columns)
print(imp.sort_values(ascending=False))
Важность показывает, на что опирается модель, а не обязательно причину в реальном мире.
Кросс-валидация
Одна отложенная выборка даёт оценку, которая зависит от того, какие объекты в неё случайно попали. Надёжнее кросс-валидация: данные делятся на k частей, модель обучается k раз — каждый раз на всех частях, кроме одной, и проверяется на оставшейся.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(DecisionTreeClassifier(max_depth=3, random_state=0), X, y, cv=5)
print(scores) # пять оценок accuracy
print(scores.mean()) # средняя
Для классификации части формируются так, чтобы доли классов в каждой были примерно как во всех данных, а объекты не перемешиваются — поэтому результат воспроизводим.
Так подбирают параметры: для каждого кандидата считают среднюю оценку и берут лучший. Готовый инструмент для перебора — GridSearchCV, он делает то же самое за вас.
Деревья — основа более сильных моделей: RandomForestClassifier усредняет много деревьев, обученных на случайных частях данных, и обычно переобучается гораздо меньше одного дерева.
Итог
DecisionTreeClassifier/DecisionTreeRegressor— модель из вопросов «признак ≤ порог?»;max_depth,min_samples_leaf— защита от переобучения;feature_importances_— вклад признаков, в сумме 1;cross_val_score(model, X, y, cv=5)— пять оценок, их среднее надёжнее одной;- подбор параметра: перебрать значения и выбрать лучшее по кросс-валидации.