A tu propio ritmo

Explora nuestra extensa colección de cursos diseñados para ayudarte a dominar varios temas y habilidades. Ya seas un principiante o un aprendiz avanzado, aquí hay algo para todos.

Bootcamp

Aprende en vivo

Únete a nosotros en nuestros talleres gratuitos, webinars y otros eventos para aprender más sobre nuestros programas y comenzar tu camino para convertirte en desarrollador.

Próximos eventos en vivo

Catálogo de contenidos

Para los geeks autodidactas, este es nuestro extenso catálogo de contenido con todos los materiales y tutoriales que hemos desarrollado hasta el día de hoy.

Tiene sentido comenzar a aprender leyendo y viendo videos sobre los fundamentos y cómo funcionan las cosas.

Buscar en lecciones


IngresarEmpezar
← Regresar a lecciones
Abrir en Colab

Análisis y Limpieza de Datos Exploratorios con Titanic

Análisis exploratorio de datos

El análisis exploratorio de datos, también conocido como EDA (Exploratory Data Analysis) es el primer paso para resolver cualquier problema de Machine Learning. Consiste en un proceso que busca analizar e investigar los conjuntos de datos de los que disponen y resumir sus principales características, empleando a menudo técnicas de visualización de datos. Este análisis se lleva a cabo a través de una serie de pasos que se detallan a continuación.

En esta sección ahondaremos en el concepto trabajando con el conjunto de datos del Titanic.

DÍA 1

Paso 1: Planteamiento del problema y recopilación de datos

Antes de comenzar a analizar el conjunto de datos, debemos entender, por un lado, el problema o desafío que estamos intentando resolver con esta información y lo idóneo o útil que puede resultarnos.

En este caso, queremos analizar qué personas sobrevivieron o no en el naufragio del Titanic y, en sucesivas fases, poder entrenar un modelo de Machine Learning para responder a la pregunta: "¿Qué tipo de personas tenían más probabilidades de sobrevivir?". Por lo tanto, encontramos que el dataset del que disponemos puede ayudarnos a resolver la cuestión planteada y aplicamos un proceso de EDA para conocerlo más en detalle.

Importaremos el conjunto de datos para comenzar a trabajar con él:

In [1]:
import pandas as pd

train_data = pd.read_csv("https://raw.githubusercontent.com/4GeeksAcademy/machine-learning-content/master/assets/titanic_train.csv")
test_data = pd.read_csv("https://raw.githubusercontent.com/4GeeksAcademy/machine-learning-content/master/assets/titanic_test.csv")
test_survived_data = pd.read_csv("https://raw.githubusercontent.com/4GeeksAcademy/machine-learning-content/master/assets/gender_submission.csv")
test_data["Survived"] = test_survived_data["Survived"]

total_data = pd.concat([train_data, test_data]).reset_index(inplace = False)
total_data.drop(columns = ["index"], inplace = True)
total_data.head()
Out[1]:
PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS

Paso 2: Exploración y limpieza de datos

Una vez que hemos cargado el conjunto de datos, debemos analizarlo en su totalidad, sin distinción de train y test, para obtener conclusiones conjuntas. Una vez que tenemos la información cargada en una estructura de datos manejable como es un DataFrame de Pandas, podemos arrancar con el proceso.

Conocer las dimensiones y tipologías de datos del objeto con el que estamos trabajando es vital. Para ello necesitamos el atributo shape para obtener las dimensiones del objeto y la función info() para conocer la tipología y la cantidad de valores no nulos:

In [2]:
# Obtener las dimensiones
total_data.shape
Out[2]:
(1309, 12)
In [3]:
# Obtener información sobre tipos de datos y valores no nulos
total_data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1309 entries, 0 to 1308
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  1309 non-null   int64  
 1   Survived     1309 non-null   int64  
 2   Pclass       1309 non-null   int64  
 3   Name         1309 non-null   object 
 4   Sex          1309 non-null   object 
 5   Age          1046 non-null   float64
 6   SibSp        1309 non-null   int64  
 7   Parch        1309 non-null   int64  
 8   Ticket       1309 non-null   object 
 9   Fare         1308 non-null   float64
 10  Cabin        295 non-null    object 
 11  Embarked     1307 non-null   object 
dtypes: float64(2), int64(5), object(5)
memory usage: 122.8+ KB

