Visualização de dados com Python

1 - Turbo introdução aos gráficos

Cleuton Sampaio, DataLearningHub Nesta lição veremos a parte básica de geração de gráficos, com formatação e posicionamento dos gráficos mais comuns.

Visualização de dados é um aspecto muito importante de um trabalho de Ciência de Dados, e nem todos conhecem os tipos de gráfico mais utilizados, além das técnicas e bibliotecas utilizadas para isto.

Quando se têm muitas variáveis, a visualização torna-se impossível. Nestes casos, é possível aplicar técnicas de redução de dimensionalidade, algo que está fora do escopo deste trabalho.

Barras, pizzas e linhas

Os gráficos mais comuns em pesquisas são estes: Barras, Pizzas e Linhas, e você pode criá-los facilmente com a Matplotlib. A primeira coisa a fazer é instalar a matplotlib:

pip install matplotlib

Se você estiver desenvolvendo dentro do Jupyter, então tem que usar um comando mágico para informar que o gráfico gerado deverá ser inserido no próprio notebook:

%matplotlib inline

Vamos mostrar um exemplo bem simples. Imaginemos dados coletados de temperaturas em 3 cidades diferentes. Temos listas contendo medições de temperaturas de cada cidade. Vamos usar Numpy para criar vetores e podermos trabalhar numericamente com eles:


In [1]:
import numpy as np
%matplotlib inline 
temp_cidade1 = np.array([33.15,32.08,32.10,33.25,33.01,33.05,32.00,31.10,32.27,33.81])
temp_cidade2 = np.array([35.17,36.23,35.22,34.33,35.78,36.31,36.03,36.23,36.35,35.25])
temp_cidade3 = np.array([22.17,23.25,24.22,22.31,23.18,23.31,24.11,23.53,24.38,21.25])

Vamos calcular a média de temperatura de cada cidade e utilizá-la para gerar um gráfico:


In [2]:
medias = [np.mean(temp_cidade1), np.mean(temp_cidade2), np.mean(temp_cidade3)] # Valores para o gráfico
nomes  = ['Cidade Um', 'Cidade Dois', 'Cidade Três'] # Nomes para o gráfico

Agora, vamos criar um gráfico de barras utilizando o módulo pyplot. Primeiramente, mostraremos um gráfico bem simples:


In [3]:
import matplotlib.pyplot as plt
fig, ax = plt.subplots() # Retorna a figura do gráfico e o objeto de elementos gráficos (axes)
ax.bar([0,1,2], medias, align='center') # Criamos um gráfico passando a posição dos elementos
ax.set_xticks([0,1,2]) # Indica a posição de cada rótulo no eixo X
ax.set_xticklabels(nomes) # Nomes das cidades
ax.set_title('Média das temperaturas') # Título do gráfico
ax.yaxis.grid(True) # Se é para mostrar a grade dos valores Y
plt.show() # Gera o gráfico


Gerar um gráfico de linhas pode ajudar a entender a evolução dos dados ao longo do tempo. Vamos gerar gráficos de linhas com as temperaturas das três cidades. Para começar, vamos gerar um gráfico de linha com uma só cidade:


In [4]:
fig, ax = plt.subplots()
ax.plot(temp_cidade1)
ax.set_title('Temperaturas da Cidade 1') # Título do gráfico
ax.yaxis.grid(True)
plt.show()


É muito comum compararmos variações de dados, e podemos fazer isso desenhando os gráficos lado a lado. Podem ser gráficos do mesmo tipo ou de diferentes tipos, além de poderem ser em várias linhas e colunas. Para isto, construímos uma instância da classe Figure separadamente, e cada instância de Axes também:


