Набор данных: «Титаник» — машинное обучение после катастрофы

В этой статье мы исследуем практическую реализацию алгоритма дерева решений с использованием scikit-learn. Мы рассмотрим различные важные концепции, связанные с решением типичной задачи машинного обучения, включая обучение и настройку модели.

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



Терминология с использованием аналогии с кухней

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

Обучение, проверка и тестирование с использованием аналогии студента

Представьте себе студента, готовящегося к экзамену по математике.

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

Шаг 4: Разделение данных

Когда мы обучаем модели, мы не хотим использовать все предоставленные обучающие данные, которые у нас есть. Вместо этого мы разделили его на три части.

Во-первых, мы разделяем предоставленные данные на

  1. Исследование данных. Мы используем эти данные для построения хорошей модели, обучая ее и корректируя определенные параметры (гиперпараметры).
  2. Тестовые данные. Мы не трогаем их, пока не убедимся, что наша модель хорошо работает с исследовательскими данными. Мы можем использовать эти данные, чтобы предоставить объективную оценку производительности нашей модели.

Далее мы разделяем исследовательские данные еще дальше.

  1. Данные для обучения. Мы используем эти данные для обучения нашей модели. Именно здесь модель учится на данных, чтобы делать точные прогнозы.
  2. Проверочные данные. Мы используем их для сравнения различных моделей и выбора их гиперпараметров и выбора наиболее эффективных из них.

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

from sklearn.model_selection import train_test_split

# Split the columns into features (X) and target variable (y)
X = train_data_p.loc[:, train_data_p.columns != 'Survived']
y = train_data_p['Survived']

# Split the train data into training, validation and test datasets
# Original train data = 80% exploratory + 20% test
# Exploratory data = 70% training + 30% validation
X_explore, X_test, y_explore, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train, X_val, y_train, y_val = train_test_split(X_explore, y_explore, test_size=0.3, random_state=42)

print("Original dataset: ", X.shape, y.shape)
print("Training dataset: ", X_train.shape, y_train.shape)
print("Validation dataset: ", X_val.shape, y_val.shape)
print("Test dataset: ", X_test.shape, y_test.shape)

Шаг 5: Обучение

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

Давайте приступим к реализации классификатора дерева решений с использованием библиотеки scikit-learn.

from sklearn import tree
from sklearn import metrics

# Create a decision tree classifier object
clf = tree.DecisionTreeClassifier(random_state=42)

# Train the decision tree on the training dataset (X_train, y_train)
clf.fit(X_train, y_train)

# Predict the survival outcomes on the validation dataset (X_val)
y_val_pred = clf.predict(X_val)

Чтобы визуализировать дерево решений, вы можете использовать приведенный ниже код. Регулируя параметр max_depth, вы можете управлять глубиной дерева. Удалите max_depth из кода ниже, чтобы увидеть полное дерево, построенное моделью.

tree.plot_tree(clf, feature_names=X_train.columns, max_depth=1)

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

print("Accuracy of decision tree classifier on training data: ", clf.score(X_train, y_train))
print("Accuracy of decision tree classifier on validation data: ", clf.score(X_val, y_val))
print("Max depth of decision tree classifier : ", format(clf.tree_.max_depth))

Шаг 6: Настройка гиперпараметров

Из приведенных выше значений точности мы видим, что модель переоснащает данные обучения с высокой точностью 1,0 для данных обучения, но с меньшей точностью 0,73 для данных проверки.

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

  1. max_depth : максимальная глубина дерева. Если None, то узлы расширяются до тех пор, пока все листья не станут чистыми или пока все листья не будут содержать менее min_samples_split выборок.
  2. min_samples_split : минимальное количество выборок, необходимое для разделения внутреннего узла. Значение по умолчанию — 2.

Другие параметры см. в документации ниже.



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

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

max_depths_tuning = [3,4,5,6,7,8]

clfs = []
for max_depth in max_depths_tuning:
    clf = tree.DecisionTreeClassifier(random_state=42, max_depth=max_depth)
    clf.fit(X_train, y_train)
    clfs.append(clf)

# plot the accuracy score on training and validation datasets for different max_depth values
train_scores = [clf.score(X_train, y_train) for clf in clfs]
val_scores = [clf.score(X_val, y_val) for clf in clfs]

