Часть 5. Переоснащение

Деревья решений склонны к переобучению. Дерево решений всегда будет превосходить обучающие данные, если мы позволим ему вырасти до максимальной глубины. Переобучение в деревьях решений происходит, когда дерево становится слишком сложным и фиксирует шум в обучающих данных, а не основной шаблон. Это может привести к плохой производительности обобщения новых невидимых данных. Например,

Рассмотрим обучение необрезанного дерева решений:

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Load the iris dataset
iris = load_iris()
X = iris.data
y = iris.target

# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

# Train a decision tree on the training set
clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)

# Predict on the training set
y_train_pred = clf.predict(X_train)
train_accuracy = accuracy_score(y_train, y_train_pred)

# Predict on the testing set
y_test_pred = clf.predict(X_test)
test_accuracy = accuracy_score(y_test, y_test_pred)

# Compare the accuracy on the training set and the testing set
print("Accuracy on the training set:", train_accuracy)
print("Accuracy on the testing set:", test_accuracy)

Вывод может выглядеть примерно так:

Accuracy on the training set: 1.0
Accuracy on the testing set: 0.8777777777777777

Здесь разница между точностью на тренировочном наборе и на тестовом наборе значительна, это означает, что дерево переобучает обучающие данные.

Способы избежать переобучения в деревьях решений:

Сокращение

В деревьях решений под обрезкой понимается процесс удаления ветвей, которые не дают большого прироста информации или которые не нужны дереву для получения точных прогнозов. Цель обрезки — упростить дерево и сделать его более обобщаемым для новых невидимых данных.

Приведенный выше пример ясно показывает разницу необрезанного и обрезанного дерева. Необрезанное дерево выглядит более плотным и сложным, с высокой дисперсией и, следовательно, переоснащением модели.

В деревьях решений существует два основных типа сокращения: предварительное и последующее.

Предварительная обрезка

Обычно мы применяем эту технику перед построением дерева решений. Это процесс ранней остановки процесса роста дерева до того, как он достигнет максимальной глубины. Рост дерева останавливается путем установки условия остановки, такого как максимальная глубина или минимальное количество выборок в листовом узле. Гиперпараметры, которые можно настроить для ранней остановки и предотвращения переобучения:

max_depth, min_samples_leaf и min_samples_split

1. max_depth: этот параметр определяет максимальную глубину дерева. Чем глубже дерево, тем сложнее модель. Более глубокое дерево может лучше соответствовать обучающим данным, но также может привести к переобучению. Чтобы предотвратить переоснащение, мы можем ограничить глубину дерева, установив максимальное значение для max_depth.

clf = DecisionTreeClassifier(max_depth=5)
clf.fit(X_train, y_train)

Здесь для гиперпараметра max_depth установлено значение 5. Это означает, что дерево не будет расти глубже, чем на 5 уровней.

2. min_samples_leaf: этот параметр определяет минимальное количество выборок, которые должны находиться на конечном узле. Листовой узел — это узел, у которого нет дочерних элементов. Установив минимальное количество выборок, необходимых для конечного узла, мы можем предотвратить переоснащение дерева за счет создания ветвей с очень небольшим количеством выборок.

clf = DecisionTreeClassifier(min_samples_leaf=10)
clf.fit(X_train, y_train)

Здесь для гиперпараметра min_samples_leaf установлено значение 10. Это означает, что конечный узел или конечный узел в дереве решений должен иметь не менее 10 образцов, чтобы его можно было создать. Если определенное разделение приводит к тому, что конечный узел содержит только 5 выборок, разделение не будет разрешено.

3. min_samples_split: этот параметр определяет минимальное количество выборок, необходимых для разделения внутреннего узла. Установив минимальное количество выборок, необходимых для разделения узла, мы можем предотвратить переоснащение дерева за счет создания ветвей с очень небольшим количеством выборок.

clf = DecisionTreeClassifier(min_samples_split=20)
clf.fit(X_train, y_train)

Здесь для гиперпараметра min_samples_split установлено значение 20. Это означает, что внутренний узел должен иметь не менее 20 семплов для разделения. Если определенный внутренний узел имеет только 15 образцов, узлу не будет разрешено дальнейшее разделение, то есть решение о классификации нового образца будет основано на большей части класса в этом листовом узле.