Una vez hemos obtenido esta información, es importante que seamos capaces de extraer conclusiones, como las siguientes:

  • Existen un total de 1309 filas (en este caso, personas) y 12 columnas, de entre las que encontramos el objetivo o clase a predecir, Survived.
  • La variable Cabin solo tiene 295 instancias con valores, por lo que contendría más de 1000 valores nulos. La variable Age también cuenta con valores nulos, pero en un número mucho más reducido que el anterior. El resto de variables cuentan siempre con valor.
  • Los datos cuentan con 7 características numéricas y 5 características categóricas.

Eliminar duplicados

Un punto muy importante a tener en cuenta en este paso es eliminar aquellas instancias que pudieran estar duplicadas en el conjunto de datos. Esto es crucial, ya que, de dejarlo, el mismo punto tendría varias representaciones, lo cual es matemáticamente incoherente e incorrecto. Para ello, hemos de ser inteligentes buscando duplicados y conocer previamente si los hay y dónde, antes de eliminarlos. Además, tenemos que tener en cuenta que una instancia puede estar repetida independientemente del identificador que pueda tener, así que en este caso nos interesa eliminar del análisis la variable PassengerId, ya que podría estar mal generada.

In [4]:
total_data.drop("PassengerId", axis = 1).duplicated().sum()
Out[4]:
0

En este caso, no encontramos ningún valor duplicado. En el caso de que lo hubiésemos encontrado, el siguiente paso sería aplicar la función de drop_duplicates().

In [5]:
total_data = total_data.drop_duplicates(subset = total_data.columns.difference(['PassengerId']))
print(total_data.shape)
total_data.head()
(1309, 12)
Out[5]:
PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS

Excluiríamos de nuevo la columna identificativa, aunque podríamos repetir el análisis incluyéndola para enriquecer el análisis:

In [6]:
if total_data.duplicated().sum():
    total_data = total_data.drop_duplicates()
print(total_data.shape)
total_data.head()
(1309, 12)
Out[6]:
PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C
2313Heikkinen, Miss. Lainafemale26.000STON/O2. 31012827.9250NaNS
3411Futrelle, Mrs. Jacques Heath (Lily May Peel)female35.01011380353.1000C123S
4503Allen, Mr. William Henrymale35.0003734508.0500NaNS

Eliminar información irrelevante

Cuando queremos preparar los datos para entrenar un modelo predictivo, debemos responder a la siguiente pregunta: ¿son todas las características imprescindibles para realizar una predicción? Normalmente, esa pregunta es un rotundo no. Tenemos que tratar de ser lo más objetivos posible y llevar a cabo este proceso previo antes de la fase de selección de características. Por lo tanto, aquí lo que trataremos de hacer es una eliminación controlada de aquellas variables que podemos estar seguros de que el algoritmo no va a utilizar en el proceso predictivo, estas son PassengerId, Name, Ticket y Cabin.

In [7]:
total_data.drop(["PassengerId", "Name", "Ticket", "Cabin"], axis = 1, inplace = True)
total_data.head()
Out[7]:
SurvivedPclassSexAgeSibSpParchFareEmbarked
003male22.0107.2500S
111female38.01071.2833C
213female26.0007.9250S
311female35.01053.1000S
403male35.0008.0500S

Paso 3: Análisis de variables univariante

Una variable univariante es un término estadístico que se emplea para referenciar un conjunto de observaciones de un atributo. Esto es, el análisis columna a columna del DataFrame. Para ello, debemos distinguir si una variable es categórica o numérica, ya que el cuerpo del análisis y las conclusiones que se pueden obtener serán distintas.

Análisis sobre variables categóricas

Una variable categórica es un tipo de variable que puede tomar uno de un número limitado de categorías o grupos. Estos grupos son a menudo nominales (por ejemplo, el color de un coche: rojo, azul, negro, etc, pero ninguno de estos colores es inherentemente "mayor" o "mejor" que los demás) pero pueden también representarse mediante números finitos.

Para representar este tipo de variables utilizaremos histogramas. Antes de comenzar a graficar, debemos identificar cuáles son categóricas, y se puede comprobar fácilmente analizando el rango de valores. En este caso, las variables categóricas son Survived, Sex, Pclass, Embarked, SibSp y Parch:

In [8]:
import matplotlib.pyplot as plt 
import seaborn as sns

fig, axis = plt.subplots(2, 3, figsize = (10, 7))

