Дерево решений — это контролируемый алгоритм машинного обучения, который работает на основе рекурсивных ответов на некоторые вопросы (условия «если-иначе»). Алгоритм используется как для регрессии, так и для классификации. Однако в основном для задач классификации.

Вопросы в полях называются внутренними узлами, где ответы на вопросы разбивают его на ветви. Узлы, которые больше не разделяются, называются листьями и представляют собой решение/выход модели.

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

Во-первых, функция корневого узла выбирается на основе результатов меры выбора атрибута (ASM). После этого ASM применяется ко всем рекурсивно возникающим узлам до тех пор, пока дальнейшее разделение не станет возможным (когда мы достигнем листа).

Избирательная мера атрибутов (ASM)

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

Два основных метода АСМ:

  • Индекс Джини
  • Прирост информации (ID3)

Индекс Джини

Индекс Джини или примесь Джини - это мера примеси (степень вероятности неправильной классификации признака), используемая для создания дерева решений. Функция с низким значением индекса Джини должна быть предпочтительной для выбора узлов при создании дерева решений. Индекс Джини используется для создания только двоичных разбиений дерева.

Прирост информации (ID3)

Прирост информации показывает, насколько информативна функция, измеряя изменения энтропии после разделения данных по этой функции. Алгоритм дерева решений всегда пытается максимизировать прирост информации, в котором узел с наибольшим приростом информации выбирается в качестве первого узла (первое разделение). Поэтому дерево сначала разбивается по признаку с наибольшей энтропией, уменьшая энтропию на всем пути вниз по листьям.

Формула энтропии:

Мы можем использовать модель DecisionTreeClassifier из библиотеки обучения scikit (документация DecisionTreeClassifier):

Давайте воспользуемся набором данных о раке из библиотеки scikit-learn и применим модель дерева решений:

# Import train_test_split function and the dataset
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.tree import DecisionTreeClassifier

cancer = load_breast_cancer()
y = cancer.target
X = cancer.data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
clf = DecisionTreeClassifier(criterion='entropy', random_state=0)
clf.fit(X_train, y_train)
print("Training accuracy:{:.2f}".format(clf.score(X_train,y_train)))
print("Test accuracy: {:.2f}".format(clf.score(X_test,y_test)))

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

from sklearn import tree
import matplotlib.pyplot as plt

fig, axes = plt.subplots(nrows = 1,ncols = 1,figsize = (16,8), dpi=100)
tree.plot_tree(clf, feature_names = cancer.feature_names, class_names=cancer.target_names, filled = True, fontsize = 5);

Изменение критерия asm с gine на энтропию:

clf = DecisionTreeClassifier(criterion='entropy', random_state=0)
clf.fit(X_train, y_train)
print("Training accuracy:{:.2f}".format(clf.score(X_train,y_train)))
print("Test accuracy: {:.2f}".format(clf.score(X_test,y_test)))

Точность нашего теста улучшилась при использовании меры выбора атрибута энтропии в качестве критерия разделения. Мы можем еще раз взглянуть на дерево, чтобы увидеть, есть ли какие-либо изменения в сделанных разбиениях.

fig, axes = plt.subplots(nrows = 1,ncols = 1,figsize = (16,8), dpi=100)
tree.plot_tree(clf, feature_names = cancer.feature_names, class_names=cancer.target_names, filled = True, fontsize = 5);

Как мы видим, наше дерево довольно сложное, что приводит к переоснащению данных. Мы можем уменьшить сложность дерева, указав максимальную глубину (max_depth) и предотвратив переоснащение.

clf = DecisionTreeClassifier(max_depth=3)
clf.fit(X_train, y_train)
print("Training accuracy:{:.2f}".format(clf.score(X_train,y_train)))
print("Test accuracy: {:.2f}".format(clf.score(X_test,y_test)))

Уменьшив максимальную глубину нашего дерева решений до трех, мы смогли уменьшить переоснащение и немного повысить точность нашего теста. Если мы сейчас рассмотрим нашу древовидную диаграмму, мы увидим гораздо более простое дерево…

Установив max_depth равным 3, мы уменьшили сложность дерева решений, обрезав его. Эта сокращенная модель менее сложна и ее немного легче понять по сравнению с предыдущей моделью, в которой дерево продолжало разбиваться до тех пор, пока все листья не станут чистыми (gini impurtiy = 0).

Регрессия дерева решений

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

import numpy as np
np.random.seed(5)
X = np.sort(5 * np.random.rand(40, 1), axis=0)
y = np.sin(X).ravel()
# Add noise to targets
y[::5] += 1 * (0.5 - np.random.rand(8))

Библиотека scikit-learn предоставляет нам модель дерева решений для регрессии под названием DecisionTreeRegressor (Документация по DecisionTreeRegressor):

from sklearn.tree import DecisionTreeRegressor
dt_reg = DecisionTreeRegressor(criterion="squared_error", random_state=0)
dt_reg.fit(X, y)

fig, axes = plt.subplots(nrows = 1, ncols = 1, figsize=(16,8), dpi=100)
tree.plot_tree(dt_reg, feature_names='X', filled=True, fontsize=5);

#generate a random Test data
T = np.linspace(0, 5, 100)[:, np.newaxis]
#creating two regression trees with different depths
dt_reg_1 = DecisionTreeRegressor(max_depth = 10, random_state=0)
dt_reg_2 = DecisionTreeRegressor(max_depth = 3, random_state=0)
#training the models
dt_reg_1.fit(X, y)
dt_reg_2.fit(X, y)
#making predictions for the random test data we generated above
y_pred_1 = dt_reg_1.predict(T)
y_pred_2 = dt_reg_2.predict(T)
#comparison plot to see the effect of tree depth
plt.figure()
plt.scatter(X, y, s=40, c="orange", label="actual")
plt.plot(T, y_pred_1, color="b", label="max_depth=10", linewidth=2)
plt.plot(T, y_pred_2, color="g", label="max_depth=3", linewidth=2)
plt.xlabel("X")
plt.ylabel("y")
plt.title("Decision Tree Regression")
plt.legend()
plt.show()

Глядя на рисунок, мы видим, как модель регрессора дерева решений с максимальной глубиной, установленной на десять, соответствует данным, захватывая весь шум в данных. Кроме того, дерево с максимальной глубиной, равной трем, намного лучше обобщает и создает лучшее соответствие данным, не захватывая весь шум.

Преимущества

  • Легко понять, интерпретировать и визуализировать
  • Обычно не требуется ни масштабирование, ни нормализация, ни выбор признаков.
  • Хорошо работает с несколькими типами данных (категориальными, числовыми, двоичными) в наборе данных (более простая предварительная обработка данных).
  • Он также подходит для задач с несколькими выходами.

Недостатки

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

Если вам это нравится, не стесняйтесь следовать за мной для получения дополнительных бесплатных руководств и курсов по машинному обучению!