Теперь можно использовать реализацию sklearn метода GridSearchCV, чтобы найти лучший набор гиперпараметров для модели дерева решений.

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV

# Define the parameter grid
param_grid = {'criterion':["gini","entropy"],
'max_depth': [2, 3, 4, 5],
'min_samples_leaf': [10, 20, 30],
'min_samples_split': [20, 30, 40]}

# Create an instance of the DecisionTreeClassifier
clf = DecisionTreeClassifier()

# Create an instance of the GridSearchCV
grid_search = GridSearchCV(clf, param_grid, cv=5)

# Fit the GridSearchCV to the data
grid_search.fit(X_train, y_train)

# Print the best set of hyperparameters
print("Best hyperparameters: ", grid_search.best_params_)

Вывод может выглядеть так:

Best hyperparameters: {'criterion': 'gini', 'max_depth': 4, 'min_samples_leaf': 10, 'min_samples_split': 20}

Постобрезка:

Это также известно как обратная обрезка. Техника постобрезки позволяет модели дерева решений расти на полную глубину, а затем удаляет ветви дерева, которые не обеспечивают значительного повышения точности проверочного набора, чтобы предотвратить переоснащение модели. Процесс последующей обрезки обычно включает в себя удаление узла и его дочерних элементов из дерева, а затем оценку влияния на точность дерева с использованием проверочного набора. Если точность существенно не снижается, узел и его дочерние элементы удаляются безвозвратно. Этот процесс рекурсивно повторяется для каждого узла дерева, начиная с самых нижних листовых узлов и двигаясь вверх.

В предварительной обрезке мы используем такие параметры, как «max_depth» и «max_samples_split». Но здесь мы обрезаем ветви дерева решений, используя технику сокращения сложности стоимости (CCP). В случае сокращения сложности стоимости ccp_alpha можно настроить для получения наиболее подходящей модели. Меньшее значение ccp_alpha приводит к большему сокращению, а большее значение приводит к меньшему сокращению.

DecisionTree в sklearn имеет функцию cost_complexity_pruning_path, которая принимает обученную модель дерева решений в качестве входных данных и возвращает эффективные альфа-каналы каждого поддерева, а также соответствующие примеси.

from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_classification

X, y = make_classification(n_samples=1000, n_features=20, n_classes=2)
clf = DecisionTreeClassifier(random_state=0)
clf.fit(X, y)

path = clf.cost_complexity_pruning_path(X, y)
alphas, impurities = path.ccp_alphas, path.impurities
print(alphas)

Вывод может выглядеть примерно так:

[0. 0.00097143 0.00098276 0.00099703 0.00099756 0.001
0.0012766 0.00164331 0.00166667 0.00197642 0.00343511 0.00833333
0.01714958 0.02144955 0.03399092 0.3331789 ]

Эти значения можно использовать для определения оптимального значения ccp_alpha для обрезки дерева.

Один из способов сделать это — использовать класс GridSearchCV из sklearn, который выполняет исчерпывающий поиск по указанной сетке параметров, чтобы найти лучший набор параметров для ccp_alpha.

param_grid = {'ccp_alpha': alphas}

grid_search = GridSearchCV(clf, param_grid, cv=5)
grid_search.fit(X, y)

best_alpha = grid_search.best_params_['ccp_alpha']
print(best_alpha)

После того, как вы определили наилучшее значение альфа-канала с помощью класса GridSearchCV или любым другим методом, например построением графика производительности дерева по различным значениям ccp_alpha, вы можете использовать это значение для обрезки дерева решений.

# Train the tree using the best value of alpha
clf = DecisionTreeClassifier(random_state=0, ccp_alpha=best_alpha)
clf.fit(X, y)

Случайный лес:

Случайный лес — это метод ансамбля, который объединяет несколько деревьев решений для создания более надежной модели. Random Forest следует методам начальной загрузки и агрегации, чтобы предотвратить переоснащение.

Последнее примечание. Спасибо за прочтение! Я надеюсь, что вы найдете эту статью информативной.

Не забудьте прочитать: Случайные леса