# Crear un histograma múltiple
sns.histplot(ax = axis[0, 0], data = total_data, x = "Survived").set_xlim(-0.1, 1.1)
sns.histplot(ax = axis[0, 1], data = total_data, x = "Sex").set(ylabel = None)
sns.histplot(ax = axis[0, 2], data = total_data, x = "Pclass").set(ylabel = None)
sns.histplot(ax = axis[1, 0], data = total_data, x = "Embarked")
sns.histplot(ax = axis[1, 1], data = total_data, x = "SibSp").set(ylabel = None)
sns.histplot(ax = axis[1, 2], data = total_data, x = "Parch").set(ylabel = None)

# Ajustar el layout
plt.tight_layout()

# Mostrar el plot
plt.show()
No description has been provided for this image

Un histograma es una representación gráfica de la distribución de un conjunto de datos. Se utiliza además para comprender la frecuencia de los datos. Al observar un histograma, podemos entender si los datos están sesgados hacia un extremo, si son simétricos, si tienen muchos valores atípicos, etcétera. Con la representación de cada variable podemos determinar que:

  • Survived: El número de personas que no sobrevivieron superan en más de 300 a los que sí lo hicieron.
  • Sex: En el Titanic había casi el doble de hombres que de mujeres.
  • Pclass: La suma de los pasajeros que viajaban en primera y segunda clase era casi idéntica a las que viajaban en tercera.
  • Embarked: La mayoría de los pasajeros del Titanic embarcaron en la estación de Southampton (S).
  • SibSp: Más de 800 pasajeros viajaron solos. Los restantes, con su pareja o alguien más de su familia.
  • Parch: Casi todos los pasajeros viajaron sin padres o hijos. Una pequeña parte sí lo hizo.

Análisis sobre variables numéricas

Una variable numérica es un tipo de variable que puede tomar valores numéricos (enteros, fracciones, decimales, negativos, etc.) en un rango infinito. Una variable categórica numérica puede ser también una variable numérica (por ejemplo, para los sucesivos análisis, podemos tomar la clase Survived como numérica también para estudiar relaciones). Normalmente se representan utilizando un histograma y diagramas de caja, expuestos juntos. Antes de comenzar a graficar, debemos también identificar cuáles son las numéricas, que son Fare, Age y PassengerId. Sin embargo, esta última carece de sentido, así que graficaremos las dos primeras:

In [9]:
fig, axis = plt.subplots(2, 2, figsize = (10, 7), gridspec_kw={'height_ratios': [6, 1]})

# Crear una figura múltiple con histogramas y diagramas de caja
sns.histplot(ax = axis[0, 0], data = total_data, x = "Fare").set(xlabel = None)
sns.boxplot(ax = axis[1, 0], data = total_data, x = "Fare")
sns.histplot(ax = axis[0, 1], data = total_data, x = "Age").set(xlabel = None, ylabel = None)
sns.boxplot(ax = axis[1, 1], data = total_data, x = "Age")

# Ajustar el layout
plt.tight_layout()

# Mostrar el plot
plt.show()
No description has been provided for this image

La combinación de los dos gráficos anteriores nos permite conocer la distribución y sus características estadísticas. De la visualización resultante podemos ver que ambas variables tienen valores atípicos que están lejos de la distribución estándar y que sus distribuciones son ligeramente asimétricas pero cercanas a una distribución normal; la primera totalmente sesgada hacia la izquierda, donde la media es inferior a la moda y la otra con menor tendencia.

Paso 4: Análisis de variables multivariante

Tras analizar las características una a una, es momento de analizarlas en relación con la predictora y con ellas mismas, para sacar conclusiones más claras acerca de sus relaciones y poder tomar decisiones sobre su procesamiento.

Así, si quisiéramos eliminar una variable debido a una alta cantidad de valores nulos o ciertos outliers, es necesario antes aplicar este proceso para asegurar que la eliminación de ciertos valores no son críticos para la supervivencia de un pasajero. Por ejemplo, la variable Cabin tiene muchos valores nulos, y tendríamos que asegurar que no hay relación entre ella y la supervivencia antes de eliminarla, ya que quizá pudiera ser muy significativa e importante para el modelo y su presencia podría decantar la predicción.

Análisis numérico-numérico

Cuando las dos variables que se comparan tienen datos numéricos, se dice que el análisis es numérico-numérico. Para comparar dos columnas numéricas se utilizan diagramas de dispersión y análisis de correlaciones.

