Exploratory Data Analysis en Python
Exploratory Data Analysis en Python
ipynb - Colaboratory
Introduccion
Exploratory Data Analysis o (EDA) es el proceso para entender un set de datos sumarizando sus
caracteristicas y mostrandolas visualmente. Este paso es sumamente importante en el
modelado de datos y la posterior aplicacion de Machine Learning. En el EDA se utilizan
histogramas, Boxplots, Scatter plotes o cualquier otra visualizacion que ayude a representas las
columnas sea univariada o multivariadamente. Explorar los datos toma tiempo y ayuda a definir
el conjunto de datos necesarios para abordar un problema asi como a entender el problema en
si mismo
No hay un método definido para llevarlo adelante, depende principalmente de los datos que se
estan explorando, por ejemplo, si hay datos categoricos (categorias o etiquetas) se suele contar
cantidades y poner los datos numericos en funcion de estas, si se analizan datos historicos
suele ser interesante ver el comportamiento de las variables en funcion del tiempo. En datasets
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 1/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
con texto libre se practica procesamiento de lenguaje natural para investigar repeticiones de
palabras o n-gramas
Este EDA se realizó sobre el dataset de ejemplo del Titanic que contiene la lista de pasajeros del
barco y sus acompañantes
import pandas as pd
import numpy as np
import seaborn as sns #visualisacion
import matplotlib.pyplot as plt #visualisacion
from matplotlib import rcParams
%matplotlib inline
sns.set(color_codes=True)
pd.set_option('display.max_columns', None)
rcParams['figure.figsize'] = 12,8
Pandas es la libreria de Python mas importante para el manejo de datos tabulares. En este caso
particular estoy leyendo el dataset desde internet, pero Google Colab tiene la opcion de cargar
archivos desde local o conectarse a Google Drive
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 2/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
df_path = "https://web.stanford.edu/class/archive/cs/cs109/cs109.1166/stuff/titanic
df = pd.read_csv(df_path)
df
Siblings/Spouses Parents/Children
Survived Pclass Name Sex Age
Aboard Aboard
Mr. Owen
0 0 3 Harris male 22.0 1 0
Braund
Mrs. John
Bradley
(Florence
1 1 1 female 38.0 1 0
Briggs
Thayer)
Cum...
Miss.
2 1 3 Laina female 26.0 0 0
Heikkinen
Mrs.
Jacques
Heath
3 1 1 female 35.0 1 0
(Lily May
Peel)
Futrelle
La funcion info() nos muestra la cantidad de datos no nulos en cada columna asi como los tipos
de dato. Hay 5 tipo básicos que podemos identificar, object que en general representa strigs,
float64, números de punto flotante, int64, números enteros, datetime que codifica fechas y
boolean que muestra valores verdaderos/falsos
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 887 entries, 0 to 886
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Survived 887 non-null int64
1 Pclass 887 non-null int64
2 Name 887 non-null object
3 Sex 887 non-null object
4 Age 887 non-null float64
5 Siblings/Spouses Aboard 887 non-null int64
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 3/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
Es importante revisar los tipos de dato para validar que los datos son interpretados
correctamente. En este caso el campo Pclass que indica la clase en la que viajaban los
pasajeros (1ra, 2da o 3ra) es un int64, pero en la práctica es una etiqueta sobre la que no vamos
a realizar ningun calculo matemático, por lo que elegimos convertirlo a object
df['Pclass'] = df['Pclass'].astype(str)
Tambien podemos observar que el campo Age esta codificado como float64 cuando la lógica
indica que es un entero, pero antes de realizar esta conversion necesitamos averiguar un poco
mas del contenido. Por el momento no realizamos ningun cambio
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 887 entries, 0 to 886
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Survived 887 non-null int64
1 Pclass 887 non-null object
2 Name 887 non-null object
3 Sex 887 non-null object
4 Age 887 non-null float64
5 Siblings/Spouses Aboard 887 non-null int64
6 Parents/Children Aboard 887 non-null int64
7 Fare 887 non-null float64
dtypes: float64(2), int64(3), object(3)
memory usage: 55.6+ KB
4. Renomabrar columnas
Podemos cambiar los nombres de las columnas para que sean mas simples de interpretar. Por
ejemplo:
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 4/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
Mr. Owen
0 0 3 Harris male 22.0 1 0
Braund
Mrs. John
Bradley
(Florence
1 1 1 female 38.0 1 0 7
Briggs
Thayer)
5. Buscar duplicados
Una práctica comun es revisar los datos para encontrar duplicados de forma general (filas
completas duplicadas) o en forma particulas sobre los indices o columnas primarias como por
ejemplo, mas de una fila por cliente pero con distintos datos
df.shape
(887, 8)
duplicate_rows_df = df[df.duplicated()]
print("Filas Duplicadas: ", duplicate_rows_df.shape)
Survived 887
Boarding_class 887
Name 887
Sex 887
Age 887
siblings 887
parent_children 887
Fare 887
dtype: int64
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 5/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
De la misma forma que en el paso anterior, buscamos valores faltantes o nulls en las variables.
Dependiendo de lo que encontremos podriamos:
Survived 0
Boarding_class 0
Name 0
Sex 0
Age 0
siblings 0
parent_children 0
Fare 0
dtype: int64
En este caso, podemos ver que no hay valores faltantes a simple vista
7. Detectar Outliers
Un outlier o dato atípico es un punto o grupo de puntos que es diferente de los demas. Los
datos atípicos pueden perjudicar el rendimiento de los modelos y no nos permiten ver la
distribucion real de la variable. Veamos el siguiente ejemplo
An outlier is a point or set of points that are different from other points. Sometimes they can be
very high or very low. It's often a good idea to detect and remove the outliers. Because outliers
are one of the primary reasons for resulting in a less accurate model. Hence it's a good idea to
remove them. The outlier detection and removing that I am going to perform is called IQR score
technique. Often outliers can be seen with visualizations using a box plot. Shown below are the
box plot of MSRP, Cylinders, Horsepower and EngineSize. Herein all the plots, you can find some
points are outside the box they are none other than outliers. The technique of finding and
removing outlier that I am performing in this assignment is taken help of a tutorial from towards
data science.
sns.boxplot(x=df['Fare'])
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 6/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='Fare'>
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 7/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
Como podemos ver, el grueso de la distribución se encuentra en la caja y los bigotes, y lo que
esta por encima o por debajo es considerado estadisticamente un outlier. Ahora veamos el
boxplot de la variable Fare de nuevo sin el dato de >500
sns.boxplot(x=df.loc[df['Fare']<500,'Fare'])
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 8/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='Fare'>
Como se puede apreciar aun hay outliers, pero ya podemos ver un poco mejor la caja. Lo que
nos muestra la visualizacion es que el grueso de la población pagó como tarifa entre 0 y 60$ y el
resto son datos atípicos
Ahora, que hacemos con estos datos? Lo primero es enteder si son correctos, ese
entendimiento siempre proviene del negocio, si no son correctos, arreglarlo con el valor
verdadero (casi nunca se puede) o eliminar la fila (no queremos valores que sabemos que son
incorrectos)
Si fueran correcto o no podemos validarlo, podriamos eliminar todos los casos pero no siempre
es la mejor opcion, imaginense que el objetivo de trabajar con este dataset fuera definir el precio
de los boletos de 1ra, 2da y 3ra clase en base a lo que pagaron los tripulantes del viaje original,
estariamos eliminando a la gente que pago mas y es una conocida estrategia de marketing
venderles a los que puede pagar mas, por lo que en ese caso, eliminarlos seria
contraproducente.
Para concluir, eliminar alguno o todos los outliers es una decision que se toma en base a toda la
información y al problema que se intenta abordar
sns.boxplot(x=df['Age'])
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 9/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='Age'>
En el boxplot de Age, tenemos algunos outliers de edad avanzada que suenan raros para la
época, pero que no son imposibles
df.loc[df.Age>70]
Mr. George
95 0 1 B male 71.0 0
Goldschmidt
Mr. Patrick
115 0 3 male 70.5 0
Connors
Mr. Ramon
490 0 1 male 71.0 0
Artagaveytia
sns.boxplot(x=df['siblings'])
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 10/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='siblings'>
sns.boxplot(x=df['parent_children'])
<AxesSubplot:xlabel='parent_children'>
En el caso de parent_children, la mayoria de los tripulantes subieron sin padres ni hijos, por eso
la caja y los bigotes estan comprimidos en el 0. Dicho esto podriamos considerar directamente
no usar la variable para ningun analisis, pero antes validemos cuantos hay en los buckets del 1
al 6
#df[['parent_children', 'Survived']].groupby('parent_children').count()
#sns.countplot(df['parent_children'])
ax = sns.countplot(x=df['parent_children'],
order=df['parent_children'].value_counts(ascending=False).index
abs_values = df['parent_children'].value_counts(ascending=False).values
ax.bar_label(container=ax.containers[0], labels=abs_values)
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 11/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
[Text(0, 0, '674'),
Text(0, 0, '118'),
Text(0, 0, '80'),
Text(0, 0, '5'),
Text(0, 0, '5'),
Text(0, 0, '4'),
Text(0, 0, '1')]
Como podemos ver, no es un solo caso en los outliers, entre 1 y 2 hay casi 200 familias. por lo
que no seria recomendable eliminarlos. Pero revisemos el caso puntual de los mas grandes
df.loc[df.parent_children>=5]
Mr. Anders
13 0 3 Johan male 39.0 1
Andersson
Mrs. Carl
Oscar
(Selma
25 1 3 female 38.0 1
Augusta
Emilia
Johansso...
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 12/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
Los ejemplos se ven correctos, son personas que estaban en 3ra clase y viajaron,
probablemente, con sus hijos
Histograma
Un histogramas es una representación gráfica de una variable en forma de barras, donde la
superficie de cada barra es proporcional a la frecuencia de los valores representados. Sirven
para obtener una "primera vista" general, o panorama, de la distribución de la población, o de la
muestra, respecto a una característica, cuantitativa y continua.
Que hacemos en el caso de las variables categoricas?. Un grafico de barras o Countplot que
muestra la cantidad de ejemplos por categoria como vimos en el caso anterior
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 887 entries, 0 to 886
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Survived 887 non-null int64
1 Boarding_class 887 non-null object
2 Name 887 non-null object
3 Sex 887 non-null object
4 Age 887 non-null float64
5 siblings 887 non-null int64
6 parent_children 887 non-null int64
7 Fare 887 non-null float64
dtypes: float64(2), int64(3), object(3)
memory usage: 55.6+ KB
sns.countplot(x=df.Survived, color='lightblue')
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 13/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='Survived', ylabel='count'>
sns.countplot(x=df.Boarding_class, color='red')
<AxesSubplot:xlabel='Boarding_class', ylabel='count'>
sns.countplot(x=df.Sex, color='red')
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 14/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='Sex', ylabel='count'>
Correlación
Este análisis nos muestra que tan dependientes son las variables unas de otras. Solo aplica
para variables numericas
plt.figure(figsize=(10,5))
c= df.corr()
sns.heatmap(c,cmap="BrBG",annot=True)
c
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 15/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
1. Hay una leve correlacion positiva entre Survived y Fare, lo que tiene sentido ya que habia
mas gente de 3ra clase que de las otras y se conoce que fallecio mas gente de 3ra
2. Correlación positiva entre siblings/spouse y parent_children, que puede esta relacionacion
con que mas parejas llevaron a sus hijos que cabezas de familia que viajaron solas
<seaborn.axisgrid.FacetGrid at 0x7f4bf9498fd0>
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 16/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<seaborn.axisgrid.FacetGrid at 0x7f4bf958a110>
Podemos ver que si bien la primera clase tiene las tarifas mas altas, noy hay tanta diferencia
entre las clases 2 y 3. Veamos que paso entre las clases y el indice de supervivencia
<AxesSubplot:xlabel='Boarding_class', ylabel='count'>
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 17/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
Asi podemos observar la correlacion, esa positividad se da porque fallecio mas gente de 3ra
clase que pago tarifas mas bajas, mientras que de 1ra clase donde se pagaron las tarifas mas
altas sobrevivió mas gente del total de la clase
Scatterplot
Usamos scatterplot para revisar la correlation entre dos variables. Veamos ahora la relacion
entre siblings/spouse y parent_children para confirmar la segunda
<AxesSubplot:xlabel='siblings', ylabel='parent_children'>
Si bien se puede apreciar una relacion positiva entre ambas variables, la visualizacion no
muestra bien las cantidades. Probemos otra cosa
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 18/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='siblings', ylabel='Count'>
Aca se puede interpretar un poco mejor, pero al estar la mayor cantidad en 0 el resto de los
valores no se aprecia correctamente
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 19/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
<AxesSubplot:xlabel='siblings', ylabel='parent_children'>
df.loc[df.siblings==0].groupby("parent_children").count()
parent_children
1 38 38 38 38 38 38 38
2 29 29 29 29 29 29 29
3 1 1 1 1 1 1 1
4 1 1 1 1 1 1 1
5 2 2 2 2 2 2 2
df.loc[df.siblings==4].groupby("parent_children").count()
parent_children
1 9 9 9 9 9 9 9
2 9 9 9 9 9 9 9
Un grafico de violin nos muetra mejor la situación por la cual se ve la correlación. El violin plot
combina la funcionalidad del box plot (mostrando los cuartiles de la distribución) y la de la
estimación de densidad kernel. Ésta es una forma muy atractiva de mostrar la distribución de un
conjunto de datos con respecto a una variable categórica, en este caso en funcion de una
variable entera.
Como mencioné al principio de este análisis, no hay un método o receta particular para llevar
adelante un analisis exploratorio, tampoco hay un limite sobre cuanto se puede explorar. Este
notebook busca mostrar un acercamiento y algunos tips al respecto
Muchas Gracias.
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 20/21
4/27/22, 11:14 PM Exploratory Data Analysis.ipynb - Colaboratory
https://colab.research.google.com/drive/1oTA5jHzhkOftrjrF-ZsAw15Zi5P2HJPI#scrollTo=TEfC0QszTKX_&printMode=true 21/21