Siempre es una buena idea examinar nuestros datos antes de empezar a trazar. Podemos leer los datos en un dataframe de pandas y mostrar las 10 primeras filas:
import pandas as pd# Read in data and examine first 10 rows
flights = pd.read_csv('data/formatted_flights.csv')
flights.head(10)
Los retrasos en la llegada de los vuelos están en minutos y los valores negativos significan que el vuelo se adelantó (resulta que los vuelos a menudo tienden a llegar antes, ¡sólo que nunca cuando estamos en ellos!) Hay más de 300.000 vuelos con un retraso mínimo de -60 minutos y un retraso máximo de 120 minutos. La otra columna del marco de datos es el nombre de la aerolínea, que podemos utilizar para hacer comparaciones.
Una buena manera de empezar a explorar una sola variable es con el histograma. Un histograma divide la variable en intervalos, cuenta los puntos de datos en cada intervalo y muestra los intervalos en el eje x y los recuentos en el eje y. En nuestro caso, las franjas serán un intervalo de tiempo que representa el retraso de los vuelos y el recuento será el número de vuelos que caen en ese intervalo. El binwidth es el parámetro más importante para un histograma y siempre debemos probar unos cuantos valores diferentes de binwidth para seleccionar el mejor para nuestros datos.
Para hacer un histograma básico en Python, podemos utilizar matplotlib o seaborn. El código siguiente muestra las llamadas a las funciones de ambas bibliotecas que crean figuras equivalentes. Para las llamadas a la gráfica, especificamos el ancho de la cubeta por el número de cubetas. Para este gráfico, usaré contenedores de 5 minutos de longitud, lo que significa que el número de contenedores será el rango de los datos (de -60 a 120 minutos) dividido por el ancho del contenedor, 5 minutos ( bins = int(180/5)
).
Para la mayoría de los histogramas básicos, Yo iría con el código de matplotlib porque es más simple, pero usaremos la función de seaborn distplot
más adelante para crear diferentes distribuciones y es bueno estar familiarizado con las diferentes opciones.
¿Cómo he llegado a 5 minutos para el binwidth? ¡La única manera de averiguar un binwidth óptimo es probar varios valores! A continuación se muestra el código para hacer la misma figura en matplotlib con una gama de binwidths. En última instancia, no hay una respuesta correcta o incorrecta para el binwidth, pero elijo 5 minutos porque creo que representa mejor la distribución.
La elección del binwidth afecta significativamente el gráfico resultante. Los anchos de bin más pequeños pueden hacer que el gráfico esté desordenado, pero los anchos de bin más grandes pueden oscurecer los matices de los datos. Matplotlib elegirá automáticamente una anchura de cubo razonable para usted, pero me gusta especificar la anchura de cubo yo mismo después de probar varios valores. No hay una verdadera respuesta correcta o incorrecta, así que pruebe algunas opciones y vea cuál funciona mejor para sus datos particulares.
Cuando los histogramas fallan
Los histogramas son una gran manera de comenzar a explorar una sola variable extraída de una categoría. Sin embargo, cuando queremos comparar las distribuciones de una variable a través de múltiples categorías, los histogramas tienen problemas de legibilidad. Por ejemplo, si queremos comparar las distribuciones de los retrasos de las llegadas entre aerolíneas, un enfoque que no funciona bien es crear histogramas para cada aerolínea en el mismo gráfico:
(Observe que el eje y se ha normalizado para tener en cuenta el diferente número de vuelos entre aerolíneas. Para ello, pase el argumento norm_hist = True
a la llamada de la función sns.distplot
.)
¡Este gráfico no es muy útil! Todas las barras superpuestas hacen casi imposible hacer comparaciones entre las aerolíneas. Veamos algunas soluciones posibles a este problema común.
Solución #1: Histogramas lado a lado
En lugar de superponer los histogramas de las aerolíneas, podemos colocarlos lado a lado. Para ello, creamos una lista de los retrasos de llegada de cada aerolínea y la pasamos a la llamada de la función plt.hist
como una lista de listas. Tenemos que especificar diferentes colores para cada aerolínea y una etiqueta para poder distinguirlas. El código, incluyendo la creación de las listas para cada aerolínea es el siguiente:
Por defecto, si pasamos una lista de listas, matplotlib pondrá las barras una al lado de la otra. Aquí, he cambiado la anchura de las barras a 15 minutos porque, de lo contrario, el gráfico está demasiado desordenado, pero incluso con esta modificación, no es una figura eficaz. Hay demasiada información para procesar a la vez, las barras no se alinean con las etiquetas, y sigue siendo difícil comparar las distribuciones entre las compañías aéreas. Cuando hacemos un gráfico, queremos que sea lo más fácil posible de entender para el espectador, ¡y esta figura no cumple ese criterio! Veamos una segunda solución potencial.
Solución #2: Barras apiladas
En lugar de trazar las barras de cada aerolínea una al lado de la otra, podemos apilarlas pasando el parámetro stacked = True
a la llamada del histograma:
# Stacked histogram with multiple airlines
plt.hist(, bins = int(180/15), stacked=True,
normed=True, color = colors, label=names)
¡Bueno, eso definitivamente no es mejor! Aquí, cada línea aérea está representada como una sección del conjunto para cada recipiente, pero es casi imposible hacer comparaciones. Por ejemplo, en un retraso de -15 a 0 minutos, ¿tiene United Air Lines o JetBlue Airlines un tamaño mayor de la barra? No puedo saberlo y los espectadores tampoco podrán hacerlo. En general, no soy partidario de las barras apiladas porque pueden ser difíciles de interpretar (aunque hay casos de uso, como cuando se visualizan proporciones). Las dos soluciones que intentamos con los histogramas no tuvieron éxito, así que es hora de pasar al gráfico de densidad.
Participaciones de densidad
Primero, ¿qué es un gráfico de densidad? Un gráfico de densidad es una versión continua y suavizada de un histograma estimado a partir de los datos. La forma más común de estimación se conoce como estimación de la densidad del núcleo. En este método, se dibuja una curva continua (el núcleo) en cada punto de datos individual y todas estas curvas se suman para hacer una única estimación de densidad suavizada. El núcleo más utilizado es una gaussiana (que produce una curva de campana gaussiana en cada punto de datos). Si, como a mí, esa descripción le resulta un poco confusa, eche un vistazo al siguiente gráfico:
Aquí, cada pequeña línea vertical negra en el eje x representa un punto de datos. Los kernels individuales (gaussianos en este ejemplo) se muestran dibujados en líneas rojas discontinuas sobre cada punto. La curva azul sólida se crea sumando las gaussianas individuales y forma el gráfico de densidad global.
El eje x es el valor de la variable al igual que en un histograma, pero ¿qué representa exactamente el eje y? El eje y en un gráfico de densidad es la función de densidad de probabilidad para la estimación de la densidad del núcleo. Sin embargo, debemos tener cuidado de especificar que se trata de una densidad de probabilidad y no de una probabilidad. La diferencia es que la densidad de probabilidad es la probabilidad por unidad en el eje x. Para convertirla en una probabilidad real, tenemos que encontrar el área bajo la curva para un intervalo específico en el eje x. Como se trata de una densidad de probabilidad y no de una probabilidad, el eje y puede tomar valores mayores que uno. El único requisito del gráfico de densidad es que el área total bajo la curva se integre en uno. Por lo general, tiendo a pensar en el eje y en un gráfico de densidad como un valor sólo para las comparaciones relativas entre las diferentes categorías.
Participaciones de densidad en Seaborn
Para hacer gráficos de densidad en seaborn, podemos utilizar la función distplot
o kdeplot
. Yo seguiré usando la función distplot
porque nos permite hacer múltiples distribuciones con una sola llamada a la función. Por ejemplo, podemos hacer un gráfico de densidad que muestre todos los retrasos de llegada sobre el histograma correspondiente:
# Density Plot and Histogram of all arrival delays
sns.distplot(flights, hist=True, kde=True,
bins=int(180/5), color = 'darkblue',
hist_kws={'edgecolor':'black'},
kde_kws={'linewidth': 4})
La curva muestra el gráfico de densidad que es esencialmente una versión suave del histograma. El eje y está en términos de densidad, y el histograma está normalizado por defecto para que tenga la misma escala y que el gráfico de densidad.
De forma análoga al binwidth de un histograma, un gráfico de densidad tiene un parámetro llamado ancho de banda que cambia los núcleos individuales y afecta significativamente al resultado final del gráfico. La librería de trazado elegirá un valor razonable del ancho de banda por nosotros (por defecto usando la estimación ‘scott’), y a diferencia del binwidth de un histograma, yo suelo usar el ancho de banda por defecto. Sin embargo, podemos ver el uso de diferentes anchos de banda para ver si hay una mejor opción. En el gráfico, ‘scott’ es el predeterminado, que parece la mejor opción.
Nota que un ancho de banda más amplio resulta en un mayor suavizado de la distribución. También vemos que aunque limitamos nuestros datos a -60 a 120 minutos, el gráfico de densidad se extiende más allá de estos límites. Este es un problema potencial con un gráfico de densidad: como calcula una distribución en cada punto de datos, puede generar datos que caen fuera de los límites de los datos originales. Esto puede significar que terminemos con valores imposibles en el eje x que nunca estuvieron presentes en los datos originales. Como nota, también podemos cambiar el kernel, que cambia la distribución dibujada en cada punto de datos y, por tanto, la distribución global. Sin embargo, para la mayoría de las aplicaciones, el kernel por defecto, el gaussiano, y la estimación de ancho de banda por defecto funcionan muy bien.
Solución #3 Gráfico de densidad
Ahora que entendemos cómo se hace un gráfico de densidad y lo que representa, veamos cómo puede resolver nuestro problema de visualizar los retrasos de llegada de múltiples aerolíneas. Para mostrar las distribuciones en el mismo gráfico, podemos iterar a través de las aerolíneas, cada vez llamando a distplot
con la estimación de la densidad del kernel establecida en True y el histograma establecido en False. El código para dibujar el gráfico de densidad con múltiples aerolíneas es el siguiente:
¡Finalmente, hemos llegado a una solución efectiva! Con el gráfico de densidad, podemos hacer fácilmente comparaciones entre aerolíneas porque el gráfico está menos desordenado. Ahora que por fin tenemos el gráfico que queremos, llegamos a la conclusión de que todas estas compañías aéreas tienen distribuciones de retrasos de llegada casi idénticas. Sin embargo, hay otras aerolíneas en el conjunto de datos, y podemos trazar una que es un poco diferente para ilustrar otro parámetro opcional para los gráficos de densidad, el sombreado del gráfico.
Participaciones de densidad sombreadas
Rellenar el gráfico de densidad puede ayudarnos a distinguir entre las distribuciones superpuestas. Aunque no siempre es un buen enfoque, puede ayudar a enfatizar la diferencia entre las distribuciones. Para sombrear los gráficos de densidad, pasamos shade = True
al argumento kde_kws
en la llamada distplot
.
sns.distplot(subset, hist = False, kde = True,
kde_kws = {'shade': True, 'linewidth': 3},
label = airline)
¡Si se sombrea o no el gráfico es, como otras opciones de trazado, una cuestión que depende del problema! Para este gráfico, creo que tiene sentido porque el sombreado nos ayuda a distinguir las parcelas en las regiones donde se superponen. Ahora, por fin tenemos información útil: Los vuelos de Alaska Airlines suelen llegar antes que los de United Airlines. La próxima vez que tengas la opción, ¡ya sabes qué aerolínea elegir!
Plots de alfombra
Si quieres mostrar cada valor de una distribución y no sólo la densidad suavizada, puedes añadir un plot de alfombra. Esto muestra cada punto de datos en el eje x, permitiéndonos visualizar todos los valores reales. El beneficio de usar distplot
de seaborn es que podemos añadir el gráfico de alfombra con una sola llamada de parámetro de rug = True
(con algún formato también).
Con muchos puntos de datos el rug plot puede saturarse, pero para algunos conjuntos de datos, puede ser útil ver cada punto de datos. La gráfica de la alfombra también nos permite ver cómo la gráfica de la densidad «crea» datos donde no existen, porque hace una distribución del núcleo en cada punto de datos. Estas distribuciones pueden filtrarse sobre el rango de los datos originales y dar la impresión de que Alaska Airlines tiene retrasos que son tanto más cortos como más largos que los realmente registrados. Tenemos que tener cuidado con este artefacto de los gráficos de densidad y señalarlo a los espectadores!
Conclusiones
Este post le ha dado, con suerte, una gama de opciones para visualizar una sola variable de una o múltiples categorías. Hay incluso más gráficos univariantes (de una sola variable) que podemos hacer, como los gráficos de densidad acumulativa empírica y los gráficos de cuantiles, pero por ahora lo dejaremos en histogramas y gráficos de densidad (¡y también en gráficos de alfombras!). No te preocupes si las opciones te parecen abrumadoras: con la práctica, elegir bien te resultará más fácil, y siempre puedes pedir ayuda si la necesitas. Además, a menudo no hay una elección óptima y la decisión «correcta» se reduce a las preferencias y a los objetivos de la visualización. Lo bueno es que, sea cual sea el gráfico que quieras hacer, ¡habrá una forma de hacerlo en Python! Las visualizaciones son un medio eficaz para comunicar los resultados, y conocer todas las opciones disponibles nos permite elegir la figura adecuada para nuestros datos.
Acepto comentarios y críticas constructivas y se me puede contactar en Twitter @koehrsen_will.