Survived - (Fare, Age)

Utilizaremos la variable Survived para comenzar con el análisis bivariante porque al tratarse de una variable categórica, pero codificada en números, puede considerarse como numérica también. Primero analizamos la clase frente a las características numéricas:

In [10]:
fig, axis = plt.subplots(2, 2, figsize = (10, 7))

# Crear un diagrama de dispersión múltiple
sns.regplot(ax = axis[0, 0], data = total_data, x = "Fare", y = "Survived")
sns.heatmap(total_data[["Survived", "Fare"]].corr(), annot = True, fmt = ".2f", ax = axis[1, 0], cbar = False)
sns.regplot(ax = axis[0, 1], data = total_data, x = "Age", y = "Survived").set(ylabel=None)
sns.heatmap(total_data[["Survived", "Age"]].corr(), annot = True, fmt = ".2f", ax = axis[1, 1])

# Ajustar el layout
plt.tight_layout()

# Mostrar el plot
plt.show()
No description has been provided for this image

Existe una relación directa (aunque no muy fuerte) entre el precio del billete (Fare) y la supervivencia del pasajero. Así, algunos pasajeros con un importe bajo de billete tuvieron menos probabilidad de supervivencia frente a los que adquirieron un billete con un precio mayor. También existe una relación lineal negativa, más débil que la anterior, entre la edad (Age) y la variable objetivo. Esto tiene sentido considerando que los niños eran uno de los grupos que tenían preferencia en usar los botes para sobrevivir.

En resumen, a pesar de existir cierta relación con estas características frente a la predictora, la significancia no es muy elevada, no siendo factores decisivos sobre si un pasajero sobrevivía o no.

Fare - Age

A continuación también podemos relacionar ambas variables para determinar su grado de afinidad o correlación:

In [11]:
fig, axis = plt.subplots(2, 1, figsize = (5, 7))

# Crear un diagrama de dispersión múltiple
sns.regplot(ax = axis[0], data = total_data, x = "Age", y = "Fare")
sns.heatmap(total_data[["Fare", "Age"]].corr(), annot = True, fmt = ".2f", ax = axis[1])

# Ajustar el layout
plt.tight_layout()

# Mostrar el plot
plt.show()
No description has been provided for this image

Se puede determinar que no existe una relación muy fuerte entre ambas variables y que la edad no impacta sobre que el precio del billete sea mayor o no.

Análisis categórico-categórico

Cuando las dos variables que se comparan tienen datos categóricos, se dice que el análisis es categórico-categórico. Para comparar dos columnas categóricas se utilizan histogramas y combinaciones.

Survived - (Sex, Pclass, Embarked, SibSp, Parch)

Primero analizamos la clase frente a las características categóricas, una a una. Aquí no habrá combinaciones de varias predictoras y la clase:

In [12]:
fig, axis = plt.subplots(2, 3, figsize = (15, 7))

sns.countplot(ax = axis[0, 0], data = total_data, x = "Sex", hue = "Survived")
sns.countplot(ax = axis[0, 1], data = total_data, x = "Pclass", hue = "Survived").set(ylabel = None)
sns.countplot(ax = axis[0, 2], data = total_data, x = "Embarked", hue = "Survived").set(ylabel = None)
sns.countplot(ax = axis[1, 0], data = total_data, x = "SibSp", hue = "Survived")
sns.countplot(ax = axis[1, 1], data = total_data, x = "Parch", hue = "Survived").set(ylabel = None)

plt.tight_layout()
fig.delaxes(axis[1, 2])

plt.show()
No description has been provided for this image

Del gráfico anterior podemos obtener las siguientes conclusiones:

  • Con mayor proporción sobrevivieron las mujeres frente a los hombres. Esto es así porque en los planes de evacuación tenían prioridad las mujeres frente a los hombres.
  • Las personas que viajaron solas tuvieron más problemas para sobrevivir frente a las que viajaron acompañadas.
  • Aquellos que viajaron en una mejor clase en el Titanic tuvieron una mayor probabilidad de supervivencia.
Combinaciones de la clase con varias predictoras

