Космический корабль Титаник — это конкурс Kaggle ML. Цель этого состоит в том, чтобы предсказать, какие пассажиры смогли перейти в другое измерение.

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

Но сначала давайте познакомимся с нашими пассажирами или набором данных:

  • 8693 образца – пассажиры
  • Функции:HomePlanet, CryoSleep, Cabin, Destination, Age, VIP,
    RoomService, FoodCourt, ShoppingMall, Spa, VRDeck, Name
  • Ярлык:перемещено

Пояснения к ярлыкам см. по ссылке на веб-сайт Kaggle.

Загрузка данных

Загрузите 3 файла csv (обучение, тест и отправка) с конкурса страница данных. (Submission.csv — это пример файла отправки, показывающий правильный формат.)

Загрузите наборы данных, прочитав файлы train.csv и test.csv с помощью pandas.

import pandas as pd
train_dataFull = pd.read_csv('train.csv', index_col='PassengerId')
test_dataFull = pd.read_csv('test.csv', index_col='PassengerId')

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

Второй шаг — предварительная обработка данных для избавления от нулевых значений и кодирования нечисловых значений.

В этом наборе данных есть два ненужных столбца.

  • Первым является столбец Name, потому что имена не являются числовыми данными и содержат слишком много уникальных значений.
  • Второй столбец Cabin. В этом столбце 6560 уникальных значений. Вы можете проверить количество уникальных значений с помощью следующего кода.
print(len(train_dataFull['Cabin'].value_counts()))

Давайте удалим эти столбцы из набора данных.

train_data = train_dataFull.drop(['Cabin', 'Name'], axis=1)
test_data = test_dataFull.drop(['Cabin', 'Name'], axis=1)

Определение X и y

y — это цель — то, что мы пытаемся предсказать.

y = train_data.Transported

Значения X — это входные данные — функции, которые позволяют нам прогнозировать. Другими словами, функции, кроме y.

X_train = train_data.drop(['Transported'], axis=1)

Разделение числовых и нечисловых данных

В этом наборе данных есть числовые и нечисловые данные. Чтобы создать модель и делать прогнозы, мы собираемся превратить нечисловые значения в категориальные переменные — таким образом, мы сможем представить их числами.

#columns with non-numeric data
objectCols = list(X_train.select_dtypes(['object']).columns)

Столбцы объектов: HomePlanet, CryoSleep, Destination и VIP.

Работа с нулевыми значениями

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

Давайте проверим количество значений NA в столбце:

#check number of na values in the cols
for col in features:
    print(col + ': ' + str(X_train[col].isna().sum()))

Как видно из вывода, среди 8693 значений есть от 179 до 217 нулевых значений. Другими словами, в этих столбцах отсутствует около 2,45% данных.

Мы собираемся вменить эти нулевые значения, используя разные стратегии.

Вот числовые столбцы с пропущенными значениями:

#imputation for Age, RoomService, FoodCourt, Shopping Mall, Spa, VRDeck - numeric cols
colsMissingNumeric = ['Age', 'RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck']

Для числовых столбцов я решил заполнить их средними значениями.

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

from sklearn.impute import SimpleImputer
myImputerNumeric = SimpleImputer(strategy='mean')
imputed_X_train_numeric = pd.DataFrame(myImputerNumeric.fit_transform(X_train[colsMissingNumeric]))
imputed_test_numeric = pd.DataFrame(myImputerNumeric.transform(test_data[colsMissingNumeric]))

После этого преобразования мы теряем имена столбцов и индексы:

RangeIndex(начало=0, стоп=6, шаг=1)

#name imputed cols
imputed_X_train_numeric.columns = X_train[colsMissingNumeric].columns
imputed_test_numeric.columns = test_data[colsMissingNumeric].columns
#add indexes
imputed_X_train_numeric.index = X_train.index
imputed_test_numeric.index = test_data.index

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

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

В этом примере я получил лучшие результаты со стратегией most_frequent.

#impute object cols before encoding
myImputerObject = SimpleImputer(strategy='most_frequent')
imputed_X_train_object = pd.DataFrame(myImputerObject.fit_transform(X_train[objectCols]))
imputed_test_object = pd.DataFrame(myImputerObject.transform(test_data[objectCols]))
#name imputed cols
imputed_X_train_object.columns = X_train[objectCols].columns
imputed_test_object.columns = test_data[objectCols].columns

Кодирование категориальных столбцов

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

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

# check cols that can be encoded-less than 15 unique values
for col in objectCols:
    print(train_dataFull[col].value_counts())

Как видно сверху:

Родная планета имеет 3 уникальных значения: Земля, Европа и Марс

CryoSleep имеет 2 уникальных значения (boolean)

Пункт назначения имеет 3 уникальных значения: TRAPPIST-1e, 55 Cancri e, PSO J318.5–22.

VIP имеет 2 уникальных значения (boolean)

Горячее кодирование

Так как между категориальными переменными нет порядковой связи (одна категориальная переменная не меньше или больше другой), может применяться однократное кодирование.

Для получения дополнительной информации о горячем кодировании перейдите по этой ссылке.

#encode imputed object cols with one hot encoding 
#these cols are not suitable for ordering and have low cardinality
OH_encoder = OneHotEncoder(handle_unknown='ignore', sparse=False)
OH_cols_train = pd.DataFrame(OH_encoder.fit_transform(imputed_X_train_object))
OH_cols_test = pd.DataFrame(OH_encoder.transform(imputed_test_object))
#add index column
OH_cols_train.index = X_train.index
OH_cols_test.index = test_data.index

Теперь у нас есть,

  • фрейм данных вмененных числовых значений
  • кадр данных вмененных и закодированных категориальных значений отдельно.

Мы можем объединить их с помощью следующего кода:

OH_X_train = pd.concat([imputed_X_train_numeric,OH_cols_train], axis=1)
OH_X_valid = pd.concat([imputed_test_numeric,OH_cols_test], axis=1)

Создание модели

Я использовал два разных алгоритма для наблюдения за точностью прогнозов.

Алгоритм случайного леса

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

Для получения дополнительной информации об алгоритме случайного леса перейдите по ссылке эта ссылка.

titanic_model = RandomForestRegressor(n_estimators = 100, random_state = 0)
titanic_model.fit(OH_X_train, y)
predictions = titanic_model.predict(OH_X_valid)

с алгоритмом случайного леса точность: 0,78816

Алгоритм XGBoost

Gradient Boosting просто получает наивную модель, вычисляет потери, обучает модель в соответствии с ней и итеративно повторяет этот процесс.

Для получения дополнительной информации о XGBoost перейдите по этой ссылке.

#XGB
titanic_model = XGBRegressor(n_estimators=1000, learning_rate=0.05)
titanic_model.fit(OH_X_train, y)
predictions = titanic_model.predict(OH_X_valid)

с XGBoost точность: 0,79120

Для получения дополнительной информации о XGBoost и алгоритме Random Forest вы также можете ознакомиться с этой статьей на Medium.

Полный исходный код доступен по моей ссылке на github. ✨

На этом наше приключение подошло к концу, спасибо за прочтение. Давайте встретимся в комментариях. 🚀