Titanic

Soy nuevo en estos temas pero después de mucho tiempo estudiando un poco aquí y allá decidí comenzar con mi primer artículo de Machine Learning, espero comparar varios algoritmos usando el dataset del Titanic y encontrar el que sea mas acertado. Bienvenidos!

El Titanic es el dataset que Kaggle usa para enseñar a los miembros el uso del Machine Learning y el uso de Kaggle. Es un ejemplo sencillo que tiene multiples campos de los pasajeros además de tener el campo que indica si sobrevivió o no. El ejemplo incluye los datasets:

  • training set (train.csv)
  • test set (test.csv)

Training set este dataset es el que se debe utilizar para crear los modelos de Machine Learning.

Test set este dataset es el que se usará para validar como se comportan los modelos que creaste; es decir, que tan acertado fuimos en decir quien sobrevive o no.

Data Dictionary

Definicion de la tabla tomado de Kaggle

Variable Definition Key
survival Survival 0 = No, 1 = Yes
pclass Ticket class 1 = 1st, 2 = 2nd, 3 = 3rd
sex Sex
Age Age in years
sibsp # of siblings / spouses aboard the Titanic
parch # of parents / children aboard the Titanic
ticket Ticket number
fare Passenger fare
cabin Cabin number
embarked Port of Embarkation C = Cherbourg, Q = Queenstown, S = Southampton

Si quieren saber más información de los datasets les recomiendo ir a la página de Kaggle y mirar los comentarios que hacen acerca de estos.

Análisis de los datos

Lo primero que debemos realizar cuando vamos a comenzar un proceso de Machine Learning (ML) es saber como son los datos con los que estamos trabajando, cómo están distribuidos, cómo se relacionan, encontrar valores nulos, etc.

Importar librerias

In [1]:
import pandas as pd               #Para manejo de datos
import seaborn as sns             #Para realizar gráficas
import matplotlib.pyplot as plt   #Para algunos parámetros de las gráficas
#Para visualizar las gráficas en el notebook
%matplotlib inline

Importar datasets

Importamos los archivos csv que tiene la página de Kaggle, usamos Pandas read_csv para esto

In [2]:
titanic_train = pd.read_csv('train.csv')
titanic_test = pd.read_csv('test.csv')

Analizamos los datasets

En esta parte simplemente estamos viendo la información que cargamos en las variables que creamos a partir de los archivos, que en este caso corresponden a DataFrames de Pandas.

A primera vista podemos ver que el dataset de train tiene la columna Survived y el de Train no la tiene, esto se debe a que la idea del ejercicio es determinar los valores de esta columna para el dataset de test.

In [3]:
titanic_train.head()
Out[3]:
TitanicTabla1
In [4]:
titanic_test.head()
Out[4]:
TitanicTabla2

Más análisis del dataset Train

En esta parte vemos que nuestro dataset tiene 891 filas y que las columnas Age, Cabin y Embarked tienen menos datos que las demás. Además en la parte de abajo podemos ver datos como la media y la desviación estándar, etc.

In [5]:
titanic_train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB
In [6]:
titanic_train.describe()
Out[6]:
TitanicTabla3

Visualizamos los datos

Ahora intentamos obtener un resumen gráfico de los datos para tener una mejor idea de los datos con los cuales estamos trabajando. Como yo me vi la película Titanic recuerdo una frase que decía “Mujeres y niños primero”, intentemos ver que tan acertado es esa afirmación.

In [7]:
# Utilizamos Seaborn countplot para realizar la gráfica
# Gráfica por género
sns.countplot(x='Survived',data=titanic_train,hue='Sex',palette='muted')
plt.title('Gráfica por género')
 Out[7]:
TitanicFig1

Observamos que efectivamente hay más mujeres que se salvaron en el titanic que hombres. Ahora intentemos ver la distribución por edades. En esta observamos que los niños si tuvieron prioridad.

In [8]:
g = sns.FacetGrid(titanic_train, col='Survived')
g.map(sns.distplot, 'Age', bins=20)
Out[8]:
TitanicFig2

Siguiendo con el análisis visual de los datos tenemos. Según recuerdo en la película (no es una fuente confiable) se embarcaban los mejor posicionados económicamente primero. Miremos la gráfica por clase.

In [9]:
# Gráfica por clase
sns.countplot(x='Survived',data=titanic_train,hue='Pclass',palette='muted')
plt.title('Gráfica por clase')
Out[9]:
TitanicFig3

Aunque no es válido decir que se salvaron más de una clase o de otra dado que los números están muy cercanos, es bueno anotar que habían muchas más personas en la tercera clase que en primera, teniendo eso en cuenta la distribución aumenta.

Ahora intentemos analizar como es la distribución entre número de familiares y chance de sobrevivir.

In [10]:
titanic_train['FamilyNum'] = titanic_train['SibSp'] + titanic_train['Parch']
In [11]:
sns.countplot(x='FamilyNum',data=titanic_train,hue='Survived',palette='muted')
Out[11]:
TitanicFig4

Feature Engineering