El análisis multivariante también permite combinar la clase con varias predictoras al mismo tiempo para enriquecer el análisis. Este tipo de operaciones deben ser subjetivas y deben combinar características relacionadas entre sí. Por ejemplo, no tendría sentido hacer un análisis entre la clase, el sexo del pasajero y la estación en la que accedió al Titanic, ya que no guarda relación el sexo del pasajero con la estación. Sin embargo, la clase y el sexo del pasajero frente a su supervivencia podría ser un análisis digno de estudio, entre otras casuísticas que se presentan a continuación:

In [13]:
fig, axis = plt.subplots(figsize = (10, 5), ncols = 2)

sns.barplot(ax = axis[0], data = total_data, x = "Sex", y = "Survived", hue = "Pclass")
sns.barplot(ax = axis[1], data = total_data, x = "Embarked", y = "Survived", hue = "Pclass").set(ylabel = None)

plt.tight_layout()

plt.show()
No description has been provided for this image

De esos análisis se observa claramente que, independientemente del puerto de embarque, las mujeres tuvieron más posibilidades de supervivencia independientemente de la clase en la que viajaron, lo que refuerza el conocimiento obtenido anteriormente. Además, de media, las personas que viajaron en clases más altas sobrevivieron más que aquellos que no lo hicieron.

Análisis de correlaciones

El objetivo del análisis de correlaciónes con datos categóricos-categóricos es descubrir patrones y dependencias entre variables, lo que ayuda a entender cómo interactúan dentro de un conjunto de datos. Este análisis es fundamental en diversos campos como ciencias sociales, investigación de mercado y epidemiología, donde los datos categóricos a menudo representan atributos clave de interés.

Este análisis tiene como objetivo determinar si y cómo las categorías de una variable están relacionadas con las categorías de otra.

In [14]:
total_data["Sex_n"] = pd.factorize(total_data["Sex"])[0]
total_data["Embarked_n"] = pd.factorize(total_data["Embarked"])[0]

fig, axis = plt.subplots(figsize = (10, 6))

sns.heatmap(total_data[["Sex_n", "Pclass", "Embarked_n", "SibSp", "Parch", "Survived"]].corr(), annot = True, fmt = ".2f")

plt.tight_layout()

plt.show()
No description has been provided for this image

El análisis de correlaciones refleja una fuerte relación directa entre el sexo (Sex) del pasajero y su supervivencia, como hemos visto en apartados anteriores. Además, se aprecia una relación entre el número de acompañantes de los pasajeros (variables SibSp y Parch). El resto de las correlaciones son débiles y no son tan significativas como para contemplarlas en el análisis.

Finalmente, para cerrar el estudio multivariante queda analizar la relación entre las variables categóricas y numéricas.

Análisis numérico-categórico (completo)

Este es el análisis a mayor detalle que podemos llevar a cabo. Para ello, simplemente hemos de calcular las correlaciones entre las variables, ya que es el mayor indicativo sobre las relaciones. Así, una vez comprobemos que existe alguna relación, podremos profundizar en el estudio. Otro elemento que nos puede ser de mucha ayuda es obtener las relaciones dos a dos entre todos los datos del dataset. Esto es, en parte, redundante porque hay muchas cosas que ya hemos calculado antes y por eso es opcional.

In [15]:
fig, axis = plt.subplots(figsize = (10, 7))

sns.heatmap(total_data[["Age", "Fare", "Sex_n", "Pclass", "Embarked_n", "SibSp", "Parch", "Survived"]].corr(), annot = True, fmt = ".2f")

plt.tight_layout()

plt.show()
No description has been provided for this image

Existe una relación entre la tipología de clase (Pclass) y la edad del pasajero (Age) fuertemente negativa (los que viajaban en primera clase eran personas con alta edad) y entre la clase y la tarifa pagada (Fare), algo que tiene mucho sentido. El resto de correlaciones se mantienen con respecto a lo visto anteriormente.

Una vez analizada la correlación, analicemos los dos casos vistos para corroborar la teoría:

In [16]:
fig, axis = plt.subplots(figsize = (10, 5), ncols = 2)

sns.regplot(ax = axis[0], data = total_data, x = "Age", y = "Pclass")
sns.regplot(ax = axis[1], data = total_data, x = "Fare", y = "Pclass").set(ylabel = None, ylim = (0.9, 3.1))

plt.tight_layout()

plt.show()
No description has been provided for this image

En el primer gráfico vemos que cuando la edad avanza, la presencia de billetes de primera clase se hace más notoria, y conforme la edad decrece, los billetes de tercera clase se hacen más presentes, reforzando la relación negativa entre las variables observadas. El segundo gráfico también refuerza lo observado, ya que los billetes de mejor clase deben ser más caros.

