Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Análisis Exploratorio de Datos
Fecha: 29 de Noviembre del 2022
En esta clase veremos algunos elementos descriptivos, numéricos y gráficos entorno a un conjunto de datos. El proceso de análisis que realizaremos se conoce como análisis exploratorio de datos, el cual corresponde a lo primero que debemos de hacer de manera propia cuando trabajamos con un conjunto de datos y es de nuestro interés llevar acabo un análisis sobre éstos.
Para ello, comenzaremos por cargar los datos:
import pandas as pd
df = pd.read_csv('https://cursopypagina.github.io/CursoPy/titanic.csv')
# vemos los primeros registros de nuestro conjunto de datos
df.head()
survived | pclass | age | sibsp | parch | fare | male | age_was_missing | embarked_from_cherbourg | embarked_from_queenstown | embarked_from_southampton | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 3 | 22.0 | 1 | 0 | 7.2500 | 1 | False | 0 | 0 | 1 |
1 | 1 | 1 | 38.0 | 1 | 0 | 71.2833 | 0 | False | 1 | 0 | 0 |
2 | 1 | 3 | 26.0 | 0 | 0 | 7.9250 | 0 | False | 0 | 0 | 1 |
3 | 1 | 1 | 35.0 | 1 | 0 | 53.1000 | 0 | False | 0 | 0 | 1 |
4 | 0 | 3 | 35.0 | 0 | 0 | 8.0500 | 1 | False | 0 | 0 | 1 |
Diremos que una variable (o dato) es cuantitativo si sus posibles valores son numéricos. En cambio, diremos que una variable es cualitativa si sus valores representan una cualidad, un atributo o una categoría. A las variables cualitativas también se le denominan categóricas.
De nuestro conjunto de datos anterior veamos cuales variables (columnas) son cuantitativas o cualitativas
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 891 entries, 0 to 890 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 survived 891 non-null int64 1 pclass 891 non-null int64 2 age 891 non-null float64 3 sibsp 891 non-null int64 4 parch 891 non-null int64 5 fare 891 non-null float64 6 male 891 non-null int64 7 age_was_missing 891 non-null bool 8 embarked_from_cherbourg 891 non-null int64 9 embarked_from_queenstown 891 non-null int64 10 embarked_from_southampton 891 non-null int64 dtypes: bool(1), float64(2), int64(8) memory usage: 70.6 KB
Tenemos que las variables cuantitativas son age, fare
y las cualitativas son el resto. Además, tendremos que las variables cuantitativas pueden ser discretas o continuas. De nuestro ejemplo tenemos que las variables cuantitativas son continuas.
Por otro lado, podemos ver también algunas estadísticas sobre las columnas numéricas de nuestro conjunto de datos
df.describe()
survived | pclass | age | sibsp | parch | fare | male | embarked_from_cherbourg | embarked_from_queenstown | embarked_from_southampton | |
---|---|---|---|---|---|---|---|---|---|---|
count | 891.000000 | 891.000000 | 891.000000 | 891.000000 | 891.000000 | 891.000000 | 891.000000 | 891.000000 | 891.000000 | 891.000000 |
mean | 0.383838 | 2.308642 | 29.699118 | 0.523008 | 0.381594 | 32.204208 | 0.647587 | 0.188552 | 0.086420 | 0.722783 |
std | 0.486592 | 0.836071 | 13.002015 | 1.102743 | 0.806057 | 49.693429 | 0.477990 | 0.391372 | 0.281141 | 0.447876 |
min | 0.000000 | 1.000000 | 0.420000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
25% | 0.000000 | 2.000000 | 22.000000 | 0.000000 | 0.000000 | 7.910400 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
50% | 0.000000 | 3.000000 | 29.699118 | 0.000000 | 0.000000 | 14.454200 | 1.000000 | 0.000000 | 0.000000 | 1.000000 |
75% | 1.000000 | 3.000000 | 35.000000 | 1.000000 | 0.000000 | 31.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 |
max | 1.000000 | 3.000000 | 80.000000 | 8.000000 | 6.000000 | 512.329200 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
donde vemos:
count=891
mean
min
max
std
Además, con base en la tabla anterior podemos comenzar a sacar información relevante sobre nuestros datos. Por ejemplo, si consideramos
# guardamos las estadisticas obtenidas en la variable df_des
df_des = df.describe()
# nos concentramos solo en la columna survived
df_des['survived']
count 891.000000 mean 0.383838 std 0.486592 min 0.000000 25% 0.000000 50% 0.000000 75% 1.000000 max 1.000000 Name: survived, dtype: float64
Dado en dicha columna solo hay ceros y unos, que el promedio sea igual a 0.38 nos dice que, en promedio, hubo más decesos que personas que sobrevivieron.
¿Qué se puede decir de la columna age
?
# muestra el dataframe df_des pero solo la columna age
df_des['age']
count 891.000000 mean 29.699118 std 13.002015 min 0.420000 25% 22.000000 50% 29.699118 75% 35.000000 max 80.000000 Name: age, dtype: float64
Reesponde a la pregunta que se ha hecho anteriormente:
En promedio los pasajeros tenían 29 años
Edad del pasajero más joven: 0.4
Edad del pasajero más grande: 80
¿Qué se puede decir de la columna male
?
# muestra el dataframe df_des pero solo la columna male
df_des['male']
count 891.000000 mean 0.647587 std 0.477990 min 0.000000 25% 0.000000 50% 1.000000 75% 1.000000 max 1.000000 Name: male, dtype: float64
Reesponde a la pregunta que se ha hecho anteriormente:
Continuando, diremos que la frecuencia de una clase o una categoría es el número de veces que la clase es observada. De nuestro ejemplo, particularmente estaremos interesados en la columna survived
y male
, las cuales son variables categóricas con dos clases. Para visualizar las frecuencias de las clases utilizaremos un histograma:
import matplotlib.pyplot as plt
plt.style.use('seaborn')
# veremos el histograma de las frecuencia de la variable survived
df.survived.hist(color='#01B9FA')
plt.title('Frecuencia para la variable survived', size=16)
plt.xlabel('0: deceso, 1: sobrevivió')
plt.ylabel('Frecuencia')
plt.show()
donde, tenemos que la clase 0 (decesos) tiene más frecuencia de aparición que la clase 1 (sobrevivientes).
Gráfica un histograma como el anterior para la columna male
y obtén conclusiones (qué observas).
# Escribe tu codigo aqui
# veremos el histograma de las frecuencia de la variable survived
df.male.hist()
plt.title('Frecuencia para la variable male', size=16)
plt.ylabel('Frecuencia')
plt.show()
Por otro lado, puede que estemos interesados en ver un gráfico informativo para la columna age
, la cual no es categórica por lo cual no podremos ver un histograma.
Para poder ver un histograma con la información de dicha columna emplearemos:
# Consideramos solo la columna edad
df_age = pd.DataFrame(df.age)
df_age
age | |
---|---|
0 | 22.000000 |
1 | 38.000000 |
2 | 26.000000 |
3 | 35.000000 |
4 | 35.000000 |
... | ... |
886 | 27.000000 |
887 | 19.000000 |
888 | 29.699118 |
889 | 26.000000 |
890 | 32.000000 |
891 rows × 1 columns
# Definimos una funcion para clasificar a las personas de acuerdo a
# un rango de edad
def rango_edad(x):
if x <= 12:
return 'Niño/a'
elif (x > 12) and (x <= 18):
return 'Joven'
elif (x > 18) and (x <= 30):
return 'Adulto/a joven'
elif (x > 30) and (x <= 60):
return 'Adulto/a'
else:
return 'Adulto/a mayor'
# agregamos una columna nueva clasificando cada fila de acuerdo
# a su edad
df_age['Rango_edad'] = df_age.age.apply(lambda x: rango_edad(x))
df_age.head()
age | Rango_edad | |
---|---|---|
0 | 22.0 | Adulto/a joven |
1 | 38.0 | Adulto/a |
2 | 26.0 | Adulto/a joven |
3 | 35.0 | Adulto/a |
4 | 35.0 | Adulto/a |
# veremos el histograma de las frecuencia de la variable survived
df_age.Rango_edad.hist(color='#01B9FA')
plt.title('Frecuencia para la variable survived', size=16)
plt.ylabel('Frecuencia')
plt.show()
Vemos que en su mayoría las personas abordo eran adultos jóvenes (18-30 años de edad).
Por otro lado, podemos ver de manera directa un gráfico referente al comportamiento de las edades de los tripulantes:
df_age.sort_values('age', ascending=False)
age | Rango_edad | |
---|---|---|
630 | 80.00 | Adulto/a mayor |
851 | 74.00 | Adulto/a mayor |
96 | 71.00 | Adulto/a mayor |
493 | 71.00 | Adulto/a mayor |
116 | 70.50 | Adulto/a mayor |
... | ... | ... |
831 | 0.83 | Niño/a |
469 | 0.75 | Niño/a |
644 | 0.75 | Niño/a |
755 | 0.67 | Niño/a |
803 | 0.42 | Niño/a |
891 rows × 2 columns
# iloc[x] accede a la fila x
df_age.sort_values('age', ascending=False).iloc[0]
age 80.0 Rango_edad Adulto/a mayor Name: 630, dtype: object
df_age.sort_values('age', ascending=False).iloc[1]
age 74.0 Rango_edad Adulto/a mayor Name: 851, dtype: object
df_age.sort_values('age', ascending=False).iloc[1][0]
74.0
df_age.sort_values('age', ascending=False).iloc[1][1]
'Adulto/a mayor'
df_age.sort_values('age', ascending=False).iloc[1][2]
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-31-1cff3f22427b> in <module> ----> 1 df_age.sort_values('age', ascending=False).iloc[1][2] /usr/local/lib/python3.7/dist-packages/pandas/core/series.py in __getitem__(self, key) 937 938 if is_integer(key) and self.index._should_fallback_to_positional(): --> 939 return self._values[key] 940 941 elif key_is_scalar: IndexError: index 2 is out of bounds for axis 0 with size 2
# Definimos una funcion que nos arroje la edad dada una fila del dataframe,
# donde dicho dataframe estara previamente ordenado de mayor a menor
f = lambda x: df_age.sort_values('age', ascending=False).iloc[x][0]
# Graficaremos la edad de los tripulantes f(0)
plt.plot([i for i in range(len(df_age))], [f(i) for i in range(len(df_age))])
plt.xlabel('Número de personas')
plt.ylabel('Edades')
plt.show()
241 / 891 * 100
27.048260381593714
Notamos que, en efecto, hubo muchas personas consideradas adultos jóvenes, donde podemos ver que, en particular, hubo una gran cantidad de personas cuya edad es muy cercana a los 30. Asimismos, podemos ver que la mayoría de las personas tuvieron una edad entre los 18 y los 30 años; hubo pocas personas que tuvieron una edad menor a los 10 años, al igual que muy pocas personas mayores de 60 años.
¿Cuántas personas tuvieron una edad entre los 29 y 31 años?
# Escribe el codigo necesario para responder la pregunta anterior
df[(df.age >= 29) & (df.age <= 31)]
survived | pclass | age | sibsp | parch | fare | male | age_was_missing | embarked_from_cherbourg | embarked_from_queenstown | embarked_from_southampton | |
---|---|---|---|---|---|---|---|---|---|---|---|
5 | 0 | 3 | 29.699118 | 0 | 0 | 8.4583 | 1 | True | 0 | 1 | 0 |
17 | 1 | 2 | 29.699118 | 0 | 0 | 13.0000 | 1 | True | 0 | 0 | 1 |
18 | 0 | 3 | 31.000000 | 1 | 0 | 18.0000 | 0 | False | 0 | 0 | 1 |
19 | 1 | 3 | 29.699118 | 0 | 0 | 7.2250 | 0 | True | 1 | 0 | 0 |
26 | 0 | 3 | 29.699118 | 0 | 0 | 7.2250 | 1 | True | 1 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
863 | 0 | 3 | 29.699118 | 8 | 2 | 69.5500 | 0 | True | 0 | 0 | 1 |
867 | 0 | 1 | 31.000000 | 0 | 0 | 50.4958 | 1 | False | 0 | 0 | 1 |
868 | 0 | 3 | 29.699118 | 0 | 0 | 9.5000 | 1 | True | 0 | 0 | 1 |
878 | 0 | 3 | 29.699118 | 0 | 0 | 7.8958 | 1 | True | 0 | 0 | 1 |
888 | 0 | 3 | 29.699118 | 1 | 2 | 23.4500 | 0 | True | 0 | 0 | 1 |
241 rows × 11 columns
Finalmente, trataremos de ver si existen relaciones entre las variables de nuestro conjunto de datos, para lo cual analizaremos:
Comenzaremos realizando algunos diagramas de dispersión, donde debemos tener cuidado pues, para dos variables en cuestión éstas deben ser ambas cuantitativas para poder realizar un gráfico de este tipo. De tal manera tendremos sólo un posible diagrama de dispersión:
df
survived | pclass | age | sibsp | parch | fare | male | age_was_missing | embarked_from_cherbourg | embarked_from_queenstown | embarked_from_southampton | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 3 | 22.000000 | 1 | 0 | 7.2500 | 1 | False | 0 | 0 | 1 |
1 | 1 | 1 | 38.000000 | 1 | 0 | 71.2833 | 0 | False | 1 | 0 | 0 |
2 | 1 | 3 | 26.000000 | 0 | 0 | 7.9250 | 0 | False | 0 | 0 | 1 |
3 | 1 | 1 | 35.000000 | 1 | 0 | 53.1000 | 0 | False | 0 | 0 | 1 |
4 | 0 | 3 | 35.000000 | 0 | 0 | 8.0500 | 1 | False | 0 | 0 | 1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
886 | 0 | 2 | 27.000000 | 0 | 0 | 13.0000 | 1 | False | 0 | 0 | 1 |
887 | 1 | 1 | 19.000000 | 0 | 0 | 30.0000 | 0 | False | 0 | 0 | 1 |
888 | 0 | 3 | 29.699118 | 1 | 2 | 23.4500 | 0 | True | 0 | 0 | 1 |
889 | 1 | 1 | 26.000000 | 0 | 0 | 30.0000 | 1 | False | 1 | 0 | 0 |
890 | 0 | 3 | 32.000000 | 0 | 0 | 7.7500 | 1 | False | 0 | 1 | 0 |
891 rows × 11 columns
df.plot.scatter(x='age', y='fare')
plt.title('Age vs Fare')
plt.show()
donde notamos que, al parecer, dichas variables no se encuentran relacionadas. Corroboremos lo anterior mediante el coeficiente de correlación de Pearson:
# el siguiente codigo nos arrojara una tabla con el coeficiente de
# correlacion de pearson entre todas las variables de nuestro
# conjunto de datos
df.corr(method='pearson')
survived | pclass | age | sibsp | parch | fare | male | age_was_missing | embarked_from_cherbourg | embarked_from_queenstown | embarked_from_southampton | |
---|---|---|---|---|---|---|---|---|---|---|---|
survived | 1.000000 | -0.338481 | -6.980852e-02 | -0.035322 | 0.081629 | 0.257307 | -0.543351 | -9.219652e-02 | 0.168240 | 0.003650 | -0.155660 |
pclass | -0.338481 | 1.000000 | -3.313388e-01 | 0.083081 | 0.018443 | -0.549500 | 0.131900 | 1.729329e-01 | -0.243292 | 0.221009 | 0.081720 |
age | -0.069809 | -0.331339 | 1.000000e+00 | -0.232625 | -0.179191 | 0.091566 | 0.084153 | -1.303789e-16 | 0.032024 | -0.013855 | -0.027121 |
sibsp | -0.035322 | 0.083081 | -2.326246e-01 | 1.000000 | 0.414838 | 0.159651 | -0.114631 | 1.895757e-02 | -0.059528 | -0.026354 | 0.070941 |
parch | 0.081629 | 0.018443 | -1.791909e-01 | 0.414838 | 1.000000 | 0.216225 | -0.245489 | -1.241038e-01 | -0.011069 | -0.081228 | 0.063036 |
fare | 0.257307 | -0.549500 | 9.156609e-02 | 0.159651 | 0.216225 | 1.000000 | -0.182333 | -1.007071e-01 | 0.269335 | -0.117216 | -0.166603 |
male | -0.543351 | 0.131900 | 8.415344e-02 | -0.114631 | -0.245489 | -0.182333 | 1.000000 | 5.521512e-02 | -0.082853 | -0.074115 | 0.125722 |
age_was_missing | -0.092197 | 0.172933 | -1.303789e-16 | 0.018958 | -0.124104 | -0.100707 | 0.055215 | 1.000000e+00 | 0.033270 | 0.337413 | -0.238377 |
embarked_from_cherbourg | 0.168240 | -0.243292 | 3.202442e-02 | -0.059528 | -0.011069 | 0.269335 | -0.082853 | 3.326967e-02 | 1.000000 | -0.148258 | -0.778359 |
embarked_from_queenstown | 0.003650 | 0.221009 | -1.385524e-02 | -0.026354 | -0.081228 | -0.117216 | -0.074115 | 3.374132e-01 | -0.148258 | 1.000000 | -0.496624 |
embarked_from_southampton | -0.155660 | 0.081720 | -2.712109e-02 | 0.070941 | 0.063036 | -0.166603 | 0.125722 | -2.383767e-01 | -0.778359 | -0.496624 | 1.000000 |
Notamos que para age
versus fare
el coeficiente es de 0.091566, esto es, las variables no están relacionadas.
Notamos también que, para survived
versus male
el coeficiente es de -0.543351, lo cual nos da indicios de una posible relación inversa.