Решение титанического набора данных машинного обучения Kaggle

Набор данных Kaggle Titanic Machine Learning Dataset - классическое открытое введение в сферу машинного обучения. Хотя это может быть проект для начинающих, все же есть таблица лидеров (приятно видеть, как вы повышаете свой рейтинг по мере того, как вы продолжаете работать над своим кодом).

Для начала необходимо загрузить файлы train.csv и test.csv прямо из Kaggle. Его можно скачать здесь: https://www.kaggle.com/c/titanic/data. Убедитесь, что файлы размещены в специально отведенном месте, и их можно будет вытащить позже.

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

Программное обеспечение, которое я буду использовать в этом проекте, будет Google Colab. Однако в данной ситуации это не имеет особого значения. Нам не нужен графический процессор. Ноутбуки Jupyter без графического процессора будут работать нормально. Первое, что нужно сделать в этом проекте, как и во многих других в информатике и машинном обучении, - это запрограммировать импорт, который нам нужен.

import pandas as pd 
from sklearn.model_selection import train_test_split 
from sklearn.ensemble import RandomForestClassifier 

Pandas будет использоваться для анализа файлов для этой задачи. Второй импорт, «train_test_split», будет использоваться для разделения и разделения файлов обучения и тестирования. Последним импортом, который нам понадобится, будет RandomForestClassifier, большой всеобъемлющий импорт, необходимый для использования случайных лесов.

Как я уже сказал, я использую Google Colab. Итак, мне нужно «смонтировать» программу на Google Colab, чтобы получить доступ к Google Диску. Я сделаю это с помощью следующего кода.

from google.colab import drive 
drive.mount('/content/gdrive')

Теперь мы должны принять файлы .csv соответствующим образом. Это можно сделать с помощью следующего кода.

train_df = pd.read_csv('/content/gdrive/My Drive/train.csv') 
test_df = pd.read_csv('/content/gdrive/My Drive/test.csv') 

Далее я собираюсь опустить разнообразную категориальную информацию. Сюда входят билеты, каюты и имена. Имена были удалены, поскольку обычно они не имели отношения к корреляции между выживанием или нет. Тем не менее, если бы это был очень глубокий анализ, некоторые имена могли быть более «важными». Например, по фамилии или префиксу. Однако по большей части это было бы слишком много зря. Кроме того, в информации о билетах и ​​салоне не было конкуренции, поэтому было лучше не принимать во внимание все эти наборы данных.

Это можно сделать с помощью следующего кода.

train_df = train_df.drop(['Name'],  axis=1) 
test_df = test_df.drop(['Name'], axis=1) 
train_df = train_df.drop(['Cabin'],  axis=1) 
test_df = test_df.drop(['Cabin'], axis=1)
train_df = train_df.drop(['Ticket'],  axis=1) 
test_df = test_df.drop(['Ticket'], axis=1)

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

train_df

То же самое можно сделать и с тестовыми данными.

test_df

Затем мы должны рассмотреть категорию «начато» в наборе данных. Как и в наборе данных о билетах и ​​каютах, значения отсутствуют. Однако существенных пробелов не так много. Наиболее частым начальным значением является «S», поэтому для нескольких пропущенных значений они будут просто заполнены буквой «S». Это неточно и неточно, но каждое значение должно быть заполнено.

common_value = 'S' 
data = [train_df, test_df] 
for dataset in data:
   dataset['Embarked'] = dataset['Embarked'].fillna(common_value)     

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

def clean_sex(train_df):
   try:
      return train_df[0]
   except TypeError:
      return "None"
train_df["Sex"] = train_df.Sex.apply(clean_sex) 
categorical_variables = ['Sex', 'Embarked'] 
for variable in categorical_variables:
   train_df[variable].fillna("Missing", inplace=True) 
   discarded = pd.get_dummies(train_df[variable],prefix = variable)        
   train_df= pd.concat([train_df, discarded], axis = 1)
   train_df.drop([variable], axis = 1, inplace = True) 

