Análisis Exploratorio de Datos�
1
Análisis Exploratorio de Datos
2
John Tukey
Python y Anaconda
3
NumPy y SciPy
4
Pandas
5
Scikit-Learn
6
El dataset Iris
7
El dataset Iris
> from sklearn.datasets import load_iris�> import pandas as pd > iris = load_iris() �> iris_df = pd.DataFrame(iris.data, columns=iris.feature_names) �> iris_df.columns��Index(['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)', 'species'], dtype='object')
8
Datos Categóricos en Pandas
9
> iris_df['species'] = pd.Categorical.from_codes(iris.target, iris.target_names)
['setosa', 'versicolor', 'virginica']
Categories (3, object): ['setosa', 'versicolor', 'virginica']
Estadísticas de Resumen
10
Frecuencia y Moda
�> iris_df['species'].value_counts()��setosa 50 versicolor 50 virginica 50 Name: species, dtype: int64
�
11
Frecuencia y Moda (2)
> iris_df.mode()� sepal length (cm) sepal width (cm) ... petal width (cm) species
0 5.0 3.0 ... 0.2 setosa
12
Medidas de Tendencia Central
13
Medidas de Tendencia Central (2)
> import numpy as np �> vec = np.random.normal(20, 10, 10) > mean_vec = np.mean(vec) > vec_outlier = np.append(vec, np.random.normal(300, 100)) > mean_vec_outlier = np.mean(vec_outlier) > (mean_vec, mean_vec_outlier) (27.38023170728834, 53.4733340171792)
�
14
Medidas de Tendencia Central (3)
> from scipy import stats > trimmed_mean_vec = stats.trim_mean(vec, 0.1)�> trimmed_mean_vec_outlier = stats.trim_mean(vec_outlier, 0.1)�(27.645770484954127, 29.286121763516398)
15
Medidas de Tendencia Central (4)
> median_vec = np.median(vec)�> median_vec_outlier = np.median(vec_outlier) > (median_vec, median_vec_outlier)
(26.803434597319807, 29.500884175255894)
16
Comparación entre la moda, la mediana y la media
17
Percentiles o Cuantiles
18
Percentiles o Cuantiles (2)
# El mínimo, los tres cuartiles y el máximo�> iris_df['sepal length (cm)'].quantile([0, 0.25, 0.5, 0.75, 1])�0% 25% 50% 75% 100%�4.3 5.1 5.8 6.4 7.9 Name: sepal length (cm), dtype: float64
19
Resumiendo un Data Frame (1)
> iris_df.describe()
20
Ejercicio
21
iris_df.groupby('species')['sepal length (cm)'].describe()
iris_df.groupby('species')['sepal width (cm)'].describe()
iris_df.groupby('species')['petal length (cm)'].describe()
iris_df.groupby('species')['petal width (cm)'].describe()
Respuesta:
> iris_df.groupby('species')['petal length (cm)'].describe()
count mean std min 25% 50% 75% max
species
setosa 50.0 1.462 0.173664 1.0 1.4 1.50 1.575 1.9
versicolor 50.0 4.260 0.469911 3.0 4.0 4.35 4.600 5.1
virginica 50.0 5.552 0.551895 4.5 5.1 5.55 5.875 6.9
Medidas de Dispersión
3.6�
22
Medidas de Dispersión (2)
23
> iris_df['sepal length (cm)'].var()
0.6856935
> iris_df['sepal length (cm)'].std()
0.8280661
Medidas de Dispersión (3)
��
24
Medidas de Dispersión (4)
25
import numpy as np
def aad(x, fun=np.median):
return np.mean(abs(x - fun(x)))
result1 = aad(iris_df['sepal length (cm)'])
result2 = aad(iris_df['sepal length (cm)'], np.mean)
print(result1)
print(result2)
Medidas de Dispersión (5)
> stats.median_abs_deviation(iris_df["sepal length (cm)"])�0.7
����
26
Estadísticas de Resumen Multivariadas
> iris_df['sepal length (cm)'].cov(iris_df['sepal width (cm)'])
-0.042434
����
27
Estadísticas de Resumen Multivariadas (2)
> iris_df.drop(columns=["species"]).cov()
����
28
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
sepal length (cm) 0.685694 -0.042434 1.274315 0.516271
sepal width (cm) -0.042434 0.189979 -0.329656 -0.121639
petal length (cm) 1.274315 -0.329656 3.116278 1.295609
petal width (cm) 0.516271 -0.121639 1.295609 0.581006
Estadísticas de Resumen Multivariadas (3)
����
29
Estadísticas de Resumen Multivariadas (4)
> iris_df.drop(columns=["species"]).corr()
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) sepal length (cm) 1.000000 -0.117570 0.871754 0.817941 sepal width (cm) -0.117570 1.000000 -0.428440 -0.366126 petal length (cm) 0.871754 -0.428440 1.000000 0.962865 petal width (cm) 0.817941 -0.366126 0.962865 1.000000
����
30
Tablas de Contingencia
# Crear un DataFrame de ejemplo con datos categóricos
data = {'sexo': ['Hombre', 'Hombre', 'Mujer', 'Mujer'],
'estudios': ['universitario', 'secundario', 'secundario', 'universitario']}
df = pd.DataFrame(data)
# Convertir las columnas a tipo 'Categorical'
df['sexo'] = pd.Categorical(df['sexo'])
df['estudios'] = pd.Categorical(df['estudios'])
# Crear una tabla de contingencia usando crosstab
contingency_table = pd.crosstab(df['sexo'], df['estudios'])
����
31
Tablas de Contingencia (2)
32
Veamos ahora para el dataset iris:
# Para el propósito de este ejemplo, vamos a categorizar la 'sepal length (cm)'
# en 'corto', 'medio', 'largo' usando pd.cut para crear categorías basadas en cuantiles
iris_df['sepal_length_cat'] = pd.cut(iris_df['sepal length (cm)'], 3, labels=["corto", "medio", "largo"])
# Ahora, vamos a cruzar las categorías de 'sepal_length_cat' con las especies usando pd.crosstab
crosstab_result = pd.crosstab(iris_df['sepal_length_cat'], iris_df['species'])
# Obteniendo:
species setosa versicolor virginica
sepal_length_cat
corto 47 11 1
medio 3 36 32
largo 0 3 17
Visualización de Datos
����
33
Visualización de Datos
Fuente: Anscombe's quartet
34
Visualización de Datos
Fuente: Same Stats, Different Graphs
35
Matplotlib
����
36
Graficando en Python
import matplotlib.pyplot as plt
import numpy as np
# Establece la semilla aleatoria para reproducibilidad.
np.random.seed(0)
# Genera datos aleatorios utilizando la distribución normal con media 10 y desviación estándar 5
data = np.random.normal(10, 5, 15)
# Crear el plot
plt.figure(figsize=(10, 6))
# Add the lines for each type
plt.plot(data, color='red', label='líneas') # Línea roja
plt.scatter(range(len(data)), data, color='blue', label='puntos') # Puntos azules
plt.plot(data, 'g--', label='ambos') # Línea discontinua verde que muestra ambos.
# Título y legendas
plt.title('Mi gráfico')
plt.legend(loc='upper right')
# mostrar el plot
plt.show()
����
37
38
Histogramas
����
39
Histogramas (2)
import matplotlib.pyplot as plt
# Selecciona la columna sepal length
sepal_length = iris_df['sepal length (cm)']
# Crea un histograma de sepal length
plt.figure(figsize=(8, 6))
plt.hist(sepal_length, edgecolor='black', )
# Título y legendas
plt.title('Histogram of Sepal Length')
plt.xlabel('Sepal Length')
plt.ylabel('Frequency')
plt.show()
40
Código:
Histogramas (3)
plt.figure(figsize=(8, 6))
plt.hist(sepal_length, edgecolor='black', bins=100)
# Título y legendas
plt.title('Histogram of Sepal Length')
plt.xlabel('Sepal Length')
plt.ylabel('Frequency')
# Show the plot
plt.show()
����
41
Histogramas (4)
42
Densidad
�
43
Densidad (1)
����
44
Densidad (2)
Código:
from scipy import stats
# Calcula la densidad de la función
density = stats.gaussian_kde(sepal_length)
# Genera un rango de valores para los cuales queremos estimar la densidad.
xs = np.linspace(sepal_length.min(), sepal_length.max(), 200)
# Calcula la densidad para cada valor en xs.
density_values = density(xs)
# Crea la figura
plt.figure(figsize=(10, 6))
plt.plot(xs, density_values, linewidth=2)
# Título y legendas
plt.xlabel('Sepal Length')
plt.ylabel('Density')
plt.title('Density of Sepal Length')
����
45
Gráficos de Torta o Pie Charts
����
46
Gráficos de Torta o Pie Charts (2)
47
Código:
species_counts = iris_df["species"].value_counts()
species_names = iris_df['species'].cat.categories.tolist()
plt.figure(figsize=(8, 6))
plt.pie(species_counts, labels=species_names, autopct='%1.1f%%', startangle=140, colors=['#ff9999','#66b3ff','#99ff99'])
# Título
plt.title('Pie Chart of Iris Species')
plt.show()
Boxplots
48
Boxplots (2)
49
Boxplots (3)
El largo de los brazos así como el criterio para identificar valores atípicos se basa en el comportamiento de una normal.
50
Boxplots (4)
51
# Crea a boxplot
plt.figure(figsize=(8, 6))
plt.boxplot(sepal_length, patch_artist=True)
# Títulos y leyendas
plt.ylabel('Sepal Length')
plt.title('Boxplot Sepal.Length')
# Muestra the plot
plt.show()
Boxplots (5)
52
Boxplots (6)
Codigo:
# Combina los ejemplos en un sólo dataset
data_to_plot = [setosa_sample, versicolor_sample, virginica_sample]
species = ['Setosa', 'Versicolor', 'Virginica']
# Crea un boxplot agrepado
plt.figure(figsize=(10, 7))
plt.boxplot(data_to_plot, patch_artist=True)
# Agrega las etiquetas
plt.xticks([1, 2, 3], species)
plt.ylabel('Sepal Length')
# Título
plt.title('Boxplot of Sepal Length by Species')
# Mostrar the plot
plt.show()
53
Boxplots (7)
54
Boxplots (8)
Codigo:
# Combina los ejemplos en un sólo dataset
data_to_plot = [sepal_length_sample, sepal_width_sample, petal_length_sample, petal_width_sample]
measurements = ['Sepal Length', 'Sepal Width', 'Petal Length', 'Petal Width']
# Crea boxplots comparativos
plt.figure(figsize=(12, 8))
plt.boxplot(data_to_plot, patch_artist=True)
# Agregar etiquetas
plt.xticks([1, 2, 3, 4], measurements)
plt.title('Comparative Boxplots of Iris Measurements')
55
Boxplots (9)
56
Boxplots (10)
�Código:
# Crear una figura
fig = go.Figure()
# Agregar los boxplots para cada especie
fig.add_trace(go.Box(y=setosa_sepal_length, name='Setosa', marker_color='red'))
fig.add_trace(go.Box(y=versicolor_sepal_length, name='Versicolor', marker_color='green'))
fig.add_trace(go.Box(y=virginica_sepal_length, name='Virginica', marker_color='blue'))
# Agregar títulos y etiquetas
fig.update_layout(
title='Sepal Length by Species',
yaxis_title='Sepal Length',
boxmode='group' # Agrupar juntas las cajas de los diferentes trazos para cada categoría
)
57
Diagramas de Dispersión
58
Diagramas de Dispersión (2)
# Plot
plt.figure(figsize=(10, 6))
# Setosa Plot
plt.scatter(setosa_sepal_length, setosa_sepal_width, c='black', marker='o', label='Setosa')
# Versicolor Plot
plt.scatter(versicolor_sepal_length, versicolor_sepal_width, c='red', marker='^', label='Versicolor')
# Virginica Plot
plt.scatter(virginica_sepal_length, virginica_sepal_width, c='green', marker='+', label='Virginica')
# Legendas
plt.legend(title='Species')
# Título y ejes
plt.xlabel('Sepal.Length')
plt.ylabel('Sepal.Width')
plt.title('Sepal Width vs. Sepal Length')
59
Código:
Diagramas de Dispersión (3)
Lo mismo usando plotly:
fig = px.scatter(iris_df, x='sepal length (cm)', y='sepal width (cm)', color='Species', color_discrete_map={'Setosa': 'red', 'Versicolor': 'green', 'Virginica': 'blue'})
60
Diagramas de Dispersión (4)
Para graficar todos los pares de las 4 variables del dataset iris usando un color y un carácter distinto para cada especie, no es posible hacerlo directamente en matplotlib, pero en plotly:
61
fig = px.scatter_matrix(df,
dimensions=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'],
color='species',
symbol='species',
title='Pair plot of Iris dataset'
)
Diagramas de Dispersión (5)
62
# Plot the values
colors = {'Setosa': 'b', 'Versicolor': 'r', 'Virginica': 'g'}
markers = {'Setosa': 'o', 'Versicolor': '^', 'Virginica': '+'}
for s, c, m in zip(species, colors.values(), markers.values()):
ax.scatter(x, y, z, c=c, marker=m, label=s)
ax.set_xlabel('Sepal Length')
ax.set_ylabel('Sepal Width')
ax.set_zlabel('Petal Width')
plt.legend()
plt.title('3D Scatter Plot')
Diagramas de Dispersión (6)
63
Gráficos de Coordenadas Paralelas
64
Gráficos de Coordenadas Paralelas (2)
pd.plotting.parallel_coordinates(data, 'Species', colormap=plt.get_cmap("Set1"))
plt.title('Parallel Coordinates Plot for Iris Data')
65
�Gráficos de Estrellas o Radar Charts
66
Gráficos de Estrellas o Radar Charts
67
Gráficos de Estrellas o Radar Charts
68
# Número de variables
num_vars = len(data.columns) - 1
# Calcular los ángulos para cada eje
angles = [n / float(num_vars) * 2 * pi for n in range(num_vars)]
angles += angles[:1] # to complete the loop
# Función Radar chart
def make_spider(row, title, color):
values = data.iloc[row].drop('Species').values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
ax.fill(angles, values, color=color, alpha=0.4)
# Beautify el plot
plt.title(title, size=11, color=color, y=1.1)
# Inicializa spider plot
fig = plt.figure(figsize=(10, 15))
# Crea un radar chart for cada plot
for i in range(data.shape[0]):
ax = plt.subplot(3, 2, i+1, polar=True)
make_spider(i, f'Sample {i+1} - {data.iloc[i]["Species"]}', 'blue')
Caras de Chernoff
69
Caras de Chernoff (2)
Ejemplo:
70
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt
# import chernoff_face para graficar
from ChernoffFace import chernoff_face
# Normalizar los datos
scaler = MinMaxScaler()
iris_normalized = scaler.fit_transform(iris_df)
# Crear un array con los nombres de las especies para cada instancia
species_names = [iris.target_names[i] for i in iris.target]
# Generar las Caras de Chernoff para los datos normalizados y etiquetar con nombres de especies
fig = chernoff_face(data=iris_normalized,
titles=species_names,
color_mapper=plt.cm.Pastel1,
figsize=(12, 12))
# Mostrar las caras
plt.tight_layout()
plt.show()
Caras de Chernoff (3)
71
72