É sempre uma boa idéia examinar nossos dados antes de começarmos a plotar. Podemos ler os dados em um dataframe pandas e exibir as primeiras 10 linhas:
import pandas as pd# Read in data and examine first 10 rows
flights = pd.read_csv('data/formatted_flights.csv')
flights.head(10)
Os atrasos na chegada do vôo são em minutos e os valores negativos significam que o vôo foi antecipado (acontece que os vôos geralmente tendem a chegar mais cedo, mas nunca quando estamos neles!) Existem mais de 300.000 voos com um atraso mínimo de -60 minutos e um atraso máximo de 120 minutos. A outra coluna no quadro de dados é o nome da companhia aérea que podemos usar para comparações.
Uma ótima maneira de começar a explorar uma única variável é com o histograma. Um histograma divide a variável em caixas, conta os pontos de dados em cada caixa, e mostra as caixas no eixo x e as contagens no eixo y. No nosso caso, as caixas serão um intervalo de tempo que representa o atraso dos voos e a contagem será o número de voos que se enquadram nesse intervalo. A largura do binwidth é o parâmetro mais importante para um histograma e devemos sempre experimentar alguns valores diferentes de binwidth para selecionar o melhor para os nossos dados.
Para fazer um histograma básico em Python, podemos usar tanto matplotlib ou seaborn. O código abaixo mostra chamadas de função em ambas as bibliotecas que criam figuras equivalentes. Para as chamadas de gráficos, nós especificamos a largura do binwidth pelo número de bins. Para este gráfico, utilizarei caixas com 5 minutos de comprimento, o que significa que o número de caixas será o intervalo dos dados (de -60 a 120 minutos) dividido pela largura da caixa, 5 minutos ( bins = int(180/5)
).
A escolha da largura do binwidth afecta significativamente o gráfico resultante. Larguras de contentor mais pequenas podem tornar o gráfico desordenado, mas larguras de contentor maiores podem obscurecer nuances nos dados. O Matplotlib irá automaticamente escolher uma largura razoável para você, mas eu mesmo gosto de especificar a largura do binwidth depois de experimentar vários valores. Não existe uma verdadeira resposta certa ou errada, por isso tente algumas opções e veja qual funciona melhor para os seus dados em particular.
Quando os Histogramas Falham
Histogramas são uma óptima maneira de começar a explorar uma única variável retirada de uma categoria. Entretanto, quando queremos comparar as distribuições de uma variável em múltiplas categorias, os histogramas têm problemas com a legibilidade. Por exemplo, se quisermos comparar as distribuições de atraso de chegada entre companhias aéreas, uma abordagem que não funciona bem é criar histogramas para cada companhia aérea no mesmo gráfico:
(Note que o eixo y foi normalizado para contabilizar o diferente número de voos entre linhas aéreas. Para fazer isso, passe no argumento norm_hist = True
para a chamada de função sns.distplot
.)
Este gráfico não é muito útil! Todas as barras sobrepostas tornam quase impossível fazer comparações entre as companhias aéreas. Vamos ver algumas soluções possíveis para este problema comum.
Solução #1: Histogramas lado a lado
Em vez de sobrepor os histogramas das companhias aéreas, podemos colocá-los lado a lado. Para fazer isso, criamos uma lista dos atrasos de chegada para cada companhia aérea, e então passamos isso para a chamada de função plt.hist
como uma lista de listas. Temos de especificar cores diferentes para cada companhia aérea e uma etiqueta para que possamos distingui-las. O código, incluindo a criação das listas para cada companhia aérea está abaixo:
Por defeito, se passarmos numa lista de listas, o matplotlib irá colocar as barras lado a lado. Aqui, eu mudei a largura do binwidth para 15 minutos porque senão o gráfico está muito desordenado, mas mesmo com esta modificação, este não é um número efetivo. Há muita informação para processar de uma só vez, as barras não se alinham com as etiquetas, e ainda é difícil comparar as distribuições entre companhias aéreas. Quando fazemos um enredo, queremos que seja o mais fácil para o espectador compreender, e este número falha por esse critério! Vamos olhar para uma segunda solução potencial.
Solução #2: Barras Empilhadas
Em vez de plotar as barras para cada linha aérea lado a lado, podemos empilhá-las passando no parâmetro stacked = True
para a chamada do histograma:
# Stacked histogram with multiple airlines
plt.hist(, bins = int(180/15), stacked=True,
normed=True, color = colors, label=names)
Bem, isso definitivamente não é melhor! Aqui, cada companhia aérea é representada como uma secção do todo para cada contentor, mas é quase impossível fazer comparações. Por exemplo, com um atraso de -15 a 0 minutos, a United Air Lines ou a JetBlue Airlines tem um tamanho maior da barra? Eu não posso dizer e os telespectadores também não poderão. Eu geralmente não sou um proponente de barras empilhadas porque elas podem ser difíceis de interpretar (embora haja casos de uso, como quando se visualizam proporções). Ambas as soluções que tentamos usar histogramas não tiveram sucesso, e por isso é hora de passar para o gráfico de densidade.
Planos de densidade
Primeiro, o que é um gráfico de densidade? Um gráfico de densidade é uma versão suavizada e contínua de um histograma estimado a partir dos dados. A forma mais comum de estimativa é conhecida como estimativa de densidade de kernel. Neste método, uma curva contínua (o kernel) é desenhada em cada ponto de dados individual e todas essas curvas são então adicionadas para fazer uma única estimativa de densidade suave. O kernel mais frequentemente usado é um gaussiano (que produz uma curva de sino gaussiano em cada ponto de dados). Se, como eu, você acha essa descrição um pouco confusa, dê uma olhada no seguinte gráfico:
Aqui, cada pequena linha vertical preta no eixo x representa um ponto de dados. Os núcleos individuais (Gaussians neste exemplo) são mostrados desenhados em linhas vermelhas tracejadas acima de cada ponto. A curva azul sólida é criada pela soma dos Gaussians individuais e forma o gráfico de densidade total.
O eixo x é o valor da variável tal como num histograma, mas o que representa exactamente o eixo y? O eixo y em um gráfico de densidade é a função de densidade de probabilidade para a estimativa da densidade do kernel. No entanto, temos de ter cuidado para especificar que se trata de uma densidade de probabilidade e não de uma probabilidade. A diferença é que a densidade de probabilidade é a probabilidade por unidade no eixo x. Para converter para uma probabilidade real, precisamos encontrar a área sob a curva para um intervalo específico no eixo x. Um pouco confuso, porque esta é uma densidade de probabilidade e não uma probabilidade, o eixo y pode assumir valores superiores a um. O único requisito do gráfico de densidade é que a área total sob a curva se integre a um. Eu geralmente tendo a pensar no eixo y de um gráfico de densidade como um valor apenas para comparações relativas entre diferentes categorias.
Gráficos de densidade em Seaborn
Para fazer gráficos de densidade em Seaborn, podemos usar a função distplot
ou kdeplot
. Continuarei a usar a função distplot
porque ela nos permite fazer múltiplas distribuições com uma chamada de função. Por exemplo, podemos fazer um gráfico de densidade mostrando todos os atrasos de chegada no topo do histograma correspondente:
# 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})
A curva mostra a plotagem de densidade que é essencialmente uma versão suave do histograma. O eixo y é em termos de densidade, e o histograma é normalizado por padrão para que tenha a mesma escala y do gráfico de densidade.
Análogo à largura do binwidth de um histograma, um gráfico de densidade tem um parâmetro chamado largura de banda que muda os grãos individuais e afeta significativamente o resultado final do gráfico. A biblioteca de plotagem irá escolher um valor razoável da largura de banda para nós (por padrão usando a estimativa ‘scott’), e ao contrário da largura do binwidth de um histograma, eu normalmente uso a largura de banda padrão. No entanto, podemos olhar para usar diferentes larguras de banda para ver se há uma escolha melhor. No gráfico, ‘scott’ é o padrão, que parece ser a melhor opção.
Notem que uma largura de banda maior resulta em mais suavidade da distribuição. Vemos também que apesar de limitarmos nossos dados a -60 a 120 minutos, o gráfico de densidade se estende para além desses limites. Esta é uma questão potencial com um gráfico de densidade: como ele calcula uma distribuição em cada ponto de dados, pode gerar dados que estão fora dos limites dos dados originais. Isso pode significar que acabamos com valores impossíveis no eixo x que nunca estiveram presentes nos dados originais! Como nota, também podemos alterar o kernel, que altera a distribuição desenhada em cada ponto de dados e, portanto, a distribuição geral. Entretanto, para a maioria das aplicações, o kernel padrão, Gaussian, e a estimativa de largura de banda padrão funcionam muito bem.
Solução #3 Density Plot
Agora entendemos como um gráfico de densidade é feito e o que ele representa, vamos ver como ele pode resolver nosso problema de visualizar os atrasos de chegada de várias linhas aéreas. Para mostrar as distribuições no mesmo gráfico, podemos iterar através das linhas aéreas, cada vez chamando distplot
com a estimativa da densidade do kernel definida para True e o histograma definido para False. O código para desenhar o gráfico de densidade com múltiplas linhas aéreas está abaixo:
Finalmente, chegamos a uma solução eficaz! Com o gráfico de densidade, podemos facilmente fazer comparações entre companhias aéreas porque o gráfico é menos desordenado. Agora que finalmente temos a parcela que queremos, chegamos à conclusão de que todas estas companhias aéreas têm distribuições de atraso de chegada quase idênticas! Entretanto, existem outras companhias aéreas no conjunto de dados, e podemos plotar uma que é um pouco diferente para ilustrar outro parâmetro opcional para gráficos de densidade, sombreando o gráfico.
Pacotes de densidade sombreados
Preencher o gráfico de densidade pode nos ajudar a distinguir entre distribuições sobrepostas. Embora esta nem sempre seja uma boa abordagem, ela pode ajudar a enfatizar a diferença entre as distribuições. Para sombrear os gráficos de densidade, passamos em shade = True
para o argumento kde_kws
na chamada distplot
.
sns.distplot(subset, hist = False, kde = True,
kde_kws = {'shade': True, 'linewidth': 3},
label = airline)
Se sombrear ou não a trama é, como outras opções de trama, uma questão que depende do problema! Para este gráfico, acho que faz sentido porque o sombreamento nos ajuda a distinguir as parcelas nas regiões onde elas se sobrepõem. Agora, finalmente, temos alguma informação útil: Os voos da Alaska Airlines tendem a ser mais frequentes do que os da United Airlines. Da próxima vez que você tiver a opção, você sabe qual companhia aérea escolher!
Rug Plots
Se você quiser mostrar todos os valores em uma distribuição e não apenas a densidade suavizada, você pode adicionar um rug plot. Isto mostra cada ponto de dados no eixo x, permitindo-nos visualizar todos os valores reais. O benefício de usar o distplot
do Seaborn é que podemos adicionar o gráfico de rug plot com uma única chamada de parâmetro de rug = True
(com alguma formatação também).
Com muitos pontos de dados o rug plot pode ficar superlotado, mas para alguns conjuntos de dados, pode ser útil visualizar cada ponto de dados. O gráfico de tapete também nos permite ver como o gráfico de densidade “cria” dados onde não existe nenhum porque faz uma distribuição do kernel em cada ponto de dados. Essas distribuições podem vazar ao longo do intervalo dos dados originais e dar a impressão de que a Alaska Airlines tem atrasos que são tanto mais curtos quanto mais longos do que realmente registrados. Precisamos ter cuidado com este artefato de gráficos de densidade e apontar para os espectadores!
Conclusions
Esse post esperançosamente deu a você uma gama de opções para visualizar uma única variável de uma ou várias categorias. Há ainda mais gráficos univariados (uma única variável) que podemos fazer tais como gráficos empíricos de densidade cumulativa e gráficos quantile-quantile, mas por enquanto vamos deixá-los em histogramas e gráficos de densidade (e rug plots também!). Não se preocupe se as opções parecerem esmagadoras: com a prática, fazer uma boa escolha será mais fácil, e você pode sempre pedir ajuda se necessário. Além disso, muitas vezes não há uma escolha ótima e a decisão “certa” se resumirá à preferência e aos objetivos da visualização. O bom é que, não importa que trama você queira fazer, vai haver uma maneira de fazê-lo em Python! As visualizações são um meio eficaz para comunicar resultados, e conhecer todas as opções disponíveis nos permite escolher a figura certa para os nossos dados.
Aceito comentários e críticas construtivas e posso ser alcançado no Twitter @koehrsen_will.