Импортируем все необходимые библиотеки
In [274]:
# pandas
import pandas as pd
from pandas import DataFrame
import re
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
%matplotlib inline
# machine learning
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import learning_curve, train_test_split, GridSearchCV
from sklearn.metrics import make_scorer, accuracy_score
Загружаем наши данные и смотрим на их состояние
In [275]:
# your code here
# train_df
# test_df
train_df.head()
Out[275]:
In [276]:
train_df.info()
print("----------------------------")
test_df.info()
Легко заметить, что в тренировочном датасете у нас не хватает данных о возрасте, каюте и месте погружения пассажира на корабль. В тестовом датасете нам не хватает данных о возрасте, каюте и плате за пребывание на корабле.
Для начала разберемся с полем Embarked в тренировочном датасете, которое отвечает за место погружения. Проверим, в каких строках у нас отсутствуют данные.
In [277]:
# Embarked
# your code here
Out[277]:
Посмотрим на общею зависимость шанса выживания от пункта погружения.
In [2]:
fig, (axis1,axis2,axis3) = plt.subplots(1,3,figsize=(15,5))
sns.countplot(x='Embarked', data=train_df, ax=axis1)
sns.countplot(x='Survived', hue="Embarked", data=train_df, order=[1,0], ax=axis2)
# group by embarked, and get the mean for survived passengers for each value in Embarked
embark_perc = train_df[["Embarked", "Survived"]].groupby(['Embarked'],as_index=False).mean()
sns.barplot(x='Embarked', y='Survived', data=embark_perc,order=['S','C','Q'],ax=axis3)
Смотрим на другие возможные зависимости, которые могли б нам указать на то, где пассажиры попали на корабль.
In [279]:
# проверить пассажиров с билетом 113572
Out[279]:
In [280]:
# вывести кол-во пассажиров с ценами от 75 до 85
In [281]:
# присвоить пустым значениям те, которые мы решили
In [282]:
# проверить что пустых больше нет
Out[282]:
Теперь исправим пустое поле с платой за путешествение в тестовом датасете.
In [283]:
# показать пустые в тестовом датасете с полем Fare
Out[283]:
Давайте посмотрим на всех пассажиров, с похожими другими признаками.
In [284]:
fig = plt.figure(figsize=(8, 5))
ax = fig.add_subplot(111)
test_df[(test_df.Pclass==3)&(test_df.Embarked=='S')].Fare.hist(bins=100, ax=ax)
plt.xlabel('Fare')
plt.ylabel('Frequency')
plt.title('Histogram of Fare, Plcass 3 and Embarked S')
Out[284]:
In [285]:
print ("The top 5 most common value of Fare")
# вывести топ 5 самых популярных значений для 3го класса (подсказка .value_counts() )
Out[285]:
Делаем вывод, что вероятнее всего плата была в таком размере.
In [286]:
test_df.set_value(test_df.Fare.isnull(), 'Fare', 8.05)
test_df.loc[test_df.Fare.isnull()]
Out[286]:
Теперь разберемся с полем Возраста в тренировочном датасете. Ему нужно уделить больше внимания, т.к. это очень важный признак, который сильно влияет на выживаемость пассажиров.
In [287]:
# вывести пустые с возрастом
Out[287]:
In [288]:
#fig, (axis1,axis2) = plt.subplots(1,2,figsize=(15,4))
#axis1.set_title('Original Age values')
#axis2.set_title('New Age values')
# среднее, дисперсия и пустые значение в тестовом датасете ( .mean() .std() .isnull().sum() )
#average_age_train =
#std_age_train =
#count_nan_age_train =
# среднее, дисперсия и пустые значение в тестовом датасете
#average_age_test =
#std_age_test =
#count_nan_age_test =
# генерируем случайные значения (mean - std) & (mean + std)
rand_1 = np.random.randint(average_age_train - std_age_train, average_age_train + std_age_train, size = count_nan_age_train)
rand_2 = np.random.randint(average_age_test - std_age_test, average_age_test + std_age_test, size = count_nan_age_test)
# строим гистограму возраста до изменений (пустые конвертим в инты)
train_df['Age'].dropna().astype(int).hist(bins=70, ax=axis1)
test_df['Age'].dropna().astype(int).hist(bins=70, ax=axis1)
# заполняем случайными значениями пустые поля с возрастом
train_df["Age"][np.isnan(train_df["Age"])] = rand_1
test_df["Age"][np.isnan(test_df["Age"])] = rand_2
# конвертим флоаты в инты
train_df['Age'] = train_df['Age'].astype(int)
test_df['Age'] = test_df['Age'].astype(int)
# гистограма нового возраста
train_df['Age'].hist(bins=70, ax=axis2)
test_df['Age'].hist(bins=70, ax=axis2)
Out[288]:
In [289]:
# Еще немного графиков
# пик выживаемости в зависимости от возраста
facet = sns.FacetGrid(train_df, hue="Survived",aspect=4)
facet.map(sns.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train_df['Age'].max()))
facet.add_legend()
# средняя выживаемость по возрасту
fig, axis1 = plt.subplots(1,1,figsize=(18,4))
average_age = train_df[["Age", "Survived"]].groupby(['Age'],as_index=False).mean()
sns.barplot(x='Age', y='Survived', data=average_age)
Out[289]:
In [290]:
# проверим статус наших датасетов после преобразование данных
В именах есть приставки, с ними тоже можно кое-что сделать, т.к. социальный статус может быть важным признаком выживаемости.
In [292]:
Title_Dictionary = {
"Capt": "Officer",
"Col": "Officer",
"Major": "Officer",
"Jonkheer": "Nobel",
"Don": "Nobel",
"Sir" : "Nobel",
"Dr": "Officer",
"Rev": "Officer",
"the Countess":"Nobel",
"Dona": "Nobel",
"Mme": "Mrs",
"Mlle": "Miss",
"Ms": "Mrs",
"Mr" : "Mr",
"Mrs" : "Mrs",
"Miss" : "Miss",
"Master" : "Master",
"Lady" : "Nobel"
}
#train_df['Title'] =
#test_df['Title'] =
train_df.head()
Out[292]:
Вместо двух полей указывающий на наличие партнера (Parch) или родственника (SibSp), сделаем одно поле FamilySize
In [293]:
#train_df['FamilySize'] =
#test_df['FamilySize'] =
train_df.head()
Out[293]:
Пол тоже очень важный признак, но если вы смотрели фильм титаник, то наверное помните "Сначала женщин и детей." Поэтому предлагаю сооздать новый признак, который будет учитывать как пол, так и возраст
In [294]:
def get_person(passenger):
# your code here
pass
train_df['Person'] = train_df[['Age','Sex']].apply(get_person,axis=1)
test_df['Person'] = test_df[['Age','Sex']].apply(get_person,axis=1)
train_df.head()
Out[294]:
In [295]:
# print status of datasets
Убедились, что теперь наши данные в порядке и переходим к откидыванию лишнего.
In [297]:
# drop 'Name', 'Cabin', 'Ticket', 'SibSp', 'Parch', 'Sex'. Drop 'PassengerId' only for traind_df
train_df.drop(labels=['PassengerId', 'Name', 'Cabin', 'Ticket', 'SibSp', 'Parch', 'Sex'], axis=1, inplace=True)
test_df.drop(labels=['Name', 'Cabin', 'Ticket', 'SibSp', 'Parch', 'Sex'], axis=1, inplace=True)
In [298]:
train_df.head()
Out[298]:
У нас есть дискретные переменные и нам стоило б их закодировать. Для этого в пандас уже существует функция get_dummies
In [299]:
# кодировать переменные с помощью get_dummies, http://pandas.pydata.org/pandas-docs/version/0.18.1/generated/pandas.get_dummies.html
#dummies_person_train =
#dummies_embarked_train =
#dummies_title_train =
#dummies_pclass_train =
# обьеденяем добавляем новые переменные в наш датафрейм с помощью concat(), http://pandas.pydata.org/pandas-docs/stable/generated/pandas.concat.html
#train_df =
#train_df =
train_df.head()
Out[299]:
In [300]:
# Аналогично для тестового датасета
#dummies_person_test =
#dummies_embarked_test =
#dummies_title_test =
#dummies_pclass_test =
#test_df =
#test_df =
test_df.head()
Out[300]:
Создадим функцию, которая будет строить зависимость обучаемости от кол-ва тестовых семплов.
In [ ]:
# не вдаемся в подробности, используем готовый код
def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,
n_jobs=1, train_sizes=np.linspace(.1, 1.0, 5), scoring='accuracy'):
plt.figure(figsize=(10,6))
plt.title(title)
if ylim is not None:
plt.ylim(*ylim)
plt.xlabel("Training examples")
plt.ylabel(scoring)
train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=cv, scoring=scoring,
n_jobs=n_jobs, train_sizes=train_sizes)
train_scores_mean = np.mean(train_scores, axis=1)
train_scores_std = np.std(train_scores, axis=1)
test_scores_mean = np.mean(test_scores, axis=1)
test_scores_std = np.std(test_scores, axis=1)
plt.grid()
plt.fill_between(train_sizes, train_scores_mean - train_scores_std,
train_scores_mean + train_scores_std, alpha=0.1,
color="r")
plt.fill_between(train_sizes, test_scores_mean - test_scores_std,
test_scores_mean + test_scores_std, alpha=0.1, color="g")
plt.plot(train_sizes, train_scores_mean, 'o-', color="r",
label="Training score")
plt.plot(train_sizes, test_scores_mean, 'o-', color="g",
label="Cross-validation score")
plt.legend(loc="best")
return plt
Разбиваем наш тренировочный датасет на 2, что б прежде чем сабмитить нашу модель, мы убедились что она не переобучается на наших данных (т.н. кросс-валидация)
In [301]:
# использовать train_test_split
X = train_df.drop(['Survived'], axis=1)
y = train_df.Survived
X_train, X_test, y_train, y_test =
Модель случайного леса это ничто иное как ансамбль решающих деревьев:
Который в результате будет выглядить где-то так:
Настоятельно рекомендую просмотреть это видео (https://www.youtube.com/watch?v=loNcrMjYh64) если вас интерисует как работает этот алгоритм
Посмотрим модель случайного леса. Параметры укажем обычные, потом благодаря GridSearchCV подберем оптимальные. Ну и в конце взглянем на то, что у нас вышло
In [303]:
# создадим обьект нашего классификатора
clf = RandomForestClassifier()
# задаем параметры случайным образом
parameters = {'n_estimators': [4, 6, 9],
'max_features': ['log2', 'sqrt','auto'],
'criterion': ['entropy', 'gini'],
'max_depth': [2, 3, 5, 10],
'min_samples_split': [2, 3, 5],
'min_samples_leaf': [1,5,8]
}
# параметр для расчета точности нашей модели
acc_scorer = make_scorer(accuracy_score)
# подбираем оптимальные параметры для нашей модели с помощью GridSearchCV
# grid_obj =
# устанавливаем полученные параметры для нашей модели
clf = grid_obj.best_estimator_
clf.fit(X_train, y_train)
Out[303]:
In [3]:
# Посмотрим скорость обучения нашей модели
predictions = clf.predict(X_test)
print(accuracy_score(y_test, predictions))
plot_learning_curve(clf, 'Random Forest', X, y, cv=4);
Повторим все выше описанные процедуры, которые мы делали для рандом фореста, теперь для логистической регрессии.
Функция активации для логистической регрессии (сигмоид):
Cost function:
In [310]:
from sklearn.linear_model import LogisticRegression
lg = LogisticRegression(random_state=42, penalty='l1')
parameters = {'C':[0.5]}
acc_scorer_lg = make_scorer(accuracy_score)
# параметр для расчета точности нашей модели
# grid_obj_lg =
# устанавливаем полученные параметры для нашей модели
lg = grid_obj_lg.best_estimator_
lg.fit(X_train, y_train)
Out[310]:
In [307]:
# Посмотрим скорость обучения нашей модели
predictions_lg = lg.predict(X_test)
print(accuracy_score(y_test, predictions_lg))
plot_learning_curve(lg, 'Logistic Regression', X, y, cv=4);
Выбираем ту модель, которая нам больше понравилась и сабмитим ее на кагл.
In [ ]:
# Можем засабмитить нашу модель
#ids = test_df['PassengerId']
#predictions = clf.predict(test_df.drop('PassengerId', axis=1))
#output = pd.DataFrame({ 'PassengerId' : ids, 'Survived': predictions })
#output.to_csv('titanic-predictions.csv', index = False)
#output.head()