Ya hemos visto como se comportan algunos datos, ahora intentemos llenar los datos vacíos y ver que otros grupos de datos podemos crear.
Primero tenemos dos columnas que tienen datos faltantes Age y Cabin, intentemos completar los datos.

In [12]:
#Cabin
titanic_train['Cabin'].apply(lambda x: str(x)[0]).value_counts()
Out[12]:
n    687
C     59
B     47
D     33
E     32
A     15
F     13
G      4
T      1
Name: Cabin, dtype: int64

En este caso para Cabin hay demasiados valores faltantes para Cabin y no destaca ningún valor que podamos ussar para obtener los valores faltantes (n).
Empezamos a crear nuestro DataFrame para aplicar nuestro algoritmo, para eso empezamos analizando que columnas utilizaremos para la predicción. La columna Cabin tiene muchos valores faltantes, la columnas PassengerId es simplemente un número consecutivo, la columna Ticket no parece tener ninguna relación con el campo Survived, la columna Name es solamente el nombre del pasajero y obviamente la columna Survived es la que tenemos que encontrar.
Eliminamos todas estas columnas de nuestro dataset para predicciones

In [13]:
titanic_train.columns
Out[13]:
Index(['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp',
       'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked', 'FamilyNum'],
      dtype='object')
In [14]:
ds = titanic_train[['Pclass', 'Sex', 'Age', 'SibSp','Parch', 'Fare', 'Embarked', 'FamilyNum']]
In [15]:
ds.head()
Out[15]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 male 22.0 1 0 7.2500 S 1
1 1 female 38.0 1 0 71.2833 C 1
2 3 female 26.0 0 0 7.9250 S 0
3 1 female 35.0 1 0 53.1000 S 1
4 3 male 35.0 0 0 8.0500 S 0

Para Age podemos crear grupos:

1 – 0 a 5
2 – 6 a 10
3 – 11 a 15
4 – 16 a 20
5 – 21 a 30
6 – 31 a 45
7 – 46 a 60
8 – >61
9 – Otros

Y de paso podemos hacer lo mismo para Fare:

1 – 0 a 100
2 – >100 a 200
3 – >200 a 300
4 – >300 a 400
5 – >400 a 500
6 – >500

Muchas operaciones!!!!

Para este punto hemos añadido la columna de FamilyNum, eliminado 5 columnas y estamos a punto de crear dos columnas más. Recordemos que además de trabajar con el dataset de titanic_train también tenemos que hacer las mismas operaciones con el dataset titanic_test así que debemos ir pensando en la manera de replicar las operaciones para el dataset faltante.

In [16]:
#Creamos el proceso

#Eliminamos las columnas
def eliminarColumnas(datos):
    return datos[['Pclass', 'Sex', 'Age', 'SibSp','Parch', 'Fare', 'Embarked']]

#Agregamos la columna FamilyNum
def agregarFamilyNum(datos):
    datos['FamilyNum'] = datos['SibSp'] + datos['Parch']
    return datos

#Creamos los grupos para Age
def gruposAge(valor):
    if valor > 0 and valor <= 5:
        return 1
    elif valor > 5 and valor <= 10:
        return 2
    elif valor > 10 and valor <= 15:
        return 3
    elif valor > 15 and valor <= 20:
        return 4
    elif valor > 20 and valor <= 30:
        return 5
    elif valor > 30 and valor <= 45:
        return 6
    elif valor > 45 and valor <= 60:
        return 7
    elif valor > 60:
        return 8
    else:
        return 9
    
#Creamos los grupos para Fare
def gruposFare(valor):
    if valor > 0 and valor <= 100:
        return 1
    elif valor > 100 and valor <= 200:
        return 2
    elif valor > 200 and valor <= 300:
        return 3
    elif valor > 300 and valor <= 400:
        return 4
    elif valor > 400 and valor <= 500:
        return 5
    elif valor > 500:
        return 6
    else:
        return 7
In [17]:
#Agrupamos las funciones
def aConvertir(datos):
    ds = eliminarColumnas(datos)
    ds = agregarFamilyNum(ds)
    ds['Age'] = ds['Age'].apply(gruposAge)
    ds['Fare'] = ds['Fare'].apply(gruposFare)
    ds.fillna('',inplace =True)
    return ds
In [18]:
ds_train = aConvertir(titanic_train)
ds_train.head()
Out[18]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 male 5 1 0 1 S 1
1 1 female 6 1 0 1 C 1
2 3 female 5 0 0 1 S 0
3 1 female 6 1 0 1 S 1
4 3 male 6 0 0 1 S 0
In [19]:
#Convertimos test también
ds_test = aConvertir(titanic_test)
ds_test.head()
Out[19]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 male 6 0 0 1 Q 0
1 3 female 7 1 0 1 S 1
2 2 male 8 0 0 1 Q 0
3 3 male 5 0 0 1 S 0
4 3 female 5 1 1 1 S 2

Ahora tenemos solamente dos campos de texto Sex y Embarked, intentemos convertir estos en valores más entendibles para los algoritmos