Вышесказанное было применено к данным «поезда». Теперь мы должны сделать то же самое для «тестового» набора данных.

def clean_sex(test_df):
try:
   return test_df[0] 
except TypeError:
   return "None"
test_df["Sex"] = test_df.Sex.apply(clean_sex) 
categorical_variables = ['Sex', 'Embarked']
for variable in categorical_variables:
   test_df[variable].fillna("Missing", inplace=True)
   discarded = pd.get_dummies(test_df[variable], prefix = variable)
   test_df= pd.concat([test_df, discarded], axis = 1)
   test_df.drop([variable], axis = 1, inplace = True) 

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

train_df["Age"].fillna (train_df.Age.mean(), inplace = True)
test_df["Age"].fillna (test_df.Age.mean(), inplace = True)

train_df["Fare"].fillna (train_df.Fare.mean(), inplace = True)
test_df["Fare"].fillna (test_df.Fare.mean(), inplace = True)

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

Это напечатает «поезд» обработанных данных.

train_df

Это напечатает «тестовые» обработанные данные.

test_df

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

train_df = train_df.round({'Age':0})
test_df = test_df.round({'Age':0})

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

Итак, для нашей локальной оценки мы опустим значение «сохранившееся» в данных поезда для новой переменной под названием «X_train». Затем для «Y_train» мы добавим только «Выжившие». Затем мы сделаем X_test равным test_df напрямую. Наконец, распечатайте форму.

X_train = train_df.drop("Survived", axis=1) 
Y_train = train_df["Survived"] 
X_test  = test_df 
X_train.shape, Y_train.shape, X_test.shape

Чтобы перепроверить, может быть полезно распечатать x_train. Опять же, это можно сделать просто с помощью следующей команды.

X_train

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

random_forest = RandomForestClassifier(criterion='gini',
    n_estimators=700, 
    min_samples_split=10, 
    min_samples_leaf=1, 
    max_features='auto', 
    oob_score=True, 
    random_state=1,
    n_jobs=-1) 
random_forest.fit(X_train, Y_train)
Y_pred = random_forest.predict(X_test) 
acc_random_forest = round(random_forest.score(X_train, Y_train) * 100, 2) 
acc_random_forest 

Значение «n_estimators» представляет количество оценок, используемых в случайном лесу (количество деревьев в лесу). В данном случае 700 было подходящим значением. «Min_samples_split» - это количество выборок (минимум), необходимое для разделения и разделения внутреннего узла. «Min_samples_leaf» представляет минимальное количество выборок, необходимых для того, чтобы быть листовым узлом. «Max_features» используется для описания размера случайных подмножеств функций, учитываемых при разделении узла. Если установлено значение «Авто», подмножество функций отсутствует. Если для параметра «oob_score» задано значение «истина», будет предпринята попытка проверки модели случайного леса с оценкой «Нет в сумке». Когда для «n_jobs» установлено значение -1, для работы будут использоваться все процессоры.

Последний сегмент приведенного выше кода соответствует модели и дает прогноз (y_pred), который работает вместе с данными X_test. Затем будет распечатана точность случайного леса. Локальное тестирование этих данных дает точность примерно 90% (91,81%). Однако это всего лишь локальный прогноз, основанный на отделении значений выживаемости от обучающего набора данных. Чтобы получить точную оценку, нам нужно отправить ее непосредственно в Kaggle. Для этого напишите следующий код, чтобы получить файл «submission.csv».

submission = pd.DataFrame({
    "PassengerId": test_df["PassengerId"],
    "Survived": Y_pred
})
submission.to_csv('submission.csv', index=False)

Вывод:

Kaggle дает значение точности «0,79186» или «79,186%». Когда я представил этот прогноз, я получил 1573 место из 19649, что составляет примерно 8% лучших. Разница между локальным прогнозом и прогнозом Kaggle заключается в том, что данные «поезда» были модифицированы как «тестовый гибридный» набор данных, а Kaggle использовал фактические «тестовые данные». Тем не менее, в обеих ситуациях был уровень рандомизации.

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