In [5]:
fig = plt.figure(figsize=(20, 5)) # Largura e altura da figura em polegadas
grade = fig.add_gridspec(1, 3) # Criamos uma grade com 1 linha e 3 colunas (pode ser com várias linhas também)
ax1 = fig.add_subplot(grade[0, 0]) # Primeira linha, primeira coluna
ax2 = fig.add_subplot(grade[0, 1]) # Primeira linha, segunda coluna
ax3 = fig.add_subplot(grade[0, 2]) # Primeira linha, terceira coluna
ax1.plot(temp_cidade1)
ax1.set_title('Temperaturas da Cidade 1') # Título do gráfico 1
ax1.yaxis.grid(True)
ax2.plot(temp_cidade2)
ax2.set_title('Temperaturas da Cidade 2') # Título do gráfico 2
ax2.yaxis.grid(True)
ax3.plot(temp_cidade3)
ax3.set_title('Temperaturas da Cidade 3') # Título do gráfico 3
ax3.yaxis.grid(True)
plt.show()


Outra maneira interessante de comparar séries de dados é criar um gráfico com múltiplas séries. Vejamos como fazer isso:


In [6]:
fig, ax = plt.subplots()
ax.plot(temp_cidade1)
ax.plot(temp_cidade2)
ax.plot(temp_cidade3)
ax.set_title('Temperaturas das Cidades 1,2 e 3') # Título do gráfico
ax.yaxis.grid(True)
plt.show()


Aqui, foram utilizadas linhas de cores diferentes, mas podemos mudar a legenda e a forma dos gráficos:


In [7]:
fig, ax = plt.subplots()
ax.plot(temp_cidade1, marker='^') # Marcadores em triângulos
ax.plot(temp_cidade2, marker='o') # Marcadores em círculos
ax.plot(temp_cidade3, marker='.') # Marcadores em pontos
ax.set_title('Temperaturas das Cidades 1,2 e 3') # Título do gráfico
ax.yaxis.grid(True)
plt.show()


Mas podemos dar maior destaque:


In [8]:
fig, ax = plt.subplots()
ax.plot(temp_cidade1, color="red",markerfacecolor='pink',  marker='^', linewidth=4, markersize=12, label='Cidade1')
ax.plot(temp_cidade2, color="skyblue",markerfacecolor='blue',  marker='o', linewidth=4, markersize=12, label='Cidade2')
ax.plot(temp_cidade3, color="green", linewidth=4, linestyle='dashed', label='Cidade3')
ax.set_title('Temperaturas das Cidades 1,2 e 3') # Título do gráfico
ax.yaxis.grid(True)
plt.legend()
plt.show()


As propriedades abaixo podem ser utilizadas para diferenciar as linhas:

  • color: Cor da linha
  • marker: Tipo de marcador
  • markerfacecolor: Cor de preenchimento do marcador
  • linewidth: Largura da linha
  • markersize: Tamanho do marcador
  • label: Rótulo da série de dados
  • linestyle: Estilo da linha de dados

E temos o método "legend()" que cria a legenda do gráfico