In [20]:
from sklearn import preprocessing
In [21]:
def preprocessCampos(train,test):
    campos = ['Sex', 'Embarked']
    ds_combinado = pd.concat([train[campos], test[campos]])
    
    for campo in campos:
        le = preprocessing.LabelEncoder()
        le = le.fit(ds_combinado[campo].fillna(''))
        train[campo] = le.transform(train[campo])
        test[campo] = le.transform(test[campo])
    return train, test
In [22]:
ds_train, ds_test = preprocessCampos(ds_train, ds_test)
ds_train.head()
Out[22]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 1 5 1 0 1 3 1
1 1 0 6 1 0 1 1 1
2 3 0 5 0 0 1 3 0
3 1 0 6 1 0 1 3 1
4 3 1 6 0 0 1 3 0
In [23]:
ds_test.head()
Out[23]:
Pclass Sex Age SibSp Parch Fare Embarked FamilyNum
0 3 1 6 0 0 1 2 0
1 3 0 7 1 0 1 3 1
2 2 1 8 0 0 1 2 0
3 3 1 5 0 0 1 3 0
4 3 0 5 1 1 1 3 2

Aplicar algoritmos

En esta parte ya tenemos nuestros datos transformados de una forma más fácil de procesar, ahora vamos a aplicar varios algoritmos y validaremos su eficacia.

In [24]:
#Creamos nuestro dataset de Survived y de entrenamiento
X = ds_train
y = titanic_train['Survived']
In [25]:
#Creamos los splits de entrenamiento y test que vamos a utilizar para nuestros algoritmos
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=66)

Linear Regression

In [26]:
from sklearn.linear_model import LinearRegression
lrmodel = LinearRegression()
lrmodel.fit(X_train,y_train)
lr_predictions = lrmodel.predict(X_test)

Logistic Regression

In [27]:
from sklearn.linear_model import LogisticRegression
logmodel = LogisticRegression()
logmodel.fit(X_train,y_train)
log_predictions = logmodel.predict(X_test)

K-Means Clustering

In [28]:
from sklearn.cluster import KMeans
kmeansmodel = KMeans(n_clusters=2)
kmeansmodel.fit(X_train)
km_predictions = kmeansmodel.predict(X_test)

K-Nearest neighbor

In [29]:
from sklearn.neighbors import KNeighborsClassifier
knnmodel = KNeighborsClassifier(n_neighbors=20)
knnmodel.fit(X_train,y_train)
knn_predictions = knnmodel.predict(X_test)

Decision Tree

In [30]:
from sklearn.tree import DecisionTreeClassifier
dtreemodel = DecisionTreeClassifier()
dtreemodel.fit(X_train,y_train)
dtree_predictions = dtreemodel.predict(X_test)

Random Forest

In [31]:
from sklearn.ensemble import RandomForestClassifier
rfcmodel = RandomForestClassifier(n_estimators=200)
rfcmodel.fit(X_train,y_train)
rfc_predictions = rfcmodel.predict(X_test)

Support Vector Machines

In [32]:
from sklearn.svm import SVC
svcmodel = SVC()
svcmodel.fit(X_train,y_train)
svc_predictions = svcmodel.predict(X_test)

Gaussian Naive Bayes

In [33]:
from sklearn.naive_bayes import GaussianNB
gnbmodel = GaussianNB()
gnbmodel.fit(X_train,y_train)
gnb_predictions = gnbmodel.predict(X_test)

Validating Scores

Después de ejecutar los algoritmos podemos comparar la precisión y escoger el mejor:

In [34]:
print('Linear Regression: ',lrmodel.score(X_test,y_test))
print('Logistic Regression: ', logmodel.score(X_test,y_test))
print('K-Means Clustering: ', kmeansmodel.score(X_test,y_test))
print('K-Nearest neighbor: ', knnmodel.score(X_test,y_test))
print('Decision Tree: ', dtreemodel.score(X_test,y_test))
print('Random Forest: ', rfcmodel.score(X_test,y_test))
print('Support Vector Machines: ', svcmodel.score(X_test,y_test))
print('Gaussian Naive Bayes: ', gnbmodel.score(X_test,y_test))
Linear Regression:  0.371556568359
Logistic Regression:  0.80223880597
K-Means Clustering:  -2114.45854816
K-Nearest neighbor:  0.791044776119
Decision Tree:  0.820895522388
Random Forest:  0.84328358209
Support Vector Machines:  0.850746268657
Gaussian Naive Bayes:  0.776119402985

Predecir el verdardero Test dataset

El mejor Algoritmo fue el de Support Vector Machines, procedamos a generar el archivo de predicciones.

In [36]:
passengers = titanic_test['PassengerId']
predictions = svcmodel.predict(ds_test)

output = pd.DataFrame({ 'PassengerId' : passengers, 'Survived': predictions })
output.to_csv('titanic-predictions.csv', index = False)
output.head()
Out[36]:
PassengerId Survived
0 892 0
1 893 1
2 894 0
3 895 0
4 896 1

Cuando subimos nuestro dataset a Kaggle, este nos da un maravilloso mensaje informándonos que somos los mejores.

KaggleTitanic

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s