Qué es el desafío del Titanic
Puede que ya hayas escuchado hablar del conocido TITANIC CHALLENGE y de la cantidad de posibilidades de solucionarlo que hay. Se trata de un problema de aprendizaje automático que busca analizar qué tipo de personas tenían más probabilidades de sobrevivir al naufragio. ¿Interesante verdad? ¿Y si te digo que este artículo tiene sorpresa? Lee hasta el final y entérate de lo que Kopuru ha preparado para ti.
Contexto histórico
El Titanic fue un transatlántico que naufragó el 15 de abril de 1912 cuando se dirigía a la ciudad de Nueva York. A pesar de ser publicitado como un barco insumergible, se hundió en el Atlántico cuando chocó contra un iceberg.
Existe mucha controversia sobre las causas de este accidente. Durante mucho tiempo se ha creído que ocurrió porque navegaba demasiado rápido por una zona de poca visibilidad y la tripulación no alcanzó a ver el iceberg a tiempo. Sin embargo, un estudio reciente considera que la tripulación si vio el iceberg a tiempo y fue un error del timonel lo que causó el naufragio.
Pasos clave para la resolución de un problema
A primera vista podríamos pensar que la probabilidad de sobrevivir era similar para todos los tripulantes, pero esa suposición estaría muy lejos de la realidad. Si has visto la película bien lo sabrás, existían algunos condicionantes. Al no haber suficientes botes salvavidas para todos, los niños, las mujeres y los pasajeros de primera clase, entre otros, tuvieron prioridad para montarse. Conclusión: la supervivencia de los pasajeros estaba condicionada a una serie de variables, que los convertían en más o menos susceptibles de llegar a tierra con vida. Pues bien, ¡vamos a analizarlo!
Estamos ante un problema de aprendizaje supervisado binario. Binario porque sólo existen dos soluciones posibles: sobrevivir o morir en el Atlántico. Y aprendizaje supervisado, porque los datos de entrenamiento tienen datos etiquetados.
Para simplificar el proceso, proponemos este esquema de pasos a seguir. Esta secuencia es muy común en los problemas de aprendizaje:
- Obtener los datos.
- Pre proceso de datos:
- Transformación de datos. (Limpiar y preparar los datos, imputación de valores…)
- EDA.
- Ingeniería de características. (Esta es una opción avanzada)
- Dividir los datos en test/train.
- Elegir un modelo de aprendizaje.
- Evaluar el modelo.
- Ajuste de hiperparámetros.
- Predicción.
Resolución sencilla paso a paso con ejemplos de código en python
Conocemos el contexto, el problema a resolver y tenemos el paso a paso así que, ahora llega lo bueno: ¿Cómo resolvemos este reto tan famoso? Sigue leyendo para ver el paso a paso en detalle. Y recuerda, puedes ir directamente al apartado que te está dando más problemas.
Paso 1: Obtener los datos
El primer paso es sencillo ya que nos dan todos los datos en el enunciado del challenge. Lo primero que tenemos que hacer es importar los datos a nuestra plataforma de trabajo. Es importante que inviertas tiempo en familiarizarte con el entorno, te facilitara el proceso.
train = pd.read_csv("/train_titanic.csv") #leemos el archivo
train.head() #esta función imprime las 5 primeras instancias del dataset. Es muy útil para visualizarlo.
test = pd.read_csv("/train_titanic.csv")
test.head()
Paso 2: Preproceso de datos
#Una función que puede darnos mucha información es describe
train.describe()
Tenemos 11 variables, pero no todas ellas tienen porque utilizarse. En ocasiones, hay variables que pueden no dar información relevante y se eliminan. Además, tener menos variables ameniza los cálculos. Siguiendo la hipótesis que hemos mencionado antes, las variables más importantes serían, la edad, el género y el estatus social. Por lo que, las variables “age”, “sex” y “Pclas” nos darían información suficiente para entrenar el clasificador.
Comprobación de valores nulos
#Comprobamos si hay valores nulos, tenemos que fijarnos sobre todo en las que nos interesan.
train.isnull().sum()
#Podemos ver que de las tres variables que habíamos elegido, "Age" no esta completa y le faltan muchos datos.
Para poder utilizar las variables tenemos que pre-procesarlas. Podemos observar que la variable “age” no tiene apenas datos. Para resolver este problema tenemos dos opciones: eliminar la variable o rellenarla. La primera opción, es la más rápida pero puede hacernos perder información muy importante. La segunda, es muy costosa y bastante más avanzada.
Normalmente podemos tomar la decisión de eliminar la variable si hay muy poca información sobre ella. En este caso, esa es la decisión que tomamos. Cabe destacar que, al ser una variable muy importante en la hipótesis que hemos planteado al principio, puede no ser la decisión más óptima. Pero, el objetivo de este post es resolver el problema de la manera más sencilla posible.
Selección de variables
Vamos a extraer las dos variables con las que finalmente hemos decidido entrenar el clasificador a un dataframe “train_x” y su resultado a un dataframe “train_y”.
#Para mantener simple la solución, solo vamos a escoger Pclass y sex
train_x = train[["Pclass", "Sex"]]
train_x.head()
#guardamos el resultado/clase aparte
train_y = train[["Survived"]]
train_y.head()
Formateo de variables para que sean computables
El siguiente paso es transformar train_x para que tenga datos computables. Podemos utilizar el diccionario para realizar correctamente este paso. Por ejemplo, en vez de usar “female” y “male” tendríamos que utilizar un sistema binario de 1 y 0.
#Ponemos los datos en un formato que sea computable.
#Lo hemos hecho ahora para ahorrar coste. Formatear datos que no vamos a utilizar no tiene sentido
train_x["Sex"].replace("male", 0, inplace = True)
train_x["Sex"].replace("female", 1, inplace = True)
train_x.head()
En el siguiente paso decidiremos como tenemos que dividir los datos en test y train. Esto ayuda a evitar el “overfitting”. Si ajustamos el clasificador demasiado a los datos con los que entrenamos, este no será capaz de generalizar.
Cabe mencionar que este pre-procesado de datos es bastante simple. Si nos fijamos en el esquema que te planteamos al inicio del post, podríamos utilizar otras técnicas para obtener un resultado más exacto.
Paso 3: Elegir el modelo de aprendizaje
Para elegir el modelo vamos a utilizar la técnica de cross-validation. Es una técnica de validación, y analiza la eficacia del modelo de predicción. Con ella podemos saber si el modelo está bien ajustado. La vamos a utilizar para comparar diferentes modelos y seleccionar el más adecuado.
Los modelos que hemos decidido utilizar y evaluar son: Random Forest y Logistic Regresion.
#Importamos el algoritmo de aprendizaje automático
from sklearn.ensemble import RandomForestClassifier
#Importamos la función que nos ayuda a dividir el dataset para evitar overfitting
from sklearn.model_selection import train_test_split
#creamos una instancia del clasificador
randomforest = RandomForestClassifier()
Nuestro siguiente paso es dividir en dos la parte de train. Una primera parte con el 70% de los datos irá a entrenar el clasificador y el otro 30% restante lo reservaremos para analizar la exactitud.
#Para que nuestro dataset no se ajuste demasiado a los datos que tenemos
#y sea incapaz de generalizar, lo dividimos. La división será %70 train %30 test
#Vamos a usar la técnica de cross-validation para medir la exactitud (accuracy)
train_split_x, crossvalidation_x, train_split_y, crossvalidation_y = train_test_split(train_x, train_y, test_size = 0.30)
print(train_split_x.head())
print(train_split_y.head())
Entrenamos el clasificador con la nueva división de los datos.
#entrenamos al clasificador, para eso se utiliza la funcion fit
randomforest.fit(train_split_x, train_split_y)
Paso 4: Evaluar el clasificador
Ahora, solo nos queda probar diferentes modelos y analizar su resultado. Basta con llamar a la función del clasificador dentro de tu entorno de desarrollo y una vez que esté entrenado, llamar a la función de cross-validation para analizarlo.
#evaluamos el clasificador
Accuracy_RandomForest = randomforest.score(crossvalidation_x, crossvalidation_y)
print("Accuracy = {}%".format(Accuracy_RandomForest * 100))
Paso 5: Ajuste de hiperparámetros
En este paso, después de ver los resultados de exactitud/accuracy, podemos decidir añadir, quitar, transformar parámetros o directamente cambiar de clasificador. Es decir, podríamos volver al paso 2 y rehacer nuestra solución. Como queremos dejar la solución simple, en este paso no vamos a tocar nada.
Paso 6: Realizar la predicción
Una vez elegido el modelo, tenemos que utilizarlo para predecir el resultado de los casos de test que nos dan en el enunciado y subirlo a Kopuru para ver cómo de eficiente es nuestra solución.
Para realizar la predicción tenemos que usar los casos de test que nos da el enunciado. Pero ¡cuidado! hay que formatearlos como hemos hecho en train para poder utilizarlos. Tenemos que elegir las mismas variables y dejarlas en el mismo estado computable.
#elegimos las mismas variables
test_x = test[["Pclass", "Sex"]]
train_x.head()
#formateamos de la misma manera
test_x["Sex"].replace("male", 0, inplace = True)
test_x["Sex"].replace("female", 1, inplace = True)
test_x.head()
#Realizamos la predicción con los casos de test
prediccion= randomforest.predict(test_x)
Siguiendo estos pasos el clasificador Random Forest debería dar una exactitud de en torno al 76% y Logistic Regresion debería dar de en torno al 82%. ¿Te ha dado esos resultados? ¿Dónde has tenido más problemas? Nos encantará leerte en los comentarios.
Antes de irte
Y aquí es donde está la sorpresa. ¿Serías capaz de mejorar el resultado? Existen muchas formas más eficientes de resolver este challenge y queremos que nos lo demuestres. ¡Ponte a prueba y súbelo a Kopuru!
Además, si consigues resolverlo y ser el mejor de todos los participantes te llevaras una tarjeta de REGALO en AMAZON por 100€.
¡No dejes pasar la oportunidad y participa antes de que finalice el plazo!