Una vez calculada la correlación podemos dibujar el pairplot (es un paso opcional):

In [17]:
sns.pairplot(data = total_data)
Out[17]:
<seaborn.axisgrid.PairGrid at 0x7fa25912fed0>
No description has been provided for this image

FIN DEL DÍA 1

¡Ahora, trabajemos y practiquemos la lección de hoy para afianzar lo aprendido!

DÍA 2

Paso 5: Ingeniería de características

La ingeniería de características (feature engineering) es un proceso que implica la creación de nuevas características (o variables) a partir de las existentes para mejorar el rendimiento del modelo. Esto puede implicar una variedad de técnicas como la normalización, la transformación de los datos, etcétera. El objetivo es mejorar la precisión del modelo y/o reducir la complejidad del mismo, facilitando así su interpretación.

En los pasos previos hemos empezado a trabajar con los datos eliminando duplicados, contabilizando los valores nulos e, incluso, para calcular correlaciones, transformando Sex y Embarked en categorías numéricas. Si bien esto podríamos haberlo hecho en este paso, ya que forma parte de la ingeniería de características, normalmente suele hacerse antes de analizar las variables, separando este proceso en uno previo y este que vamos a ver a continuación.

Análisis de outliers

Un valor atípico (outlier) es un punto de datos que se desvía significativamente de los demás. Es un valor que es notablemente diferente de lo que sería de esperar dada la tendencia general de los datos. Estos outliers pueden ser causados por errores en la recolección de datos, variaciones naturales en los datos, o pueden ser indicativos de algo significativo, como una anomalía o evento extraordinario.

El análisis descriptivo es una poderosa herramienta para caracterizar el conjunto de datos: la media, desviación y los cuartiles nos brindan una poderosa información sobre cada variable. La función describe() de un DataFrame nos ayuda a calcular en unos tiempos muy reducidos todos estos valores.

In [18]:
total_data.describe()
Out[18]:
SurvivedPclassAgeSibSpParchFareSex_nEmbarked_n
count1309.0000001309.0000001046.0000001309.0000001309.0000001308.0000001309.0000001309.000000
mean0.3773872.29488229.8811380.4988540.38502733.2954790.3559970.392666
std0.4849180.83783614.4134931.0416580.86556051.7586680.4789970.655586
min0.0000001.0000000.1700000.0000000.0000000.0000000.000000-1.000000
25%0.0000002.00000021.0000000.0000000.0000007.8958000.0000000.000000
50%0.0000003.00000028.0000000.0000000.00000014.4542000.0000000.000000
75%1.0000003.00000039.0000001.0000000.00000031.2750001.0000001.000000
max1.0000003.00000080.0000008.0000009.000000512.3292001.0000002.000000

Si bien la experiencia es un componente importante en el análisis de los resultados de la tabla anterior, podemos utilizar ciertas reglas para detectarlos, como ver el valor mínimo y máximo de una característica específica y compararlo con su percentil 25% y 75%. Por ejemplo, todo parece normal salvo para la columna Fare que tiene una media de 32,20 pero su percentil del 50% es 14 y su valor máximo es 512. Podríamos decir que 512 parece ser un valor atípico, pero podría ser un error de transcripción. También es posible que el billete más caro tuviera ese precio. Sería útil investigar un poco y confirmar o desmentir esa información.

Dibujar los diagramas de cajas de las variables también nos da una información muy poderosa sobre los valores atípicos que se salen de las regiones de confianza:

In [19]:
fig, axis = plt.subplots(3, 3, figsize = (15, 10))

sns.boxplot(ax = axis[0, 0], data = total_data, y = "Survived")
sns.boxplot(ax = axis[0, 1], data = total_data, y = "Pclass")
sns.boxplot(ax = axis[0, 2], data = total_data, y = "Age")
sns.boxplot(ax = axis[1, 0], data = total_data, y = "SibSp")
sns.boxplot(ax = axis[1, 1], data = total_data, y = "Parch")
sns.boxplot(ax = axis[1, 2], data = total_data, y = "Fare")
sns.boxplot(ax = axis[2, 0], data = total_data, y = "Sex_n")
sns.boxplot(ax = axis[2, 1], data = total_data, y = "Embarked_n")

plt.tight_layout()

plt.show()