Mas, geralmente, quando estamos criando um modelo, usamos dataframes Pandas, com vários atributos. Dá para gerar gráfico diretamente a partir deles? Sim, é claro. Veremos um exemplo simples. Primeiramente, vamos importar o pandas e depois ler dois datasets CSV (Os datasets estão em: https://github.com/cleuton/datascience/tree/master/datasets


In [9]:
import pandas as pd
dolar = pd.read_csv('../datasets/dolar.csv')
desemprego = pd.read_csv('../datasets/desemprego.csv')

In [10]:
dolar.head()


Out[10]:
Periodo Dolar
0 2007.08 1.9652
1 2007.09 1.8988
2 2007.10 1.8002
3 2007.11 1.7691
4 2007.12 1.7852

Vamos analisar esse dataframe:


In [11]:
dolar.describe()


Out[11]:
Periodo Dolar
count 121.000000 121.000000
mean 2012.189091 96.254918
std 2.943821 415.140965
min 2007.080000 1.563100
25% 2010.020000 1.789014
50% 2012.080000 2.188057
75% 2015.020000 3.135572
max 2017.080000 2313.000000

Tem algo errado! Alguns valores estão asima de 1.000. Deve ser erro de dataset. Vamos acertar isso:


In [12]:
dolar.loc[dolar.Dolar > 1000, ['Dolar']] = dolar['Dolar'] / 1000

In [13]:
desemprego.head()


Out[13]:
Periodo Desemprego
0 2007.08 10.4
1 2007.09 10.5
2 2007.10 10.0
3 2007.11 10.0
4 2007.12 9.3

Podemos construir gráficos em linha de cada um deles usando o plot, mas, na verdade qualquer tipo de gráfico pode ser gerado com dataframes.


In [14]:
fig = plt.figure(figsize=(20, 5)) # Largura e altura da figura em polegadas
grade = fig.add_gridspec(1, 2) # Criamos uma grade com 1 linha e 3 colunas (pode ser com várias linhas também)
ax1 = fig.add_subplot(grade[0, 0]) # Primeira linha, primeira coluna
ax2 = fig.add_subplot(grade[0, 1]) # Primeira linha, segunda coluna
ax1.plot(dolar['Periodo'],dolar['Dolar']) # Potamos o valor do dólar por período
ax1.set_title('Evolução da cotação do Dólar') 
ax1.yaxis.grid(True)
ax2.plot(desemprego['Periodo'],desemprego['Desemprego'])
ax2.set_title('Evolução da taxa de desemprego') # Evolução da taxa de desemprego por período
ax2.yaxis.grid(True)


É... Uma das grandes vantagens da visualização, mesmo simples, é constatarmos uma correlação positiva entre o valor do dólar e o desemprego. Mas cuidado para não tomar isso como relação de causa e efeito! Há outros fatores que influenciam ambos! Para ilustrar isso, e mostrar como criar gráficos de dispersão (scatter) vamos plotar um gráfico com o dólar no eixo X e o desemprego no Y:


In [15]:
fig, ax = plt.subplots()
ax.scatter(dolar['Dolar'],desemprego['Desemprego'])
ax.set_xlabel("Valor do dólar")
ax.set_ylabel("Taxa de desemprego")
plt.show()


Podemos ver que até há alguma correlação aparente, mas em algum momento, depois do valor de R$ 3,00, a taxa de desemprego deu um salto. Isso prova que faltam variáveis explicativas no modelo.

Para encerrar essa lição, vejamos como gerar gráficos de pizza. Para começar, vamos "inventar" um dataframe de vendas mensais de produtos:


In [16]:
df_vendas = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))

In [17]:
df_vendas.head()


Out[17]:
A B C D
0 34 75 72 58
1 7 34 85 51
2 62 90 50 82
3 61 70 29 98
4 17 96 91 19

Bom, imaginemos que cada coluna representa as vendas de um dos produtos, e cada linha seja um dia. Vamos gerar um gráfico de pizza com as vendas.


In [18]:
list(df_vendas.columns)


Out[18]:
['A', 'B', 'C', 'D']

In [19]:
fig, ax = plt.subplots()
totais = df_vendas.sum()
ax.pie(totais, labels=list(df_vendas.columns),autopct='%1.1f%%')
ax.set_title('Vendas do período') 
plt.show()


E podemos "explodir" um ou mais pedaços. Por exemplo, vamos separar o pedaço maior, do produto "C":


In [20]:
listexplode = [0]*len(totais) # criamos uma lista contendo zeros: Um para cada fatia da pizza
imax = totais.idxmax() # Pegamos o índice do produto com maior quantidade de vendas
ix = list(df_vendas.columns).index(imax) # Agora, transformamos este índice em posição da lista
listexplode[ix]=0.1 # Modificamos a especificação de destaque da fatia com maior valor
fig, ax = plt.subplots()
ax.pie(totais, labels=list(df_vendas.columns),autopct='%1.1f%%', explode=listexplode)
ax.set_title('Vendas do período') 
plt.show()


Aqui usamos algumas funções interessantes. Como "totais" é uma série (pandas.Series) podemos obter o índice da coluna com maior valor com a função "ixmax()". Só que ele retornará o índice da coluna, que é o nome do produto. Precisamos da posição (de zero até tamanho-1). Então eu faço uma "maracutaia" com a lista de colunas do dataframe original, pegando a posição do produto. Depois, é só modificar a lista "listexplode" informando o quanto queremos destacar aquela determinada fatia (as outras ficam como zero).