fig, ax = plt.subplots()
ax.plot(max_depths_tuning, train_scores, marker='o', label='train', drawstyle='steps-post')
ax.plot(max_depths_tuning, val_scores, marker='o', label='val', drawstyle='steps-post')
ax.set_xlabel("max_depth")
ax.set_ylabel("accuracy")
ax.set_title("Accuracy vs max_depth for training and testing sets")
ax.legend()
plt.show()

  • График ясно показывает, что по мере того, как мы делаем дерево решений глубже, оно становится лучше для точного прогнозирования обучающих данных.
  • Однако это улучшение не работает, когда речь идет о новых, невидимых данных. Точность проверочного набора начинает падать, что указывает на переоснащение.
  • Но в max_depth = 4, мы находим баланс. Модель хорошо работает как с данными обучения, так и с данными проверки, демонстрируя свою способность обобщать и делать точные прогнозы.

GridSearchCV

Если мы хотим точно настроить несколько гиперпараметров, таких как min_sample_split и num_features, мы можем обратиться к удобному инструменту, предоставленному scikit-learn, который называется GridSearchCV. (Есть и другие методы!)

Перекрестная проверка (CV) – это метод, при котором вы

  • Разделите набор обучающих данных на k групп.
  • Попробуйте различные комбинации гиперпараметров, обучая модель на k-1 группах и тестируя оставшуюся группу.
  • Оцените производительность каждой комбинации и выберите оптимальные параметры.

Поиск по сетке включает в себя обучение нашей модели всем возможным комбинациям указанных гиперпараметров в k-1 группах, а затем тестирование модели в оставшейся группе. Он сравнивает и находит комбинацию гиперпараметров, которая дает наилучшую точность для нашей модели.

from sklearn.model_selection import GridSearchCV

tuned_params = [{'max_depth': [2,3,4,5,6,7,8], 'min_samples_split': [20,30,40,50,60,70,80,90]}]
tclf = GridSearchCV(tree.DecisionTreeClassifier(), tuned_params, scoring='accuracy')

# Using exploratory data directly instead of training data
# as the cross validation algorithm splits the provided data
# into training and validation groups internally
tclf.fit(X_explore, y_explore)

ix = tclf.best_index_
print(tclf.best_params_)
print('Index of the combination: ', ix)

  • В этом примере у нас есть 7 возможных значений для max_depth и 8 возможных значений для min_samples_split.
  • Это означает, что у нас есть всего 56 комбинаций параметров, которые можно опробовать.
  • GridSearchCV строит и оценивает 56 моделей, используя перекрестную проверку предоставленных данных, а затем сообщает нам наилучшую комбинацию гиперпараметров, дающую максимальную оценку.

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

train_scores = tclf.cv_results_["mean_train_score"]
val_scores = tclf.cv_results_["mean_test_score"]
index = np.arange(len(tclf.cv_results_["params"]))

fig, ax = plt.subplots()
ax.plot(index, train_scores, marker='o', label='train', drawstyle='steps-post')
ax.plot(index, val_scores, marker='o', label='val', drawstyle='steps-post')
ax.set_xlabel("Index")
ax.set_ylabel("Accuracy")
ax.set_title("Train and test scores for different hyperparameters")
ax.legend()
plt.show()

В индексе 8 мы видим, что и поезд, и тест имеют самые высокие оценки. Это соответствует комбинации гиперпараметров {'max_depth': 3, 'min_samples_split': 20}, в чем мы можем убедиться, обратившись к tclf.cv_results_["params"][8].

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

print("Accuracy of tuned decision tree classifier on training data: ", train_scores[8])
print("Accuracy of tuned decision tree classifier on validation data: ", val_scores[8])
print("Accuracy of tuned decision tree classifier on unseen test data: ", tclf.score(X_test, y_test))

Шаг 7: Заключительный шаг

Поскольку значения точности для всех трех моделей одинаковы, это указывает на то, что наша модель не переоснащается.

Теперь мы можем приступить к обучению модели с использованием настроенных гиперпараметров на всем предоставленном обучающем наборе данных и делать прогнозы на тестовом наборе данных, предоставленном Kaggle.

Отправка выходных данных, сгенерированных приведенным ниже кодом, привела к получению оценки 0,7799.

# Create a decision tree classifier object using the tuned hyperparameters
clf = tree.DecisionTreeClassifier(max_depth=3, min_samples_split=20, random_state=42)

# Train the decision tree on the entire training dataset
clf.fit(X, y)

# Predict the survival outcomes on the provided test dataset (X_val)
X_final_test = test_data_p.loc[:, train_data_p.columns != 'Survived']
predictions = clf.predict(X_final_test)

# create output file
output = pd.DataFrame({'PassengerId': test_data.PassengerId, 'Survived': predictions})
output.to_csv('submission.csv', index=False)

Дальнейшие шаги:

Не стесняйтесь исследовать классификатор Random Forest, перейдя по этой ссылке.

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