Você está na página 1de 184

PYTHON

PARA
DATA SCIENCE
Apostila do Aluno
Adson Nogueira Alves - Analista Capacitação Técnica
Autor

Larissa Jessica Alves - Analista de suporte Pedagógico


Revisão da apostila

FIT Instituto de Tecnologia

Sorocaba, 2 de julho de 2022


Autor

Adson Nogueira Alves é técnico de


Informática (2007), Graduação em
Engenharia de Controle e Automação
(2016), Mestrado em Engenharia Elé-
trica (2021), atualmente é doutorando
em Ciências da Computação pela
Universidade Estadual de Campinas -
UNICAMP.
Áreas de estudo e atuação: Sistemas
Embarcados, Robótica, Inteligência
Artificial e Aprendizado de Máquinas,
Sistemas distribuidos, Automação,
Controle e Educação.
Pesquisas:
Doutorado: "Algoritmos de decisão de
alocação / offloading de processos para
aprendizado de máquina distribuído".
Mestrado: "Controle de um veículo
aéreo não tripulado (VANT) usando
abordagem de aprendizagem por re-
forço profundo (DRL) ".
Graduação: "Acionamento remoto de
baixo custo usando aplicativo multipla-
taforma".
Apresentação

Podemos dizer que Data Science ou Ciência de Dados é a combinação de métodos


científicos, matemáticos e estatísticos que através de uma programação especializada e
análises avançadas de Inteligência Artificial (IA) explora de forma profunda informações
geralmente ignoradas de uma grande base de dados, devido a sua complexidade de abs-
tração.

Um cientista de dados atua na preparação, análise e apresentação dos resultados,


afim de revelar padrões e permitir tirar conclusões que ajudem de forma significativa nas
tomadas de decisão de uma área de interesse.

A preparação envolve manipulação dos dados; A análise requer o uso de algoritmos


e modelos de IA; E os resultados são compartilhados através de ferramentas de visuali-
zação de dados que possibilitem ver os padrões e entender as tendências.

Algumas áreas de atuação:

Análise de crédito, Sistemas de detecção de objetos em tempo real, Mineração de


processos de negócios cognitivos, Classificação de perfil em tempo real, Segurança ur-
bana, Cuidado com a saúde e diversos outros.

Nesta apostila desenvolveremos nossas primeiras habilidades como Cientista de


Dados, atuando na preparação, análise e apresentação dos resultados. Essa apostila tem
o objetivo de apresentar um curso básico de Data Science, abordando estruturas e biblio-
tecas essenciais do tema.

Bons estudos!
Obs.: todas as imagens desta apostila são de autoria própria.
Sumário
1 Introdução 6
1.1 Visão Geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Ambiente de Desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Material complementar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2 NumPy 8
2.1 NumPy arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.1 Funções para criar arrays: arange(), zeros(), ones(), linspace()
e eye() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1.2 Módulo random . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.3 Atributos e métodos de arrays . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Exercícios Extras I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3 Exercicios Extras I Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4 Seleção e indexação de numpy arrays . . . . . . . . . . . . . . . . . . . . . . 19
2.4.1 Seleção por chaves . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.2 Broadcasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.3 Indexação de arrays 2D (matrizes) . . . . . . . . . . . . . . . . . . . . 21
2.4.4 Seleção por expressão lógica . . . . . . . . . . . . . . . . . . . . . . . 23
2.5 Exercícios Extras II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.6 Exercícios Extras II Resolvidos . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.7 Operações em NumPy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.7.1 Universal Array Functions . . . . . . . . . . . . . . . . . . . . . . . . 30

3 Pandas 32
3.1 Séries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.2 Pandas DataFrames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2.1 Seleção e indexação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.2.2 Lidando com informações faltantes . . . . . . . . . . . . . . . . . . . 46
3.2.3 Agrupamento de dados por groupby . . . . . . . . . . . . . . . . . . . 48
3.2.4 merge, join e concatenate DataFrames . . . . . . . . . . . . . . . . . 51
3.2.5 Operações em DataFrames . . . . . . . . . . . . . . . . . . . . . . . . 58
3.2.6 Entrada e saída de dados . . . . . . . . . . . . . . . . . . . . . . . . . 62

4 Avaliação 1 - Numpy e Pandas 65


4.1 Exercício Avaliativo NumPy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
5

4.2 Exercícios Avaliativos Pandas . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

5 Matplotlib 70
5.1 Opções avançadas do Matplotlib . . . . . . . . . . . . . . . . . . . . . . . . . 86

6 Seaborn 106
6.1 Gráficos de distribuições: distplot(), jointplot(), pairplot() e rugplot()106
6.2 Gráficos categóricos: barplot(), countplot(), boxplot(), violinplot(),
stripplot(), swarmplot() e catplot() . . . . . . . . . . . . . . . . . . . . . 115
6.3 Combinando gráficos categóricos . . . . . . . . . . . . . . . . . . . . . . . . . 129
6.4 Gráficos de matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
6.4.1 Heatmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
6.5 Grids: PairGrid(), pairplot(), FacetGrid() e JointGrid() . . . . . . . . . 135
6.6 Regressão: lmplot() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
6.7 Formatação, estilos e cores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
6.7.1 Marcadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
6.7.2 Inserindo uma grade . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
6.7.3 Proporção e tamanho . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

7 Visualização com pandas 157


7.1 Tipos de gráficos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
7.2 Exercícios Extras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
7.3 Exercícios Extras Resolvido . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

8 Avaliação 2 - Matplotlib e Seaborn 177


8.1 Exercícios Avaliativo Matplotlib . . . . . . . . . . . . . . . . . . . . . . . . . . 177
8.2 Exercícios Avaliativo Seaborn . . . . . . . . . . . . . . . . . . . . . . . . . . . 178

9 Categoria das Notas 179

10 Conclusão 180

11 Controle de revisão do documento 182


6

1 Introdução

1.1 Visão Geral

Algumas definições importantes:

• Linguagem de programação (LP): uma linguagem artificial usada para controlar o com-
portamento de um sistema ou máquina. Assim como a linguagem humana são definidos
através de regra sintática e semântica, para determinar estrutura e significado, respectiva-
mente.

• Framework ou Estrutura: tem objetivo de simplificar e acelerar o desenvolvimento,


reunindo ferramentas ou estruturas usadas para resolver rotinas e tarefas respectivas.

• Libraries ou Biblioteca: é uma coleção de códigos pré-escritos que são usados para
otimizar a programação.

• Função:é um módulo recursivo do código, responsável por uma tarefa específica.

• API’s: interface que estabelece uma comunicação viavél entre dois sistemas ou plataformas,
agregando funções diversificadas sem precisar saber como elas foram implementadas.

• Documentação: geralmente acompanha uma Framework ou Libraries, afim de comple-


mentar para torná-lo mais compreensível para quem for analisar os detalhes de implemen-
tação.

Entre as linguagens de programação disponíveis, Python é a mais tradicional para trabalhar


com grande volume de dados. Segundo o Tiobe, empresa responsável por medir a qualidade de
software, Python é a segunda linguagem mais utilizada, representando 11, 67% do total [11].

Existem diversas frameworks e Libraries utilizadas no amplo cenário de Data Science, a


Tabela 1 lista algumas que são bastante citadas:

Desta maneira, será abordado em nivel basico ferramentas para preparação, análise e apre-
sentação dos dados, utilizando a linguagem de programação Python e Frameworks/Libraries
como NumPy, Pandas, Matplotlib e Seaborn.

1.2 Ambiente de Desenvolvimento


Utilizaremos a ferramenta Colaboratory [2], ou apenas Colab, durante todo o curso. É uma
ferramenta desenvolvida pela Google que permite hospedar na nuvem, códigos de Aprendizado
de Máquina e Inteligência Artificial de forma gratuita. Com ele é possível compilar linhas
7

Tabela 1: Tabela de Frameworks and Libraries para Data Science.

Item Label
1 TensorFlow
2 Keras
3 Scikit-learn
4 Matplotlib
5 Pandas
6 NumPy
7 Pytorch
8 Seaborn
9 Shogun
10 AWS Deep Learning AMI

de código de forma independente, permitindo visualizar os resultados linha a linha, além da


possibilidade de adicionar textos ao código de forma limpa.

Outras vantagens como não ser necessário configurar o ambiente, acesso livre a GPUs (Uni-
dades de Processamento Gráfico) e TPU’s (Unidade de processamento de Tensor) responsáveis
por aumentar a velocidade de processamento gráfico e de aprendizagem profunda também são
disponibilizados.

Segunda a Google, o Colab foi desenvolvido para facilitar o trabalho de Estudantes,


Cientistas de dados e Pesquisadores de Inteligência Artificial.

1.3 Material complementar


Ao final do curso, sugiro fortemente que explore alguns links um pouco mais e amplie o seu
conhecimento:

• Programiz [9]

• Udemy [12]

• W3schools [13]

• Medium [6]

• Anaconda [1]

• Kaggle [3]
8

2 NumPy

Segundo a documentação [7], NumPy é um pacote para computação científica em Python.


Possuindo objetos array multidimensional e uma variedade de rotinas que possibilitam operações
rápidas em matrizes, incluindo matemática, lógica, manipulação de formas, classificação, seleção,
I/O, Transformações discreta de Fourier, álgebra linear básica, operações estatísticas básicas,
simulação aleatória e muito mais. A base do NumPy são objetos do tipo ndarray, que trabalham
com dados multidimensionais.
Algumas diferenças importantes entre o NumPy array e Python array padrão, são:

• O tamanho do ndarray tem um tamanho fixo na criação, alterar o seu tamanho significa
apagar o original e criar um novo ndarray, evitando alocação de memoria desnecessária.

• Para Numpy array é requerido que se tenha o mesmo tipo de dados. Com exceção quando
trabalhamos com arrays de tipo objeto.

• Numpy facilita operações matemáticas além de outros tipos de operações para grande
volume de dados.

• O Python array começa a se tornar ineficiente para tratar o crescente numero de dados
matemáticos e científicos.

Como iremos utilizar a ferramenta Colab não é necessário realizar pré instalação da biblio-
teca, porém caso queira utilizar o NumPy fora desse ambiente será necessário a instalação através
de uma instrução bastante simples no Prompt de Comando (CMD) do seu sistema operacional,
basta utilizar um dos comandos abaixo:

• conda install numpy


Caso utilize o Anaconda [1]
• pip install numpy
Caso contrário

Para utilizar o NumPy, é necessário realizar a importação da biblioteca dentro do ambiente


de programação Colab, denominado como Notebook. Digite a seguinte instrução:

[1]: import numpy as np # abreviação de numpy foi convencionado como np

2.1 NumPy arrays


Numpy arrays são muito poderosos do ponto de vista computacional. Para criar um numpy
array podemos declarar uma lista e utilizá-la como parâmetro para a função array(). Note que
9

podemos ter arrays dentro de arrays, definindo assim uma matriz.

[2]: my_list = [1,2,3]


my_list

[2]: [1, 2, 3]

[3]: np.array(my_list)

[3]: array([1, 2, 3])

[4]: my_matrix = [[1,2,3],[4,5,6],[7,8,9]]


print(my_matrix)

[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

[5]: x = np.array(my_matrix)
print(x)

[[1 2 3]
[4 5 6]
[7 8 9]]

2.1.1 Funções para criar arrays: arange(), zeros(), ones(), linspace() e eye()

Podemos criar arrays específicas através de uma série de funções disponíveis na documentação
[7].

• arange() fornece uma sequência de números entre um valor inicial, um valor final e opci-
onalmente com um passo definido.

a= np.arange(inicio, fim, passo)

[6]: ?np.arange

[7]: np.arange(0,10)

[7]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

[8]: np.arange(0,11,2)

[8]: array([ 0, 2, 4, 6, 8, 10])


10

• zeros() e ones() são funções que criam arrays contendo apenas valores iguais a 0 (zero)
ou 1 (um), respectivamente. Precisamos passar para a função o tamanho do array, ou uma
tupla com a extensão em cada dimensão.

a = np.zeros((dim1, dim2, dim3, ...))


b = np.ones((dim1, dim2, dim3, ...))

[9]: np.zeros(3)

[9]: array([0., 0., 0.])

[10]: np.zeros((5,5))

[10]: array([[0., 0., 0., 0., 0.],


[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])

[11]: np.ones(3)

[11]: array([1., 1., 1.])

[12]: np.ones((3,3))

[12]: array([[1., 1., 1.],


[1., 1., 1.],
[1., 1., 1.]])

• linspace() gera um número de valores igualmente espaçados em um determinado inter-


valo. A sintaxe é:

a = np.linspace(inicio, fim, quantidade)

[13]: np.linspace(0,10,3)

[13]: array([ 0., 5., 10.])

[14]: np.linspace(0,10,50)
11

[14]: array([ 0. , 0.20408163, 0.40816327, 0.6122449 , 0.81632653,


1.02040816, 1.2244898 , 1.42857143, 1.63265306, 1.83673469,
2.04081633, 2.24489796, 2.44897959, 2.65306122, 2.85714286,
3.06122449, 3.26530612, 3.46938776, 3.67346939, 3.87755102,
4.08163265, 4.28571429, 4.48979592, 4.69387755, 4.89795918,
5.10204082, 5.30612245, 5.51020408, 5.71428571, 5.91836735,
6.12244898, 6.32653061, 6.53061224, 6.73469388, 6.93877551,
7.14285714, 7.34693878, 7.55102041, 7.75510204, 7.95918367,
8.16326531, 8.36734694, 8.57142857, 8.7755102 , 8.97959184,
9.18367347, 9.3877551 , 9.59183673, 9.79591837, 10. ])

• eye() retorna a matriz identidade, ou seja, a matriz quadrada onde todas as entradas são
zero com exceção dos elementos da diagonal que são iguais a 1.

a = np.eye(dimensão)

[15]: np.eye(4)

[15]: array([[1., 0., 0., 0.],


[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])

2.1.2 Módulo random

Neste módulo da biblioteca é possível gerar números randômicos ou aleatórios. Diversas funções
estão disponíveis:

• rand() fornece array populado com números aleatórios com uma distrbuição uniforme entre
[0, 1[ (incluindo zero e excluindo o 1). A sintaxe é:

a = np.random.rand(dim1, dim2, dim3, ...)

onde dim1, dim2, etc são as extensões das dimensões do array retornado.

[16]: np.random.rand(2)

[16]: array([0.44044892, 0.13166482])

[17]: np.random.rand(5,5)
12

[17]: array([[0.73767662, 0.36388773, 0.71340131, 0.07119516, 0.32426023],


[0.53584544, 0.17811678, 0.09953834, 0.75068116, 0.76562695],
[0.06123676, 0.83146727, 0.09678223, 0.01918742, 0.1265345 ],
[0.11064762, 0.69620762, 0.5826046 , 0.57157172, 0.0607168 ],
[0.663342 , 0.9522166 , 0.94311743, 0.31525781, 0.44731857]])

• randn() retorna uma amostra da distribuição normal padrão (gaussiana com média µ = 0
e variância σ = 1). A sintaxe é análoga à do rand():

a = np.random.randn(dim1, dim2, dim3, ...)

[18]: np.random.randn(2)

[18]: array([ 0.44990648, -0.24882174])

[19]: np.random.randn(7,5)

[19]: array([[-0.13127119, 0.45188661, 0.49104535, -1.81414184, 0.32893752],


[-0.44440966, -0.95816352, 0.17870062, -0.09719435, -0.94936321],
[-0.62319395, 0.39299776, 1.49643061, -0.82349221, 0.15691528],
[ 0.73961328, 0.04520582, 0.32173792, -0.43964299, 2.06867207],
[ 0.10675037, 0.23158769, 1.4189436 , 1.32742904, 0.96287861],
[ 1.25430581, -1.23904911, -0.84627082, -0.19364229, 1.27493693],
[ 0.73647505, 0.76277838, -1.06358633, -1.10809755, -0.0595814 ]])

• randint() retorna um array de números inteiros aleatórios no intervalo [ a, b[ e dimensão


(dim1, dim2, ...):

a = np.random.randint(a, b, (dim1, dim2, ...))

[20]: np.random.randint(1,100)

[20]: 25

[21]: np.random.randint(1,100,10)

[21]: array([48, 16, 40, 6, 84, 89, 74, 53, 97, 22])

• seed() inicializa o gerador de números aleatórios. Isto é uma boa prática quando traba-
lhamos com números aleatórios, pois torna o resultado determinístico, uma vez que para
um mesmo parâmetro, os mesmos números aleatórios são gerados.
13

np.random.seed(semente)

[22]: np.random.seed(12)
x = np.random.randint(1, 20)
print(x)
x = np.random.randint(1, 20)
print(x)
np.random.seed(12)
x = np.random.randint(1, 20)
print(x)

12
7
12

2.1.3 Atributos e métodos de arrays

São funções e atributos intrínsicos dos arrays, considerados dados internos. Usando os arrays a
e b para exemplificar, temos:

[23]: a = np.arange(25)
b = np.random.randint(0,50,10)

[24]: a

[24]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,


17, 18, 19, 20, 21, 22, 23, 24])

[25]: b

[25]: array([27, 6, 49, 2, 3, 3, 12, 48, 22, 49])

• reshape() altera as dimensões do array, com a sintaxe:

a.reshape((dim1, dim2, dim3, ...))

Desde que as dimensões inicias e finais sejam compatíveis.

[26]: a.reshape(5,5)
14

[26]: array([[ 0, 1, 2, 3, 4],


[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])

• max(), min(), argmax() e argmin() retornam os valores máximo, mínimo, o índice do


valor máximo e índice do valor mínimo de um array, respectivamete.

[27]: b.max()

[27]: 49

[28]: b.argmax()

[28]: 2

[29]: b.min()

[29]: 2

[30]: b.argmin()

[30]: 3

• shape é uma tupla que armazena as dimensões do array

[31]: # Vector
a.shape

[31]: (25,)

[32]: a.reshape(1,25)

[32]: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,


16, 17, 18, 19, 20, 21, 22, 23, 24]])

[33]: a.reshape(1,25).shape

[33]: (1, 25)

[34]: a.reshape(25,1)
15

[34]: array([[ 0],


[ 1],
[ 2],
[ 3],
[ 4],
[ 5],
[ 6],
[ 7],
[ 8],
[ 9],
[10],
[11],
[12],
[13],
[14],
[15],
[16],
[17],
[18],
[19],
[20],
[21],
[22],
[23],
[24]])

[35]: a.reshape(25,1).shape

[35]: (25, 1)

• dtype armazena o tipo de variável que está guardada no array

[36]: b.dtype

[36]: dtype('int32')

[37]: a = np.linspace(0, 1, 10)


a
16

[37]: array([0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,


0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])

[38]: a.dtype

[38]: dtype('float64')
17

2.2 Exercícios Extras I


(Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta).

1. Construa um vetor com 15 elementos de numeros aleatórios inteiros, variando de 0 até


10000.

[ ]:

2. Obtenha seus valores máximo, mínimo, assim com os respectivos índices.

[ ]:

3. Transforme esse vetor em uma matrix 3 × 5.

[ ]:
18

2.3 Exercicios Extras I Resolvidos


1. Construa um vetor com 15 elementos de numeros aleatórios inteiros, variando de 0 até
10000. Gabarito:

[48]: x = np.random.randint(0, 10000, 15)


x

[48]: array([9138, 7212, 8170, 1588, 9603, 9216, 4279, 2581, 8341, 3785, 5606,
8248, 4802, 4270, 1054])

2. Obtenha seus valores máximo, mínimo, assim como os respectivos índices.


Gabarito:

[49]: maximo = x.max()


maximo

[49]: 9603

[50]: i_maximo = x.argmax()


i_maximo

[50]: 4

[51]: minimo = x.min()


minimo

[51]: 1054

[52]: i_minimo = x.argmin()


i_minimo

[52]: 14

3. Transforme esse vetor em uma matrix 3 × 5

[53]: x.reshape(3,5)

[53]: array([[9138, 7212, 8170, 1588, 9603],


[9216, 4279, 2581, 8341, 3785],
[5606, 8248, 4802, 4270, 1054]])
19

2.4 Seleção e indexação de numpy arrays


Nesta subseção vamos entender como selecionar um ou mais elementos de um array e alterá-los.
Assim, vamos importar o NumPy e criar um array:

[1]: import numpy as np

[2]: arr = np.arange(0,11)

[3]: arr

[3]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

2.4.1 Seleção por chaves

Este é o método mais básico de seleção de elementos, sendo exatamente igual ao que vimos
anteriormente. Podemos também selecionar elementos com índices negativos, o que significa
percorrer o array de trás para frente.

[4]: arr[5]

[4]: 5

[5]: arr[2:5]

[5]: array([2, 3, 4])

[6]: arr[-1]

[6]: 10

2.4.2 Broadcasting

Uma vantagem significativa em utilizar NumPy está na utilização de broadcasting. O broadcasting


realiza atribuição de valores em múltiplas entradas do array de uma só vez. Veja o exemplo:

[7]: #Alterar valor de um intervalo


arr[0:5] = 100

arr
20

[7]: array([100, 100, 100, 100, 100, 5, 6, 7, 8, 9, 10])

[8]: arr = np.arange(0,11)

arr

[8]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

[9]: arr2 = arr[0:6]

arr2

[9]: array([0, 1, 2, 3, 4, 5])

[10]: arr2[:] = 99

arr2

[10]: array([99, 99, 99, 99, 99, 99])

Este tipo de alteração impacta também o array original, uma vez que ambos compartilham
o mesmo endereço de memória, exatamente como no caso das listas.

[11]: arr

[11]: array([99, 99, 99, 99, 99, 99, 6, 7, 8, 9, 10])

Para evitar estes problemas, temos que utilizar o método copy() e gerar um novo espaço
de memória.

[12]: arr_copy = arr.copy()

print(arr_copy)
print(arr)

arr[2:4] = -1

print(arr_copy)
print(arr)
21

[99 99 99 99 99 99 6 7 8 9 10]
[99 99 99 99 99 99 6 7 8 9 10]
[99 99 99 99 99 99 6 7 8 9 10]
[99 99 -1 -1 99 99 6 7 8 9 10]

2.4.3 Indexação de arrays 2D (matrizes)

Para recuperar um único registro, precisamos de dois índices, um para linha e outro para coluna.
Isto pode ser feito de duas maneiras:

x = arr_2d[linha][coluna]
y = arr_2d[linha,coluna]

Podemos também recuperar linhas ou colunas separadamente:

l = arr_2d[linha]
l = arr_2d[linha,:]
c = arr_2d[:,coluna]

[13]: arr_2d = np.array(([5,10,15],[20,25,30],[35,40,45]))

arr_2d

[13]: array([[ 5, 10, 15],


[20, 25, 30],
[35, 40, 45]])

[14]: #selecionando linha


arr_2d[1]

[14]: array([20, 25, 30])

[15]: # selecionando um elemento (coluna) de uma linha

arr_2d[1][0]

[15]: 20

[16]: arr_2d[1,0]

[16]: 20
22

Podemos fazer Slicing em diferentes dimensões,

s = arr_2d[linha_inicio:linha_fim, coluna_inicio:coluna_fim]

[17]: print(arr_2d, '\n')

print(arr_2d[:2,1:])

[[ 5 10 15]
[20 25 30]
[35 40 45]]

[[10 15]
[25 30]]

[18]: #linha 2
arr_2d[2]

[18]: array([35, 40, 45])

[19]: #linha 2
arr_2d[2,:]

[19]: array([35, 40, 45])

[20]: # criar matriz com zeros


arr2d = np.zeros((10,10))

# faz broadcast por linha


for i in range(len(arr2d)):
arr2d[i] = i

arr2d

[20]: array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[2., 2., 2., 2., 2., 2., 2., 2., 2., 2.],
[3., 3., 3., 3., 3., 3., 3., 3., 3., 3.],
[4., 4., 4., 4., 4., 4., 4., 4., 4., 4.],
23

[5., 5., 5., 5., 5., 5., 5., 5., 5., 5.],
[6., 6., 6., 6., 6., 6., 6., 6., 6., 6.],
[7., 7., 7., 7., 7., 7., 7., 7., 7., 7.],
[8., 8., 8., 8., 8., 8., 8., 8., 8., 8.],
[9., 9., 9., 9., 9., 9., 9., 9., 9., 9.]])

[21]: # indexação em ordem qualquer


arr2d[[2,4,6,8]]

[21]: array([[2., 2., 2., 2., 2., 2., 2., 2., 2., 2.],
[4., 4., 4., 4., 4., 4., 4., 4., 4., 4.],
[6., 6., 6., 6., 6., 6., 6., 6., 6., 6.],
[8., 8., 8., 8., 8., 8., 8., 8., 8., 8.]])

[22]: # indexação em ordem qualquer


arr2d[[6,4,2,7]]

[22]: array([[6., 6., 6., 6., 6., 6., 6., 6., 6., 6.],
[4., 4., 4., 4., 4., 4., 4., 4., 4., 4.],
[2., 2., 2., 2., 2., 2., 2., 2., 2., 2.],
[7., 7., 7., 7., 7., 7., 7., 7., 7., 7.]])

2.4.4 Seleção por expressão lógica

Podemos obter um array de valores booleanos ao utilizar uma expressão lógica envolvendo o array.
Com isto, podemos selecionar apenas os elementos do array original que satisfazem uma certa
condição:

[23]: arr = np.arange(1,11)


arr

[23]: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

[24]: bool_arr = arr > 4

[25]: bool_arr

[25]: array([False, False, False, False, True, True, True, True, True,
True])
24

[26]: arr[bool_arr]

[26]: array([ 5, 6, 7, 8, 9, 10])

[27]: arr[arr > 2]

[27]: array([ 3, 4, 5, 6, 7, 8, 9, 10])

[28]: x = 2
arr[arr > x]

[28]: array([ 3, 4, 5, 6, 7, 8, 9, 10])


25

2.5 Exercícios Extras II


(Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta).

1. Dado o array abaixo:

arr = np.arange(0,50)

• Selecione somente os números impares.

[ ]:

• Troque todos o números ímpares por -1.

[ ]:
26

2.6 Exercícios Extras II Resolvidos


1. Dado o array abaixo:
Gabarito:

arr = np.arange(0,50)

[47]: arr = np.arange(0, 50)


arr

[47]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,


17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49])

• Selecione somente os números impares

[48]: arr[arr%2 == 1]

[48]: array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33,
35, 37, 39, 41, 43, 45, 47, 49])

• Troque todos o números ímpares por -1

[50]: arr[arr%2 == 1] = -1
arr

[50]: array([ 0, -1, 2, -1, 4, -1, 6, -1, 8, -1, 10, -1, 12, -1, 14, -1, 16,
-1, 18, -1, 20, -1, 22, -1, 24, -1, 26, -1, 28, -1, 30, -1, 32, -1,
34, -1, 36, -1, 38, -1, 40, -1, 42, -1, 44, -1, 46, -1, 48, -1])
27

2.7 Operações em NumPy


A facilidade de realizar operações com NumPy é um diferencial. Operações aritméticas são
adaptadas para os operandos envolvidos, sendo que o broadcast é automático.

[1]: import numpy as np


arr = np.arange(0,10)
print(arr)

[0 1 2 3 4 5 6 7 8 9]

[2]: arr + arr

[2]: array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])

[3]: arr * arr

[3]: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])

[4]: arr - arr

[4]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

[5]: # A divisão por zero gera apenas um aviso de runtime e seu resultado é um␣
,→nan

arr/arr

C:\Users\jagapadi\AppData\Local\Continuum\anaconda3\envs\jupyter\lib\site-
packages\ipykernel_launcher.py:2: RuntimeWarning: invalid value encountered␣
,→in

true_divide

[5]: array([nan, 1., 1., 1., 1., 1., 1., 1., 1., 1.])

[6]: # outra divisão por zero, que desta vez retorna o valor de infinito
1/arr

C:\Users\jagapadi\AppData\Local\Continuum\anaconda3\envs\jupyter\lib\site-
packages\ipykernel_launcher.py:2: RuntimeWarning: divide by zero␣
,→encountered in
28

true_divide

[6]: array([ inf, 1. , 0.5 , 0.33333333, 0.25 ,


0.2 , 0.16666667, 0.14285714, 0.125 , 0.11111111])

[7]: arr**2

[7]: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81], dtype=int32)

Alguns métodos úteis de arrays:

• array.sum() retorna a soma dos elementos.


• array.cumsum() retorna a soma cumulativa.
• array.mean() fornece a média.
• array.std() fornece o desvio padrão.

[8]: arr.sum()

[8]: 45

[9]: x = np.arange(0,25).reshape(5,5)

print(x)

print('\nsoma por coluna = ', x.sum(axis=0))

print('\nsoma por linha = ',x.sum(axis=1))

[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]]

soma por coluna = [50 55 60 65 70]

soma por linha = [ 10 35 60 85 110]

[10]: arr.cumsum()
29

[10]: array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45], dtype=int32)

[11]: print(x.cumsum())

print('\nsoma cumulativa por coluna = \n', x.cumsum(axis=0))

print('\nsoma cumulativa por linha = \n', x.cumsum(axis=1))

[ 0 1 3 6 10 15 21 28 36 45 55 66 78 91 105 120 136 153


171 190 210 231 253 276 300]

soma cumulativa por coluna =


[[ 0 1 2 3 4]
[ 5 7 9 11 13]
[15 18 21 24 27]
[30 34 38 42 46]
[50 55 60 65 70]]

soma cumulativa por linha =


[[ 0 1 3 6 10]
[ 5 11 18 26 35]
[ 10 21 33 46 60]
[ 15 31 48 66 85]
[ 20 41 63 86 110]]

[12]: print('média =', x.mean())

print('\nmédia por coluna = ', x.mean(axis=0))

print('\nmédia por linha = ', x.mean(axis=1))

média = 12.0

média por coluna = [10. 11. 12. 13. 14.]

média por linha = [ 2. 7. 12. 17. 22.]


30

[13]: print('desvio padrão =', x.std())

print('\ndesvio padrão por coluna = ', x.std(axis=0))

print('\ndesvio padrão por linha = ', x.std(axis=1))

desvio padrão = 7.211102550927978

desvio padrão por coluna = [7.07106781 7.07106781 7.07106781 7.07106781


7.07106781]

desvio padrão por linha = [1.41421356 1.41421356 1.41421356 1.41421356


1.41421356]

2.7.1 Universal Array Functions

As Universal Array Functions ou ufuncs são funções especiais que agem em todos os elementos
de um array.

[14]: # raiz quadrada


np.sqrt(arr)

[14]: array([0. , 1. , 1.41421356, 1.73205081, 2. ,


2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])

[15]: #exponencial (e^x)


np.exp(arr)

[15]: array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,


5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
2.98095799e+03, 8.10308393e+03])

[16]: np.max(arr) # mesmo resultado que arr.max()

[16]: 9

[17]: np.sin(arr) # função seno


31

[17]: array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 ,


-0.95892427, -0.2794155 , 0.6569866 , 0.98935825, 0.41211849])

[18]: np.log(arr) # logaritmo natural (base e)

C:\Users\jagapadi\AppData\Local\Continuum\anaconda3\envs\jupyter\lib\site-
packages\ipykernel_launcher.py:1: RuntimeWarning: divide by zero␣
,→encountered in

log
"""Entry point for launching an IPython kernel.

[18]: array([ -inf, 0. , 0.69314718, 1.09861229, 1.38629436,


1.60943791, 1.79175947, 1.94591015, 2.07944154, 2.19722458])
32

3 Pandas

Pandas é uma biblioteca de leitura, escrita e manipulação de dados em formatos de séries


e/ou tabelas. Sua documentação está disponível em [4].

3.1 Séries

Uma série é muito semelhante a uma matriz NumPy (Pandas series foi construída sobre
o objeto da matriz NumPy). O que diferencia a matriz NumPy de uma série é que esta pode
ser indexada por um rótulo, em vez de apenas um índice inteiro. Além disso, a série não precisa
necessariamente conter dados numéricos, mas sim qualquer objeto Python arbitrário.

[1]: import numpy as np


import pandas as pd # abreviação de pandas foi convencionado como pd

Para criar uma série, pode-se converter uma lista, numpy array, ou dicionário em pandas
em séries:

[2]: labels = ['a', 'b', 'c']


my_list = [10, 20, 30]
arr = np.array([1.1, 1.2, 1.3])
dic = {'x' : 10, 'y' : 20, 'z' : 30}

[3]: pd.Series(data=my_list)

[3]: 0 10
1 20
2 30
dtype: int64

[4]: pd.Series(data=my_list, index=labels)

[4]: a 10
b 20
c 30
dtype: int64

[5]: pd.Series(my_list, labels)


33

[5]: a 10
b 20
c 30
dtype: int64

[6]: pd.Series(arr)

[6]: 0 1.1
1 1.2
2 1.3
dtype: float64

[7]: pd.Series(arr, labels)

[7]: a 1.1
b 1.2
c 1.3
dtype: float64

** Dictionary**

[8]: pd.Series(dic)

[8]: x 10
y 20
z 30
dtype: int64

Uma pandas Series pode guardar qualquer tipo de variável.

[9]: pd.Series(data=labels)

[9]: 0 a
1 b
2 c
dtype: object

[10]: # até mesmo funções


pd.Series([sum, print, len])
34

[10]: 0 <built-in function sum>


1 <built-in function print>
2 <built-in function len>
dtype: object

Podemos passar explicitamente para o construtor da série quem serão os índices, que
podemo ser utilizados para indexação.

[11]: ser1 = pd.Series([1, 2, 3, 4], index=['USA', 'Germany', 'Brazil',␣


,→'Japan'])

[12]: ser1

[12]: USA 1
Germany 2
Brazil 3
Japan 4
dtype: int64

[13]: ser2 = pd.Series([1, 2, 5, 4], index=['USA', 'Germany', 'Italy', 'Japan'])

[14]: ser2

[14]: USA 1
Germany 2
Italy 5
Japan 4
dtype: int64

[15]: ser1['USA']

[15]: 1

As operações são realizadas obedecendo-se a ordem dos índices:

[16]: ser1 + ser2

[16]: Brazil NaN


Germany 4.0
Italy NaN
35

Japan 8.0
USA 2.0
dtype: float64

Podemos concatenar séries com a função concat(), passando as séries a serem concate-
nadas em uma lista e a direção que a concatenação deve ser realizada.

[17]: pd.concat([ser1, ser2], axis=1, sort=False) # concatenação ao longo das␣


,→colunas

[17]: 0 1
USA 1.0 1.0
Germany 2.0 2.0
Brazil 3.0 NaN
Japan 4.0 4.0
Italy NaN 5.0

[18]: pd.concat([ser1, ser2], axis=0, sort=False) # concatenação ao longo da␣


,→linha

[18]: USA 1
Germany 2
Brazil 3
Japan 4
USA 1
Germany 2
Italy 5
Japan 4
dtype: int64

3.2 Pandas DataFrames


Uma sequência de séries, cada uma correspondendo a uma coluna, é armazenada no formato de
DataFrame:

[1]: import pandas as pd


import numpy as np
36

[2]: from numpy.random import randn


np.random.seed(101)

[3]: index = 'A B C D E'


columns = 'W X Y Z'
df = pd.DataFrame(randn(5, 4),
index=index.split(),
columns=columns.split())

[4]: df

[4]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
C -2.018168 0.740122 0.528813 -0.589001
D 0.188695 -0.758872 -0.933237 0.955057
E 0.190794 1.978757 2.605967 0.683509

3.2.1 Seleção e indexação

Podemos selecionar uma ou múltiplas colunas utlizando seus rótulos:

[5]: df['X']

[5]: A 0.628133
B -0.319318
C 0.740122
D -0.758872
E 1.978757
Name: X, dtype: float64

[6]: df[['W','Z']]

[6]: W Z
A 2.706850 0.503826
B 0.651118 0.605965
C -2.018168 -0.589001
D 0.188695 0.955057
37

E 0.190794 0.683509

[7]: # uma notação antiga é


df.W

[7]: A 2.706850
B 0.651118
C -2.018168
D 0.188695
E 0.190794
Name: W, dtype: float64

As colunas de um pandas DataFrame são do tipo Séries:

[8]: type(df['W'])

[8]: pandas.core.series.Series

Para criar uma nova coluna utilizamos a mesma notação dos dicionários, porém ao invés
de utilizar uma chave utilizamos o rótulo de uma coluna. Também devemos tomar cuidado pois
o elemento a ser inserido deve ser uma série.

[9]: df['new'] = df['W'] + df['Y']

[10]: df

[10]: W X Y Z new
A 2.706850 0.628133 0.907969 0.503826 3.614819
B 0.651118 -0.319318 -0.848077 0.605965 -0.196959
C -2.018168 0.740122 0.528813 -0.589001 -1.489355
D 0.188695 -0.758872 -0.933237 0.955057 -0.744542
E 0.190794 1.978757 2.605967 0.683509 2.796762

Pode-se remover colunas com a função drop()

[11]: df.drop('new', axis=1)

[11]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
38

C -2.018168 0.740122 0.528813 -0.589001


D 0.188695 -0.758872 -0.933237 0.955057
E 0.190794 1.978757 2.605967 0.683509

Note que o DataFrame original não é alterado desta maneira! A função drop() retorna
um novo DataFrame que é uma cópia do original, porém sem os dados removidos.

[12]: df

[12]: W X Y Z new
A 2.706850 0.628133 0.907969 0.503826 3.614819
B 0.651118 -0.319318 -0.848077 0.605965 -0.196959
C -2.018168 0.740122 0.528813 -0.589001 -1.489355
D 0.188695 -0.758872 -0.933237 0.955057 -0.744542
E 0.190794 1.978757 2.605967 0.683509 2.796762

Precisamos passar o parâmetro inplace=True para alterar o DataFrame original:

[13]: df.drop('new', axis=1, inplace=True)

[14]: df

[14]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
C -2.018168 0.740122 0.528813 -0.589001
D 0.188695 -0.758872 -0.933237 0.955057
E 0.190794 1.978757 2.605967 0.683509

E podemos remover linhas com a mesma função, apenas alterando o valor do parâmetro
axis:

[15]: df.drop('E', axis=0)

[15]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
C -2.018168 0.740122 0.528813 -0.589001
D 0.188695 -0.758872 -0.933237 0.955057
39

Para selecionar linhas, utilizamos o método loc[]:

[16]: df.loc['A']

[16]: W 2.706850
X 0.628133
Y 0.907969
Z 0.503826
Name: A, dtype: float64

[17]: df.loc[['A', 'D']]

[17]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
D 0.188695 -0.758872 -0.933237 0.955057

Também podemos utilizar os índices das linhas com o método: iloc[]

[18]: df.iloc[2]

[18]: W -2.018168
X 0.740122
Y 0.528813
Z -0.589001
Name: C, dtype: float64

[19]: df.iloc[[1,3]]

[19]: W X Y Z
B 0.651118 -0.319318 -0.848077 0.605965
D 0.188695 -0.758872 -0.933237 0.955057

A seleção de partes do DataFrame também é possível, por meio do método loc[linhas,


colunas]:

[20]: df.loc['B','Y']

[20]: -0.8480769834036315

[21]: df.loc[['A','B'],['W','Y']]
40

[21]: W Y
A 2.706850 0.907969
B 0.651118 -0.848077

Podemos também realizar uma seleção condicional, de maneira idêntica a que fizemos com
os numpy arrays:

[22]: df

[22]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
C -2.018168 0.740122 0.528813 -0.589001
D 0.188695 -0.758872 -0.933237 0.955057
E 0.190794 1.978757 2.605967 0.683509

[23]: df > 0

[23]: W X Y Z
A True True True True
B True False False True
C False True True False
D True False False True
E True True True True

[24]: df[df > 0]

[24]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 NaN NaN 0.605965
C NaN 0.740122 0.528813 NaN
D 0.188695 NaN NaN 0.955057
E 0.190794 1.978757 2.605967 0.683509

[25]: df[df['W'] > 0]

[25]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
41

D 0.188695 -0.758872 -0.933237 0.955057


E 0.190794 1.978757 2.605967 0.683509

[26]: df[df['W'] > 0]['Y']

[26]: A 0.907969
B -0.848077
D -0.933237
E 2.605967
Name: Y, dtype: float64

[27]: df[df['W'] > 0][['Y', 'X']]

[27]: Y X
A 0.907969 0.628133
B -0.848077 -0.319318
D -0.933237 -0.758872
E 2.605967 1.978757

Podemos utilizar expressões lógicas também:

[28]: df[(df['W'] > 0) & (df['Y'] > 0)]

[28]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
E 0.190794 1.978757 2.605967 0.683509

Algumas opções mais sofisticadas para a indexação estão disponíveis no pandas. Por
exemplo, podemos resetar ou alterar os índices, e até mesmo criar hierarquias de índices.

[29]: df

[29]: W X Y Z
A 2.706850 0.628133 0.907969 0.503826
B 0.651118 -0.319318 -0.848077 0.605965
C -2.018168 0.740122 0.528813 -0.589001
D 0.188695 -0.758872 -0.933237 0.955057
E 0.190794 1.978757 2.605967 0.683509
42

[30]: # Reset para o padrão 0, 1, ..., n


df.reset_index()

[30]: index W X Y Z
0 A 2.706850 0.628133 0.907969 0.503826
1 B 0.651118 -0.319318 -0.848077 0.605965
2 C -2.018168 0.740122 0.528813 -0.589001
3 D 0.188695 -0.758872 -0.933237 0.955057
4 E 0.190794 1.978757 2.605967 0.683509

Podemos criar uma nova série em uma coluna e utilizar a mesma como índices:

[31]: newind = 'CA NY WY OR CO'.split()

[32]: df['States'] = newind

[33]: df

[33]: W X Y Z States
A 2.706850 0.628133 0.907969 0.503826 CA
B 0.651118 -0.319318 -0.848077 0.605965 NY
C -2.018168 0.740122 0.528813 -0.589001 WY
D 0.188695 -0.758872 -0.933237 0.955057 OR
E 0.190794 1.978757 2.605967 0.683509 CO

[34]: df.set_index('States')

[34]: W X Y Z
States
CA 2.706850 0.628133 0.907969 0.503826
NY 0.651118 -0.319318 -0.848077 0.605965
WY -2.018168 0.740122 0.528813 -0.589001
OR 0.188695 -0.758872 -0.933237 0.955057
CO 0.190794 1.978757 2.605967 0.683509

[35]: df

[35]: W X Y Z States
A 2.706850 0.628133 0.907969 0.503826 CA
43

B 0.651118 -0.319318 -0.848077 0.605965 NY


C -2.018168 0.740122 0.528813 -0.589001 WY
D 0.188695 -0.758872 -0.933237 0.955057 OR
E 0.190794 1.978757 2.605967 0.683509 CO

[36]: df.set_index('States',inplace=True)

[37]: df

[37]: W X Y Z
States
CA 2.706850 0.628133 0.907969 0.503826
NY 0.651118 -0.319318 -0.848077 0.605965
WY -2.018168 0.740122 0.528813 -0.589001
OR 0.188695 -0.758872 -0.933237 0.955057
CO 0.190794 1.978757 2.605967 0.683509

Pandas permite o uso de múltiplos índices e até mesmo criar uma hierarquia de índices.
Por exemplo, podemos criar uma lista de tuplas e utilizar a função MultiIndex.from_tuples()
para criar esta estrutura.

[38]: # Níveis de índices


outside = ['G1', 'G1', 'G1', 'G2', 'G2', 'G2']
inside = [1, 2, 3, 1, 2, 3]

[39]: hier_index = list(zip(outside, inside))


print(hier_index)

[('G1', 1), ('G1', 2), ('G1', 3), ('G2', 1), ('G2', 2), ('G2', 3)]

[40]: hier_index = pd.MultiIndex.from_tuples(hier_index)

[41]: hier_index

[41]: MultiIndex([('G1', 1),


('G1', 2),
('G1', 3),
('G2', 1),
('G2', 2),
44

('G2', 3)],
)

[42]: df = pd.DataFrame(np.random.randn(6, 2), index=hier_index, columns=['A',␣


,→'B'])

df

[42]: A B
G1 1 0.302665 1.693723
2 -1.706086 -1.159119
3 -0.134841 0.390528
G2 1 0.166905 0.184502
2 0.807706 0.072960
3 0.638787 0.329646

Neste caso, a indexação de linhas por meio do loc[] pode retornar um DataFrame, ao
invés de uma série:

[43]: df.loc['G1']

[43]: A B
1 0.302665 1.693723
2 -1.706086 -1.159119
3 -0.134841 0.390528

Para obter apenas uma linha, precisamos utilizar a indexação do DataFrame obtido na
primeira indexação:

[44]: df.loc['G1'].loc[1]

[44]: A 0.302665
B 1.693723
Name: 1, dtype: float64

Os nomes dos índices podem ser lidos e laterados por meio da propriedade: index.names

[45]: df.index.names

[45]: FrozenList([None, None])


45

[46]: df.index.names = ['Group','Num']

[47]: df

[47]: A B
Group Num
G1 1 0.302665 1.693723
2 -1.706086 -1.159119
3 -0.134841 0.390528
G2 1 0.166905 0.184502
2 0.807706 0.072960
3 0.638787 0.329646

A indexação nesta estrutura hierárquica pode ser feita por meio do método gs() também,
o qual permite escolher o nível da hierarquia por meio do parâmetro level:

[48]: df.xs('G1')

[48]: A B
Num
1 0.302665 1.693723
2 -1.706086 -1.159119
3 -0.134841 0.390528

[49]: df.xs(['G1',1])

[49]: A 0.302665
B 1.693723
Name: (G1, 1), dtype: float64

[50]: df.xs(1,level='Num')

[50]: A B
Group
G1 0.302665 1.693723
G2 0.166905 0.184502
46

3.2.2 Lidando com informações faltantes

No pandas, informações faltantes são exibidas como NaN (not a number ). Internamente, elas são
do tipo np.nan.

[1]: import numpy as np


import pandas as pd

[2]: df = pd.DataFrame({'A' : [1, 2, np.nan],


'B' : [5, np.nan, np.nan],
'C' : [1, 2, 3]})

[3]: df

[3]: A B C
0 1.0 5.0 1
1 2.0 NaN 2
2 NaN NaN 3

Podemos identificar os registros faltantes com o método isnull():

[4]: df.isnull()

[4]: A B C
0 False False False
1 False True False
2 True True False

dropna() e fillna() E podemos remover todas as linhas que contém ao menos um registro
faltante com o dropna(). Para realizar a mesma operação com colunas, basta passar o parâ-
metro axis=1. Alternativamente, você pode definir um limite de valores faltantes tolerável, ou
threshold, passando o parâmetro thresh.

[5]: df.dropna()

[5]: A B C
0 1.0 5.0 1

[6]: df.dropna(axis=1)
47

[6]: C
0 1
1 2
2 3

[7]: df.dropna(thresh=2)

[7]: A B C
0 1.0 5.0 1
1 2.0 NaN 2

Uma saída também muito utilizada quando em face de dados faltantes é simplesmente
substitui-los por algum valor padrão. Isso pode ser feito por meio do método fillna(). O que
muitas pessoas fazem é utilizar valores médios ou medianas das séries, de modo a impactar de
maneira mínima as estatísticas das mesmas.

[8]: df.fillna(value='algo')

[8]: A B C
0 1 5 1
1 2 algo 2
2 algo algo 3

[9]: df['A'].fillna(value=df['A'].mean())

[9]: 0 1.0
1 2.0
2 1.5
Name: A, dtype: float64

[10]: df1 = pd.DataFrame({'A' : [1, 2, np.nan],


'B' : [5, np.nan, np.nan],
'C' : [1, 2, 3]})

df2 = pd.DataFrame({'A' : [1, 2, np.nan],


'B' : [5, np.nan, np.nan],
'C' : [1, 2, 3]})
48

[11]: col = df1.columns.values

for i in col:
df1[i].fillna(value=df1[i].mean(), inplace=True)

df1

[11]: A B C
0 1.0 5.0 1
1 2.0 5.0 2
2 1.5 5.0 3

3.2.3 Agrupamento de dados por groupby

O método groupby do pandas DataFrame permite que você agrupe dados para aplicar funções
especiais, chamadas de funções agregativas nos mesmos. Isto é muito utilizado quando precisamos
obter as estatísticas de grupos selecionados dentro dos dados de um DataFrame, por exemplo.

[1]: import pandas as pd


# Criar o dataframe
data = {'Company' : ['GOOG', 'GOOG', 'MSFT', 'MSFT', 'FB', 'FB'],
'Person' : ['Sam', 'Charlie', 'Amy', 'Vanessa', 'Carl', 'Sarah'],
'Sales' : [200, 120, 340, 124, 243, 350]}

data

[1]: {'Company': ['GOOG', 'GOOG', 'MSFT', 'MSFT', 'FB', 'FB'],


'Person': ['Sam', 'Charlie', 'Amy', 'Vanessa', 'Carl', 'Sarah'],
'Sales': [200, 120, 340, 124, 243, 350]}

[2]: df = pd.DataFrame(data)

[3]: df

[3]: Company Person Sales


0 GOOG Sam 200
1 GOOG Charlie 120
2 MSFT Amy 340
49

3 MSFT Vanessa 124


4 FB Carl 243
5 FB Sarah 350

[4]: by_comp = df.groupby('Company')


by_comp

[4]: <pandas.core.groupby.generic.DataFrameGroupBy object at␣


,→0x00000266F1C46860>

O objeto retornado pelo groupby não tem muita utilidade nesta forma, porém podemos
aplicar uma série de funções nele e extrair por exemplo, as estatísticas.

[5]: by_comp.mean()

[5]: Sales
Company
FB 296.5
GOOG 160.0
MSFT 232.0

[6]: by_comp.std()

[6]: Sales
Company
FB 75.660426
GOOG 56.568542
MSFT 152.735065

[7]: by_comp.min()

[7]: Person Sales


Company
FB Carl 243
GOOG Charlie 120
MSFT Amy 124

[8]: by_comp.max()
50

[8]: Person Sales


Company
FB Sarah 350
GOOG Sam 200
MSFT Vanessa 340

[9]: by_comp.count()

[9]: Person Sales


Company
FB 2 2
GOOG 2 2
MSFT 2 2

Um resumo das estatísticas pode ser obtido por meio do método describe()

[10]: by_comp.describe()

[10]: Sales
count mean std min 25% 50% 75% max
Company
FB 2.0 296.5 75.660426 243.0 269.75 296.5 323.25 350.0
GOOG 2.0 160.0 56.568542 120.0 140.00 160.0 180.00 200.0
MSFT 2.0 232.0 152.735065 124.0 178.00 232.0 286.00 340.0

[11]: by_comp.describe().transpose()

[11]: Company FB GOOG MSFT


Sales count 2.000000 2.000000 2.000000
mean 296.500000 160.000000 232.000000
std 75.660426 56.568542 152.735065
min 243.000000 120.000000 124.000000
25% 269.750000 140.000000 178.000000
50% 296.500000 160.000000 232.000000
75% 323.250000 180.000000 286.000000
max 350.000000 200.000000 340.000000

[12]: by_comp.describe().transpose()['GOOG']
51

[12]: Sales count 2.000000


mean 160.000000
std 56.568542
min 120.000000
25% 140.000000
50% 160.000000
75% 180.000000
max 200.000000
Name: GOOG, dtype: float64

3.2.4 merge, join e concatenate DataFrames

Existem diversas maneiras de agrupar as informações de diferentes DataFrames em um único


objeto. Para administradores de bancos de dados relacionais, cujo trabalho consiste em manter
enormes tabelas de dados, este é um trabalho rotineiro, que é possível graças às chaves relacionais.
Em Pandas, este mesmo conceito é utilizado para manter a coerência dos dados nestas operações
agregativas.

[1]: import pandas as pd

[2]: df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],


'B': ['B0', 'B1', 'B2', 'B3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index=[0, 1, 2, 3])

[3]: df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],


'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']},
index=[4, 5, 6, 7])

[4]: df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],


'B': ['B8', 'B9', 'B10', 'B11'],
'C': ['C8', 'C9', 'C10', 'C11'],
'D': ['D8', 'D9', 'D10', 'D11']},
index=[8, 9, 10, 11])
52

[5]: df1

[5]: A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3

[6]: df2

[6]: A B C D
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7

[7]: df3

[7]: A B C D
8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11

A concatenação dos DataFrames é realizada pela função concat(), onde devemos passar
como parâmetro uma lista contendo os DataFrames a serem concatenados. O padrão desta
função é seguir a ordem dos índices, colocando nas mesmas colunas os dados com os mesmos
rótulos. Porém, podemos subverter esta ordem fornecendo o parâmetro axis=1.

[8]: pd.concat([df1, df2, df3])

[8]: A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 A4 B4 C4 D4
5 A5 B5 C5 D5
53

6 A6 B6 C6 D6
7 A7 B7 C7 D7
8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11

[9]: pd.concat([df1, df2, df3], axis=1)

[9]: A B C D A B C D A B C D
0 A0 B0 C0 D0 NaN NaN NaN NaN NaN NaN NaN NaN
1 A1 B1 C1 D1 NaN NaN NaN NaN NaN NaN NaN NaN
2 A2 B2 C2 D2 NaN NaN NaN NaN NaN NaN NaN NaN
3 A3 B3 C3 D3 NaN NaN NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN A4 B4 C4 D4 NaN NaN NaN NaN
5 NaN NaN NaN NaN A5 B5 C5 D5 NaN NaN NaN NaN
6 NaN NaN NaN NaN A6 B6 C6 D6 NaN NaN NaN NaN
7 NaN NaN NaN NaN A7 B7 C7 D7 NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN NaN NaN A8 B8 C8 D8
9 NaN NaN NaN NaN NaN NaN NaN NaN A9 B9 C9 D9
10 NaN NaN NaN NaN NaN NaN NaN NaN A10 B10 C10 D10
11 NaN NaN NaN NaN NaN NaN NaN NaN A11 B11 C11 D11

Tipos de merge: podemos aglutinar os dados também por meio da função merge, que opera em
pares de DataFrames e seleciona quais dados manter de acordo com o tipo de merge: left, right,
outer ou inner. Estas opções são exatamente iguais às opções que existem em bancos de dados
relacionais do tipo Sql, correspondendo à preservação dos registros com chaves no DataFrame
da esquerda (left), da direita (right), que aparecem em ambos os DataFrames obrigatioriamente
(inner, ou na intersecção das keys) ou que aparecem em um ou outro dataframe (outter, ou na
união das keys).

[10]: left = pd.DataFrame({'key': ['K1', 'K4', 'K2', 'K3'],


'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key': ['K0', 'K1', 'K2', 'K3'],


54

'C': ['C0', 'C1', 'C2', 'C3'],


'D': ['D0', 'D1', 'D2', 'D3']})

[11]: left

[11]: key A B
0 K1 A0 B0
1 K4 A1 B1
2 K2 A2 B2
3 K3 A3 B3

[12]: right

[12]: key C D
0 K0 C0 D0
1 K1 C1 D1
2 K2 C2 D2
3 K3 C3 D3

[13]: pd.merge(left, right, how='left', on='key')

[13]: key A B C D
0 K1 A0 B0 C1 D1
1 K4 A1 B1 NaN NaN
2 K2 A2 B2 C2 D2
3 K3 A3 B3 C3 D3

[14]: pd.merge(left, right, how='right', on='key')

[14]: key A B C D
0 K1 A0 B0 C1 D1
1 K2 A2 B2 C2 D2
2 K3 A3 B3 C3 D3
3 K0 NaN NaN C0 D0

[15]: pd.merge(left, right, how='inner', on='key')


55

[15]: key A B C D
0 K1 A0 B0 C1 D1
1 K2 A2 B2 C2 D2
2 K3 A3 B3 C3 D3

[16]: pd.merge(left, right, how='outer', on='key')

[16]: key A B C D
0 K1 A0 B0 C1 D1
1 K4 A1 B1 NaN NaN
2 K2 A2 B2 C2 D2
3 K3 A3 B3 C3 D3
4 K0 NaN NaN C0 D0

[17]: pd.merge(left, right, on='key')

[17]: key A B C D
0 K1 A0 B0 C1 D1
1 K2 A2 B2 C2 D2
2 K3 A3 B3 C3 D3

Note que o padrão do merge é por inner join, que é a opção mais segura: selecionar as
chaves que estão presentes em ambos os DataFrames. A seguir, um exemplo mais elaborado,
com mais chaves

[18]: left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],


'key2': ['K0', 'K1', 'K0', 'K1'],
'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],


'key2': ['K0', 'K0', 'K0', 'K0'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']})

[19]: left
56

[19]: key1 key2 A B


0 K0 K0 A0 B0
1 K0 K1 A1 B1
2 K1 K0 A2 B2
3 K2 K1 A3 B3

[20]: right

[20]: key1 key2 C D


0 K0 K0 C0 D0
1 K1 K0 C1 D1
2 K1 K0 C2 D2
3 K2 K0 C3 D3

[21]: pd.merge(left, right, on=['key1', 'key2'])

[21]: key1 key2 A B C D


0 K0 K0 A0 B0 C0 D0
1 K1 K0 A2 B2 C1 D1
2 K1 K0 A2 B2 C2 D2

[22]: pd.merge(left, right, how='outer', on=['key1', 'key2'])

[22]: key1 key2 A B C D


0 K0 K0 A0 B0 C0 D0
1 K0 K1 A1 B1 NaN NaN
2 K1 K0 A2 B2 C1 D1
3 K1 K0 A2 B2 C2 D2
4 K2 K1 A3 B3 NaN NaN
5 K2 K0 NaN NaN C3 D3

[23]: pd.merge(left, right, how='right', on=['key1', 'key2'])

[23]: key1 key2 A B C D


0 K0 K0 A0 B0 C0 D0
1 K1 K0 A2 B2 C1 D1
2 K1 K0 A2 B2 C2 D2
3 K2 K0 NaN NaN C3 D3
57

[24]: pd.merge(left, right, how='left', on=['key1', 'key2'])

[24]: key1 key2 A B C D


0 K0 K0 A0 B0 C0 D0
1 K0 K1 A1 B1 NaN NaN
2 K1 K0 A2 B2 C1 D1
3 K1 K0 A2 B2 C2 D2
4 K2 K1 A3 B3 NaN NaN

[25]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],


'B': ['B0', 'B1', 'B2']},
index=['K0', 'K1', 'K2'])

right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],


'D': ['D0', 'D2', 'D3']},
index=['K0', 'K2', 'K3'])

[26]: pd.merge(left, right, how='left', left_index=True, right_index=True,)

[26]: A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2

Por fim, o método join é conveniente para combinar as colunas de dois DataFrames cujos
índices podem ser diferentes.

[27]: left = pd.DataFrame({'A': ['A0', 'A1', 'A2'],


'B': ['B0', 'B1', 'B2']},
index=['K0', 'K1', 'K2'])

right = pd.DataFrame({'C': ['C0', 'C2', 'C3'],


'D': ['D0', 'D2', 'D3']},
index=['K0', 'K2', 'K3'])

[28]: left
58

[28]: A B
K0 A0 B0
K1 A1 B1
K2 A2 B2

[29]: right

[29]: C D
K0 C0 D0
K2 C2 D2
K3 C3 D3

[30]: left.join(right)

[30]: A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2

[31]: left.join(right, how='outer')

[31]: A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2
K3 NaN NaN C3 D3

3.2.5 Operações em DataFrames

Pode-se realizar uma série de operações sobre as Series e DataFrames, sendo que muitas destas
são geralmente de natureza estatística.

[1]: import pandas as pd


df = pd.DataFrame({'col1' : [1, 2, 3, 4],
'col2' : [444, 555, 666, 444],
'col3' : ['abc', 'def', 'ghi', 'xyz']})
df.head()
59

[1]: col1 col2 col3


0 1 444 abc
1 2 555 def
2 3 666 ghi
3 4 444 xyz

unique(), nunique(), value_counts(), sum(), mean() e std() Valores únicos e não únicos,
assim como contagem de valores absolutos podem ser obtidos a partir dos métodos unique(),
nunique() e value_counts(), respectivamente. Para séries com valores numéricos, pode-se
obter somas e estatísticas com sum(), mean() e std() por exemplo.

[2]: df['col2'].unique()

[2]: array([444, 555, 666], dtype=int64)

[3]: df['col2'].nunique()

[3]: 3

[4]: df['col2'].value_counts()

[4]: 444 2
555 1
666 1
Name: col2, dtype: int64

[5]: df['col1'].sum()

[5]: 10

[6]: df['col1'].mean()

[6]: 2.5

[7]: df['col1'].std()

[7]: 1.2909944487358056

Conforme visto anteriormente, podemos também selecionar os dados a partir de alguma


expressão lógica.
60

[8]: newdf = df[(df['col1'] > 2) & (df['col2'] == 444)]

[9]: newdf

[9]: col1 col2 col3


3 4 444 xyz

apply() Existem também a opção de aplicar uma função em todos os dados de um DataFrame
por meio do método apply().

[10]: def vezes2(x):


return x * 2

[11]: df['col1'].apply(vezes2)

[11]: 0 2
1 4
2 6
3 8
Name: col1, dtype: int64

[12]: df['col3'].apply(len)

[12]: 0 3
1 3
2 3
3 3
Name: col3, dtype: int64

Remover uma coluna inteira é simples, basta utilizar a palavra reservada del e a série da
coluna:

[13]: del df['col1']

[14]: df

[14]: col2 col3


0 444 abc
1 555 def
61

2 666 ghi
3 444 xyz

Os nomes das colunas e rótulos dos índices podem ser obtidos das propriedades columns
e index:

[15]: df.columns

[15]: Index(['col2', 'col3'], dtype='object')

[16]: df.index

[16]: RangeIndex(start=0, stop=4, step=1)

Ordenamento dos dados podem ser obtido de maneir direta, por meio do método
sort_values(). O parâmetro do mesmo é a coluna, ou série que deverá ser utilizada para
as comparações durante o ordenamento.

[17]: df

[17]: col2 col3


0 444 abc
1 555 def
2 666 ghi
3 444 xyz

[18]: df.sort_values(by='col2') #inplace=False by default

[18]: col2 col3


0 444 abc
3 444 xyz
1 555 def
2 666 ghi

Por fim, podemos também criar uma tabela de pivôs a partir de um DataFrame. Esta
tabela simplesmente agrega os valores em uma ordem definida por índices e colunas, conforme o
exemplo a seguir:
62

[19]: data = {'A':['foo', 'foo', 'foo', 'bar', 'bar', 'bar'],


'B':['one', 'one', 'two', 'two', 'one', 'one'],
'C':['x', 'y', 'x', 'y', 'x', 'y'],
'D':[1, 3, 2, 5, 4, 1]}

df = pd.DataFrame(data)

[20]: df

[20]: A B C D
0 foo one x 1
1 foo one y 3
2 foo two x 2
3 bar two y 5
4 bar one x 4
5 bar one y 1

[21]: df.pivot_table(values='D', index=['A', 'B'], columns=['C'])

[21]: C x y
A B
bar one 4.0 1.0
two NaN 5.0
foo one 1.0 3.0
two 2.0 NaN

3.2.6 Entrada e saída de dados

Nos exemplos que vimos até o momento, tivemos que digitar os valores que seriam armazenados
nas séries ou DataFrames. Obviamente esta não é uma situação real de trabalho, onde muitas
vezes os dados são fornecidos por outras ferramentas, tais como gerenciadores de planilhas do
tipo Excel ou OpenOffice, arquivos de dados, páginas da internet ou bancos de dados relacionais.
Vamos ver como ler e escrever os dados tanto em planilhas quanto em arquivos do tipo csv
(comma separated values - valores separados por vírgula).

[1]: import numpy as np


import pandas as pd
63

read_csv() e to_csv() A leitura de um arquivo csv, que é basicamente um arquivo de texto


onde cada linha representa um registro, contendo diversos valores separados por vírgula, é feita
pela função read_csv()

[2]: df = pd.read_csv('exemplo.csv')
df

[2]: a b c d
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15

De maneira análoga, os dados podem ser escritos no mesmo formato por meio do método
to_csv()

[3]: df.to_csv('exemplo.csv', index=False)

read_excel() e to_excel() Pandas pode ler e escrever em planilhas do Excel. No entanto,


muito cuidado com o tipo de informações que você irá ler, pois fórmulas e imagens não são lidos,
apenas os valores numéricos. Muitas vezes a presença de uma imagem em uma planilha pode
gerar um erro na leitura do arquivo.

A leitura é feita pela função read_excel(). Você pode inclusive escolher até mesmo qual
aba gostaria de ler, passando o parâmetro sheet_name.

[4]: pd.read_excel('Excel_Sample.xlsx', sheet_name='Sheet1')

[4]: Unnamed: 0 a b c d
0 0 0 1 2 3
1 1 4 5 6 7
2 2 8 9 10 11
3 3 12 13 14 15

A escrita para o formato Excel é feita pelo método to_excel(), onde da mesma maneira
a aba da planilha de destino pode ser escolhida. Para realizar esta operação, é necessária a
instalação do módulo openpyxl. Isto pode ser realizado no terminal por meio do comando

conda install openpyxl.


64

[5]: df.to_excel('Excel_Sample.xlsx',sheet_name='Sheet1')

Para ler de uma página html, você precisa ter instaladas as bibliotecas htmllib5, lxml e
BeautifulSoup4. Para isto, basta digitar no terminal os seguintes comandos:

conda install lxml


conda install html5lib
conda install BeautifulSoup4

E em seguida reiniciar seu jupyter notebook. Feito isto, Pandas pode ler informações de
tabelas no formato html. Por exemplo, a leitura dos dados de um site do governo americano onde
constam informações sobre bancos falidos pode ser obtida por meio da função read_html().

[6]: df = pd.read_html('http://www.fdic.gov/bank/individual/failed/banklist.
,→html')

[7]: df[0].head()

[7]: Bank Name City ST CERT \


0 Ericson State Bank Ericson NE 18265
1 City National Bank of New Jersey Newark NJ 21111
2 Resolute Bank Maumee OH 58317
3 Louisa Community Bank Louisa KY 58112
4 The Enloe State Bank Cooper TX 10716

Acquiring Institution Closing Date


0 Farmers and Merchants Bank February 14, 2020
1 Industrial Bank November 1, 2019
2 Buckeye State Bank October 25, 2019
3 Kentucky Farmers Bank Corporation October 25, 2019
4 Legend Bank, N. A. May 31, 2019
65

4 Avaliação 1 - Numpy e Pandas

4.1 Exercício Avaliativo NumPy


(Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta).

1. Importe NumPy como np.

[1]:

2. Crie um array com 10 zeros.

[ ]:

3. Crie um array com 10 ‘uns’.

[ ]:

4. Crie um array com 10 ‘cincos’.

[ ]:

5. Crie um vetor de números inteiros de 10 ate 50.

[ ]:

6. Crie um vetor com o numeros pares de 10 até 50.

[ ]:

7. Crie uma matriz 3 × 3 com os valores de 0 até 8.

[ ]:

8. Crie uma matriz identidade 7 × 7.

[ ]:

9. Use numpy para gerar um número aleatório entre 0 e 1.

[ ]:

10. Use o numpy para gerar 25 números aleatório de distribuição normal padrão (gaussiana
com média µ = 0 e desvio padrão σ = 1).
66

[ ]:

11. Crie a matrix abaixo:

array([[0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1 ],
[0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2 ],
[0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3 ],
[0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4 ],
[0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5 ],
[0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6 ],
[0.61, 0.62, 0.63, 0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7 ],
[0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79, 0.8 ],
[0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9 ],
[0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1. ]])

[ ]:

12. Crie um array de 20 elementos igulmente espaçados entre 0 e 1.

[ ]:

13. Dada a matrix abaixo:

array([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]])

Obtenha as seguintes matrizes por indexação e se necessário, reshape: *

array([[12, 13, 14, 15],


[17, 18, 19, 20],
[22, 23, 24, 25]])

array([[ 2],
[ 7],
[12]])


67

array([21, 22, 23, 24, 25])

array([[16, 17, 18, 19, 20],


[21, 22, 23, 24, 25]])

[ ]:

14. Some todos os valores da matriz.

[ ]:

15. Some todas as colunas da matriz.

[ ]:

16. Calcule o desvio padrão por coluna.

[ ]:
68

4.2 Exercícios Avaliativos Pandas


(Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta).

Nos exercícios abaixo iremos utilizar os dados de salários da cidade de São Francisco, SF
Salaries Dataset [3] do site do Kaggle [8].

1. Importe pandas como pd.

[ ]:

2. Leia o arquivo Salaries.csv e salve as informações no DataFrame sal.

[ ]:

3. Verifique os primeiros registros de sal.

[ ]:

4. Use o método info() para descobrir o número de registros.

[ ]:

5. Qual é a média de BasePay?

[ ]:

6. Qual é o maior salário em OvertimePay no dataset?

[ ]:

7. Qual a profissão (JobTitle) de Courtney T Mcelrath?

[ ]:

8. Quanto ele recebe incluindo os benefícios (TotalPayBenefits)?

[ ]:

9. Qual a pessoa mais bem paga incluindo os benefícios?

[ ]:

10. Qual a pessoa com o pior pagamento incluindo os benefícios?

[ ]:
69

11. Qual e média da base salárial (BasePay) de todos os funcionários no período de 2011-2014?

[ ]:

12. Quantas profissões diferente há nessa base de dados?

[ ]:

13. Quais são as 5 profissões mais comuns?

[ ]:

14. Quantas profissões tinham apenas uma pessoa no ano de 2014?

[ ]:

15. Quantas pessoas tem a palavra ‘Chief’ na sua profissão (jobTitle)?

[ ]:

16. Há correlação (correlation) entre o tamanho do nome da profissão e o salário?

[ ]:
70

5 Matplotlib

O Matplotlib é a biblioteca de visualização de dados com Python. Foi criado por John
Hunter, com o intuito de replicar os recursos do MatLab no Python, sua documentação esta
disponível em [5]. Caso queira utilizar fora do Collab é necessário realizar a instalação através da
instrução:

• conda install matplotlib


Caso utilize o Anaconda [1]
• pip install matplotlib
Caso contrário

Primeiramente importamos a biblioteca e utilizamos a função mágica %matplotlib


inline para tornar a visualização dos resultados esteticamente agradável para o formato de
jupyter notebooks.

[1]: import matplotlib.pyplot as plt # abreviação de matplotlib.pyplot foi␣


,→convencionado como plt

%matplotlib inline

O matplotlib foi construído pensando-se na compatibilidade com NumPy, Listas e Pandas


Series.

[2]: import numpy as np


x = np.linspace(0, 5, 11)
y = x ** 2

[3]: x

[3]: array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ])

[4]: y

[4]: array([ 0. , 0.25, 1. , 2.25, 4. , 6.25, 9. , 12.25, 16. ,


20.25, 25. ])

O comando básico é a função plot(), que gera um gráfico a partir dos dados que são
passados como parâmetros. Outras funções fazem ajustes das informações exibidas na tela, tal
como os títulos dos dados nos eixos e o título do gráfico em si, por exemplo.
71

[5]: plt.plot(x, y, 'r')


plt.xlabel('eixo X')
plt.ylabel('eixo Y')
plt.title('Título do gráfico')
plt.show()

Figura 1: Matplotlib - Estrutura básica do gráfico

Podemos criar múltiplos gráficos na mesma área de pintura com a função subplot():

[6]: # plt.subplot(nrows, ncols, plot_number)


plt.subplot(1,2,1)
plt.plot(x, y, 'r--')
plt.subplot(1,2,2)
plt.plot(y, x, 'g*-');
72

Figura 2: Matplotlib - Múltiplos gráficos

No matplotlib podemos utilizar uma abordagem baseada em orientação a objetos. A idéia


principal é criar objetos de figura e depois chamar métodos ou atributos dos mesmos. Essa
abordagem se mostra bastante prática quando se lida com uma tela com vários gráficos. Para
exemplificar, vamos criar uma instância de figura e em seguida adicionar eixos a essa figura.

[7]: # criar uma figura, que nada mais é do que uma tela de pintura vazia
fig = plt.figure()

# adicionar eixos à figura


axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # esquerda, base, largura e␣
,→altura (de 0 a 1)

# imprimir nos eixos


axes.plot(x, y, 'b')
axes.set_xlabel('rótulo de x') # Notice the use of set_ to begin methods
axes.set_ylabel('rótulo de y')
axes.set_title('Título do gráfico')
plt.show()
73

Figura 3: Matplotlib - Instância de figure()

Deste modo podemos incluir múltiplos gráficos em uma mesma figura:

[8]: # criar a figura


fig = plt.figure()

axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # figura principal


axes2 = fig.add_axes([0.2, 0.5, 0.3, 0.25]) # inset

# Figura principal
axes1.plot(x, y, 'b')
axes1.set_xlabel('eixo X axes1')
axes1.set_ylabel('eixo Y axes1')
axes1.set_title('Título axes1')

# Figura do inset
axes2.plot(y, x, 'r')
axes2.set_xlabel('eixo X axes2')
axes2.set_ylabel('eixo Y axes2')
axes2.set_title('Título axes2');
74

Figura 4: Matplotlib - Instância de figure(), múltiplos gráficos

A função plt.subplots() atua como um gerenciador de eixos mais automático.

[9]: # similar ao plt.figure() mas retorna uma tupla com a figura e os eixos
fig, axes = plt.subplots()

# desenhar os gráficos no eixo


axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('título');
75

Figura 5: Matplotlib - Usando subplots()

Você pode especificar o número de colunas e linhas quando cria o objeto axes:

[10]: # figura vazia com 2 axes


fig, axes = plt.subplots(nrows=1, ncols=2)

Figura 6: Matplotlib - Usando subplots(), adicionando número de colunas e linhas


76

[11]: # o objeto axes é um array de objetos que podem ser utilizados para␣
,→plotar gráficos

axes

[11]: array([<matplotlib.axes._subplots.AxesSubplot object at␣


,→0x0000020429010080>,

<matplotlib.axes._subplots.AxesSubplot object at␣


,→0x000002042B36EA90>],

dtype=object)

Podemos iterar sobre os elementos deste array:

[12]: for ax in axes:


ax.plot(x, y, 'b')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('título')

# mostar a figura
fig
[12]:

Figura 7: Matplotlib - Gerando por Iteração


77

Um problema comum com o subplot ou figures é a sobreposição. Podemos


usar o método fig.tight_layout() ou plt.tight_layout(), que ajusta
automaticamente as posições dos eixos na tela da figura para que não haja
conteúdo sobreposto:

[13]: fig, axes = plt.subplots(nrows=1, ncols=2)

for ax in axes:
ax.plot(x, y, 'g')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('title')

plt.tight_layout()

Figura 8: Matplotlib - Configuração de Layout (Sobrepor)

O Matplotlib permite que a proporção, o DPI (dots per inch ou pixels


por polegada) e o tamanho da figura sejam especificados quando o objeto
Figura for criado. Você pode usar os argumentos das palavras-chave figsize
edpi.

[14]: fig = plt.figure(figsize=(8, 4), dpi=100)


78

<Figure size 800x400 with 0 Axes>

Os mesmos argumentos também podem ser passados para os gerenciadores de


layout, como a função subplots:

[15]: fig, axes = plt.subplots(figsize=(10, 3), dpi=200)

axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('título');

Figura 9: Matplotlib - Configuração Layout (figsize e dpi)

O Matplotlib pode salvar figuras de alta qualidade em vários formatos,


incluindo PNG, JPG, EPS, SVG, PGF e PDF. Para isso, basta utilizar o método
savefig.

[16]: fig.savefig("figura.png")

Aqui também podemos especificar o DPI e escolher entre diferentes


formatos de saída:

[17]: fig.savefig("figura.pdf", dpi=200)

Agora que abordamos o básico de como criar uma figuras e adicionar


instâncias de eixos à tela, vejamos como colocar títulos, rótulos de eixos e
legendas.
79

[18]: ax.set_title("Título")
ax.set_xlabel("eixo x")
ax.set_ylabel("eixo y")

[18]: Text(227.80000000000004, 0.5, 'eixo y')

Você pode usar o argumento da keyword label="texto" quando gráficos


ou outros objetos são adicionados à figura e, em seguida, usar o método
legend() sem argumentos para adicionar a legenda à figura.

[19]: fig = plt.figure(figsize=(6, 4))

ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])

ax.plot(x, x ** 2, label="x ** 2")


ax.plot(x, x ** 3, label="x ** 3")
ax.legend()

[19]: <matplotlib.legend.Legend at 0x2042b1d8c50>

Figura 10: Matplotlib - Adicionando legenda

A função legend() usa um argumento opcional de keyword loc que pode ser
usado para especificar onde na figura a legenda deve ser fixada. Os valores
80

permitidos são códigos numéricos ou strings para os vários locais em que a


legenda pode ser desenhada.

[20]: ax.legend(loc='upper right')


ax.legend(loc='upper left')
ax.legend(loc='lower left')
ax.legend(loc='lower right')

ax.legend(loc='best') # determinado automaticamente


fig
[20]:

Figura 11: Matplotlib - Customização da Legenda

As cores e estilos dos traços também podem ser determinados por meio de
parâmetros. Uma maneira muito usual é utilizar a notação do tipo MATLAB.

[21]: fig, ax = plt.subplots()


ax.plot(x, x ** 2, 'b.-') # linha azul com pontos
ax.plot(x, x ** 3, 'g--') # linha verde tracejada
plt.show()
81

Figura 12: Matplotlib - Customização estilo de traço

Também podemos definir cores por seus nomes ou códigos hexadecimais RGB
e, opcionalmente, fornecer um valor de transparência, ou alfa, por meio dos
argumentos color ealpha.

[22]: fig, ax = plt.subplots()

ax.plot(x, x+1, color="blue", alpha=0.5) # 50% transparente


ax.plot(x, x+2, color="#8B008B") # codigo hexadecimal RGB
ax.plot(x, x+3, color="#FF8C00")
plt.show()
82

Figura 13: Matplotlib - Customização estilo de cor

Para alterar a largura da linha, podemos usar o argumento da


palavra-chave linewidth oulw. O estilo da linha pode ser selecionado usando
os argumentos de palavra-chave linestyle ouls:

[23]: fig, ax = plt.subplots(figsize=(12,6))

ax.plot(x, x+1, color="red", linewidth=0.25)


ax.plot(x, x+2, color="red", linewidth=0.50)
ax.plot(x, x+3, color="red", linewidth=1.00)
ax.plot(x, x+4, color="red", linewidth=2.00)

# opções de linestype: ‘-‘, ‘–’, ‘-.’, ‘:’, ‘steps’


ax.plot(x, x+5, color="green", lw=3, linestyle='-')
ax.plot(x, x+6, color="green", lw=3, ls='-.')
ax.plot(x, x+7, color="green", lw=3, ls=':')

# traços customizados
line, = ax.plot(x, x+8, color="black", lw=1.50)
line.set_dashes([5, 10, 15, 10]) # formato: comprimento da linha,␣
,→comprimento do espaço, ...
83

# símbolos de marcadores: marker = '+', 'o', '*', 's', ',', '.', '1',␣
,→'2', '3', '4', ...

ax.plot(x, x+ 9, color="blue", lw=3, ls='-', marker='+')


ax.plot(x, x+10, color="blue", lw=3, ls='--', marker='o')
ax.plot(x, x+11, color="blue", lw=3, ls='-', marker='s')
ax.plot(x, x+12, color="blue", lw=3, ls='--', marker='1')

# tamanho e cor dos marcadores


ax.plot(x, x+13, color="purple", lw=1, ls='-', marker='o', markersize=2)
ax.plot(x, x+14, color="purple", lw=1, ls='-', marker='o', markersize=4)
ax.plot(x, x+15, color="purple", lw=1, ls='-', marker='o', markersize=8,
markerfacecolor="red")
ax.plot(x, x+16, color="purple", lw=1, ls='-', marker='s', markersize=8,
markerfacecolor="yellow", markeredgewidth=3,␣
,→markeredgecolor="green");

Figura 14: Matplotlib - Estilos de Customização traço e cor

Podemos configurar os eixos usando os métodos set_ylim() eset_xlim() no


objeto axis, ou axis ('tight') para obter automaticamente faixas de eixos.

[24]: fig, axes = plt.subplots(1, 3, figsize=(12, 4))

axes[0].plot(x, x ** 2, x, x ** 3)
84

axes[0].set_title("intervalos padrão para eixos")

axes[1].plot(x, x ** 2, x, x ** 3)
axes[1].axis('tight')
axes[1].set_title("eixos do tipo 'tight axes'")

axes[2].plot(x, x ** 2, x, x ** 3)
axes[2].set_ylim([0, 60])
axes[2].set_xlim([2, 5])
axes[2].set_title("intervalos customizados");

Figura 15: Matplotlib - Configurando eixos

Tipos especiais de gráficos incluem gráfico de dispersão (scatter),


histogramas (hist) e boxplot (boxplot) entre outros.

[25]: plt.scatter(x,y)
plt.show()
85

Figura 16: Matplotlib - Gráficos Espaciais

[26]: from random import sample


data = sample(range(1, 1000), 100)
plt.hist(data)
plt.show()

Figura 17: Matplotlib - Histograma


86

[27]: data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# box plot retangular


plt.boxplot(data, vert=True, patch_artist=True);

Figura 18: Matplotlib - Boxplot

5.1 Opções avançadas do Matplotlib


Diversas opções se encontram disponíveis para você customizar seus gráficos.
A primeira delas é o uso da escala logarítmica nos eixos.

[1]: import matplotlib


import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

[2]: x = np.linspace(0, 5, 21)

[3]: fig, axes = plt.subplots(1, 2, figsize=(10, 4))

axes[0].plot(x, x ** 2, x, np.exp(x))
87

axes[0].set_title("Escala linear")

axes[1].plot(x, x**2, x, np.exp(x))


axes[1].set_yscale("log")
axes[1].set_title("Escala logarítmica em y");

Figura 19: Matplotlib - Escala logarítmica nos eixos

Podemos determinar explicitamente onde queremos as marcações dos


eixo com os métodos set_xticks() e set_yticks(), os quais recebem listas
com os valores das posições onde as marcações deve ser posicionadas.
Adicionalmente, podemos utilizar também o método set_xticklabels() e
set_yticklabels() que recebem os símbolos que devem ser utilizados na
marcação.

[4]: fig, ax = plt.subplots(figsize=(10, 4))

ax.plot(x, x**2, x, x**3, lw=2)

ax.set_xticks([1, 2, 3, 4, 5])
ax.set_xticklabels([r'$\alpha$',
r'$\beta$',
r'$\gamma$',
r'$\delta$',
r'$\epsilon$'],
fontsize=18) # notação no formato LaTeX
88

yticks = [0, 50, 100, 150]


ax.set_yticks(yticks)
ax.set_yticklabels(["$%.1f$" % y for y in yticks], fontsize=18); #␣
,→notação no formato LaTeX

Figura 20: Matplotlib - Customização direta nos eixos

Em muitas situações podemos ter uma variação muito grande dos valores
em um eixo, até mesmo em ordens de grandeza. Neste caso, é aconselhável
utilizar notação científica.

[5]: fig, ax = plt.subplots(1, 1)

ax.plot(x, x**2, x, np.exp(x))


ax.set_title("notação científica")

ax.set_yticks([0, 50, 100, 150])

from matplotlib import ticker


formatter = ticker.ScalarFormatter(useMathText=True)
formatter.set_scientific(True)
formatter.set_powerlimits((-1,1))
ax.yaxis.set_major_formatter(formatter)
89

Figura 21: Matplotlib - Escala com notação científica

Podemos também ajustar a numeração e distância entre os eixos:

[6]: # distância entre x e y e os números dos eixos


matplotlib.rcParams['xtick.major.pad'] = 5
matplotlib.rcParams['ytick.major.pad'] = 5

fig, ax = plt.subplots(1, 1)

ax.plot(x, x ** 2, x, np.exp(x))
ax.set_yticks([0, 50, 100, 150])

ax.set_title("espaçamento de eixos")

# espaçamento entre rótulos dos eixos e números


ax.xaxis.labelpad = 5
ax.yaxis.labelpad = 5

ax.set_xlabel("x")
ax.set_ylabel("y");
90

Figura 22: Matplotlib - Espaçamento de eixos

[7]: # restaurar valores padrão


matplotlib.rcParams['xtick.major.pad'] = 3
matplotlib.rcParams['ytick.major.pad'] = 3

Ocasionalemnte, ao salvar os gráficos em arquivos, algumas informações


acabam sendo cortadas. Isto pode ser evitado ao se ajustar as posições dos
eixos, por meio do método subplots_adjust().

[8]: fig, ax = plt.subplots(1, 1)

ax.plot(x, x**2, x, np.exp(x))


ax.set_yticks([0, 50, 100, 150])

ax.set_title("Título")
ax.set_xlabel("x")
ax.set_ylabel("y")

fig.subplots_adjust(left=0.15, right=.9, bottom=0.1, top=0.9);


91

Figura 23: Matplotlib - Ajuste de posição de eixo

O método grid() controla a aparência e existência de linhas de grade.


Para a customização das mesmas, utilizamos os mesmos parâmetros vistos para
a função plot().

[9]: fig, axes = plt.subplots(1, 2, figsize=(10,3))

# aparência padrão
axes[0].plot(x, x**2, x, x**3, lw=2)
axes[0].grid(True)

# aparência customizada
axes[1].plot(x, x**2, x, x**3, lw=2)
axes[1].grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
92

Figura 24: Matplotlib - Plotagem com linhas de grade

Podemos inclusive mudar a aparência dos eixos x e y do gráfico.

[10]: fig, ax = plt.subplots(figsize=(6,2))

ax.spines['bottom'].set_color('blue')
ax.spines['top'].set_color('blue')

ax.spines['left'].set_color('red')
ax.spines['left'].set_linewidth(2)

# desligar o eixo da direita


ax.spines['right'].set_color("none")
ax.yaxis.tick_left()

Figura 25: Matplotlib - Customização dos eixos (Layout)

Algumas vezes é útil ter eixos duplicados em um gráfico, para


representar curvas com unidades diferentes, por exemplo. O matplotlib
suporta esta funcionalidade com as funçõe twinx() e twiny().
93

[11]: fig, ax1 = plt.subplots()

ax1.plot(x, x**2, lw=2, color="blue")


ax1.set_ylabel(r"área $(m^2)$", fontsize=18, color="blue")
for label in ax1.get_yticklabels():
label.set_color("blue")

ax2 = ax1.twinx()
ax2.plot(x, x**3, lw=2, color="red")
ax2.set_ylabel(r"volume $(m^3)$", fontsize=18, color="red")
for label in ax2.get_yticklabels():
label.set_color("red")

Figura 26: Matplotlib - Eixos duplicados

A escolha da posição da intersecção do eixos também é permitida:

[12]: fig, ax = plt.subplots()

ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0)) # posição do eixo x em y=0
94

ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0)) # posição do eixo y em x=0

xx = np.linspace(-0.75, 1., 100)


ax.plot(xx, xx**3);

Figura 27: Matplotlib - Posição de intersecção dos eixos

Diversos outros tipos de gráficos podem ser obtidos além do básico


plot. Alguns tipos úteis são mostrados a seguir.

[13]: n = np.array([0,1,2,3,4,5])

[14]: fig, axes = plt.subplots(1, 4, figsize=(12,3))

axes[0].scatter(xx, xx + 0.25*np.random.randn(len(xx)))
axes[0].set_title("dispersão")

axes[1].step(n, n**2, lw=2)


axes[1].set_title("escada")

axes[2].bar(n, n**2, align="center", width=0.5, alpha=0.5)


axes[2].set_title("barras")
95

axes[3].fill_between(x, x**2, x**3, color="green", alpha=0.5);


axes[3].set_title("preenchido");

Figura 28: Matplotlib - Estilos de gráficos

É possível adicionar anotações em texto aos gráficos, por meio do


método text(). Do mesmo modo que outros métodos que lidam com texto no
matplotlib, este método aceita strings no fomato LaTeX.

[15]: fig, ax = plt.subplots()

ax.plot(xx, xx**2,'b', xx, xx**3,'g')

ax.text(0.10, 0.25, r"$y=x^2$", fontsize=20, color="blue")


ax.text(0.65, 0.10, r"$y=x^3$", fontsize=20, color="green");
96

Figura 29: Matplotlib - Anotações de textos aos gráficos

Múltiplos gráficos podem ser adicionados a uma tela de pintura do


matplotlib, por meio da função fig.add_axes() ou por meio de gerenciadores
de subfiguras tais como subplots(), subplot2grid() ou gridspec().

[16]: fig, ax = plt.subplots()


fig.tight_layout()

Figura 30: Matplotlib - Layout vazio


97

[17]: fig = plt.figure()


ax1 = plt.subplot2grid((3,3), (0,0), colspan=3)
ax2 = plt.subplot2grid((3,3), (1,0), colspan=2)
ax3 = plt.subplot2grid((3,3), (1,2), rowspan=2)
ax4 = plt.subplot2grid((3,3), (2,0))
ax5 = plt.subplot2grid((3,3), (2,1))
fig.tight_layout()

Figura 31: Matplotlib - Layout múltiplo

[18]: import matplotlib.gridspec as gridspec

[19]: fig = plt.figure()

gs = gridspec.GridSpec(2, 3, height_ratios=[2,1], width_ratios=[1,2,1])

for g in gs:
ax = fig.add_subplot(g)

fig.tight_layout()
98

Figura 32: Matplotlib - Layout múltiplo

Adicionar axes manualmente por meio do add_axes() é útil quando


queremos adicionar figuras to tipo inset, por exemplo.

[20]: fig, ax = plt.subplots()

ax.plot(xx, xx**2, xx, xx**3)


fig.tight_layout()

# inset
inset_ax = fig.add_axes([0.3, 0.55, 0.35, 0.35]) # X, Y, largura, altura

inset_ax.plot(xx, xx**2, xx, xx**3)


inset_ax.set_title('zoom na origem')

# intervalo do eixo
inset_ax.set_xlim(-.2, .2)
inset_ax.set_ylim(-.005, .01)

# localização das marcações


inset_ax.set_yticks([0, 0.005, 0.01])
99

inset_ax.set_xticks([-0.1,0,.1]);

Figura 33: Matplotlib - Layout múltiplo

Mapas de cores e curvas de nível são muito úteis ao se representar


funções de duas variáveis em um plano. Na maioria das vezes utilizamos o
código de cores do mapa para representar o valor da função em cada ponto
do plano. Para isso, existem diversos mapas pré-definidos, o que facilita
muito o uso deste tipo de representação. Para uma lista de mapas de cores,
favor visitar este site.

[21]: alpha = 0.7


phi_ext = 2 * np.pi * 0.5

def flux_qubit_potential(phi_m, phi_p):


return 2 + alpha - 2 * np.cos(phi_p) * np.cos(phi_m) - alpha * np.
,→cos(phi_ext - 2*phi_p)

[22]: phi_m = np.linspace(0, 2*np.pi, 100)


phi_p = np.linspace(0, 2*np.pi, 100)
X,Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T
100

Plot de pseudo-cor com pcolor().

[ ]: fig, ax = plt.subplots()

p = ax.pcolor(X/(2*np.pi), Y/(2*np.pi), Z, cmap=matplotlib.cm.RdBu,␣


,→vmin=abs(Z).min(), vmax=abs(Z).max())

cb = fig.colorbar(p, ax=ax)

Figura 34: Matplotlib - Mapas de cores

Resultado parecido pode ser obtido com imshow():

[ ]: fig, ax = plt.subplots()

im = ax.imshow(Z, cmap=matplotlib.cm.RdBu, vmin=abs(Z).min(), vmax=abs(Z).


,→max(), extent=[0, 1, 0, 1])

im.set_interpolation('bilinear')

cb = fig.colorbar(im, ax=ax)
101

Figura 35: Matplotlib - Mapas de cores

E um mapa de curvas de nível pode ser visualizado com contour():

[ ]: fig, ax = plt.subplots()

cnt = ax.contour(Z, cmap=matplotlib.cm.RdBu, vmin=abs(Z).min(),␣


,→vmax=abs(Z).max(), extent=[0, 1, 0, 1])
102

Figura 36: Matplotlib - Mapas de curvas de nível

Podemos representar gráficos de figuras de 2 variáveis com o


matplotlib, gerando gráficos tridimensionais. Para isso, devemos criar
uma instância da classe Axes3D. Estes objetos podem ser adicionados à tela
de pintura da mesma maneira que fizemos para gráficos bidimensionais, ou
de maneira mais conveniente, passando o argumento projection='3d' para os
métodos add_axes() ou add_subplot().

[ ]: from mpl_toolkits.mplot3d.axes3d import Axes3D

Plots de superfícies tridimensionais podem ser obtidos com o


plot_surface()

[ ]: fig = plt.figure(figsize=(14,6))

# ax é um tipo diferente de axes, já preparado para informações em 3D


ax = fig.add_subplot(1, 2, 1, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)

# surface_plot com código de cores


ax = fig.add_subplot(1, 2, 2, projection='3d')
103

p = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=matplotlib.cm.


,→coolwarm, linewidth=0, antialiased=False)

cb = fig.colorbar(p, shrink=0.5)

Figura 37: Matplotlib - Gráficos tridimensional

Também podemos visualizar os gráficos tridimensionais por meio do plot


do tipo wireframe.

[ ]: fig = plt.figure(figsize=(8,6))

ax = fig.add_subplot(1, 1, 1, projection='3d')

p = ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4)


104

Figura 38: Matplotlib - Gráfico tridimensional

Por fim, podemos fazer projeções do tipo curvas de nível nos planos que
delimitam os gráficos, facilitando sua interpretação.

[ ]: fig = plt.figure(figsize=(8,6))

ax = fig.add_subplot(1,1,1, projection='3d')

ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)


cset = ax.contour(X, Y, Z, zdir='z', offset=-np.pi, cmap=matplotlib.cm.
,→coolwarm)

cset = ax.contour(X, Y, Z, zdir='x', offset=-np.pi, cmap=matplotlib.cm.


,→coolwarm)

cset = ax.contour(X, Y, Z, zdir='y', offset=3*np.pi, cmap=matplotlib.cm.


,→coolwarm)

ax.set_xlim3d(-np.pi, 2*np.pi);
ax.set_ylim3d(0, 3*np.pi);
ax.set_zlim3d(-np.pi, 2*np.pi);
105

Figura 39: Matplotlib - Projeção do gráfico tridimensional nos planos


106

6 Seaborn

Seaborn é uma biblioteca de visualização de dados baseada no matplotlib. Além de apresen-


tar belos gráficos e opções mais ricas do que o matplotlib, o seaborn também contém conjuntos
de dados que podem ser facilmente acessados, documentação completa em [10].

[1]: import seaborn as sns


%matplotlib inline

O repositório tips por exemplo mostra dados de gorjetas que atendentes de restaurantes
receberam.

[2]: tips = sns.load_dataset('tips') # https://github.com/mwaskom/seaborn-data

[3]: tips.head()

[3]: total_bill tip sex smoker day time size


0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

6.1 Gráficos de distribuições: distplot(), jointplot(), pairplot() e


rugplot()
A função distplot() mostra a distribuição de uma grandeza univariada (linha contínua) a partir
das observações (barras).

[4]: sns.distplot(tips[('total_bill')])

[4]: <matplotlib.axes._subplots.AxesSubplot at 0x1ba7fc6f2b0>


107

Figura 40: Seaborn - Gráfico de distribuição

Você pode remover a função e visualizar apenas o histograma com kde=False:

[5]: sns.distplot(tips[('total_bill')], kde=False, bins=30)

[5]: <matplotlib.axes._subplots.AxesSubplot at 0x1ba7ffce160>


108

Figura 41: Seaborn - Gráfico de distribuição sem a função

A função jointplot() permite basicamente que você combine duas representações dis-
tintas, por meio do parâmetro kind para comparar com scatter, reg, resid, kde e hex.

[6]: sns.jointplot(x='total_bill', y='tip', data=tips, kind='scatter')

[6]: <seaborn.axisgrid.JointGrid at 0x1ba0104aef0>


109

Figura 42: Seaborn - Combinação de regressão

[7]: sns.jointplot(x='total_bill', y='tip', data=tips,kind='hex')

[7]: <seaborn.axisgrid.JointGrid at 0x1ba011c12b0>


110

Figura 43: Seaborn - Combinação de regressão

[8]: sns.jointplot(x='total_bill', y='tip', data=tips,kind='reg')

[8]: <seaborn.axisgrid.JointGrid at 0x1ba012cdb00>


111

Figura 44: Seaborn - Combinação de regressão

Como o próprio nome sugere, pairplot() exibe as relações entre pares de variáveis em um
pandas DataFrame para as colunas numéricas e também exibe uma escala de cores para colunas
com variáveis categóricas.

[9]: sns.pairplot(tips)

[9]: <seaborn.axisgrid.PairGrid at 0x1ba0145c208>


112

Figura 45: Seaborn - Combinação pairplot()

[10]: sns.pairplot(tips,hue='sex',palette='coolwarm')

[10]: <seaborn.axisgrid.PairGrid at 0x1ba01956f28>


113

Figura 46: Seaborn - Combinação pairplot()

rugplot() é um conceito muito simples, ele apenas traça uma marca para cada ponto de
uma distribuição, formando algo parecido com um tapete (daí o nome).

[11]: sns.rugplot(tips['total_bill'])

[11]: <matplotlib.axes._subplots.AxesSubplot at 0x1ba019564e0>


114

Figura 47: Seaborn - Combinação rugplot()

[12]: sns.kdeplot(tips[('total_bill')])
sns.rugplot(tips[('total_bill')])

[12]: <matplotlib.axes._subplots.AxesSubplot at 0x1ba02024550>

Figura 48: Seaborn - Combinação rugplot()


115

[13]: sns.kdeplot(tips[('tip')])
sns.rugplot(tips[('tip')])

[13]: <matplotlib.axes._subplots.AxesSubplot at 0x1ba020adcc0>

Figura 49: Seaborn - Combinação rugplot()

6.2 Gráficos categóricos: barplot(), countplot(), boxplot(),


violinplot(), stripplot(), swarmplot() e catplot()
Agora vamos discutir o uso do seaborn para plotar dados categóricos! Os príncipais são esses:

• factorplot
• boxplot
• violinplot
• stripplot
• swarmplot
• barplot
• countplot

[1]: import seaborn as sns


import numpy as np
%matplotlib inline
116

[2]: tips = sns.load_dataset('tips')


tips.head()

[2]: total_bill tip sex smoker day time size


0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

[3]: tips.describe()

[3]: total_bill tip size


count 244.000000 244.000000 244.000000
mean 19.785943 2.998279 2.569672
std 8.902412 1.383638 0.951100
min 3.070000 1.000000 1.000000
25% 13.347500 2.000000 2.000000
50% 17.795000 2.900000 2.000000
75% 24.127500 3.562500 3.000000
max 50.810000 10.000000 6.000000

barplot() e countplot() são muito semelhantes, pois ambos permitem que você ob-
tenha dados agregados de um recurso categórico em seus dados. O primeiro é um gráfico que
permite agregar os dados categóricos com base em alguma função (por padrão a média).

[4]: sns.barplot(x='sex',y='total_bill',data=tips)

[4]: <matplotlib.axes._subplots.AxesSubplot at 0x2141004e6d8>


117

Figura 50: Seaborn - Função barplot()

Você pode alterar o estimador passando uma função, que converte os dados em um valor
escalar.

[5]: sns.barplot(x='sex',y='total_bill', data=tips, estimator=np.std)

[5]: <matplotlib.axes._subplots.AxesSubplot at 0x2141036a470>


118

Figura 51: Seaborn - Função barplot() - valor escalar

O countplot() é essencialmente o mesmo que o barplot(), exceto que o estimador está


explicitamente contando o número de ocorrências. É por isso que só passamos o valor x.

[6]: sns.countplot(x='sex',data=tips)

[6]: <matplotlib.axes._subplots.AxesSubplot at 0x214103deeb8>


119

Figura 52: Seaborn - Função countplot()

boxplot() e violinplot() são usados para mostrar a distribuição dos dados categóricos.
Esses gráficos mostram a distribuição de dados quantitativos de uma maneira que facilita as
comparações entre variáveis ou entre os níveis de uma variável categórica.

O boxplot() mostra os quartis do conjunto de dados enquanto as linhas (whiskers) se


estendem para mostrar o restante da distribuição, exceto os pontos que são determinados como
outliers usando um método que é uma função da faixa inter-quartil.

[7]: sns.boxplot( data=tips,palette='rainbow')

[7]: <matplotlib.axes._subplots.AxesSubplot at 0x2141041f588>


120

Figura 53: Seaborn - Função boxplot()

[8]: # mudar orientação com orient='h'


sns.boxplot(data=tips,palette='rainbow',orient='h')

[8]: <matplotlib.axes._subplots.AxesSubplot at 0x214104c1ef0>

Figura 54: Seaborn - Função boxplot() - horizontal


121

[9]: sns.boxplot(x="day", y="total_bill", hue="smoker",data=tips,␣


,→palette="coolwarm")

[9]: <matplotlib.axes._subplots.AxesSubplot at 0x21410567978>

Figura 55: Seaborn - Função boxplot() - Customizada

O violinplot() desempenha um papel semelhante ao boxplot(). Ele mostra a distri-


buição de dados quantitativos em vários níveis de uma (ou mais) variáveis categóricas, para que
essas distribuições possam ser comparadas. Ao contrário do boxplot, no qual todos os compo-
nentes do gráfico correspondem aos pontos de dados reais, o gráfico de violino apresenta uma
estimativa da densidade do núcleo da distribuição correspondente.

[10]: sns.violinplot(x="day", y="total_bill", data=tips,palette='rainbow')

[10]: <matplotlib.axes._subplots.AxesSubplot at 0x2141066a358>


122

Figura 56: Seaborn - Função violinplot()

[11]: sns.violinplot(x="day", y="total_bill",␣


,→data=tips,hue='sex',palette='Set1')

[11]: <matplotlib.axes._subplots.AxesSubplot at 0x214106fa358>

Figura 57: Seaborn - Função violinplot() - Customizada


123

[12]: sns.violinplot(x="day", y="total_bill",␣


,→data=tips,hue='sex',split=True,palette='Set1')

[12]: <matplotlib.axes._subplots.AxesSubplot at 0x214107aec50>

Figura 58: Seaborn - Função violinplot() - Customizada

stripplot() desenhará um gráfico de dispersão separando por uma variável categórica.


Um stripplot pode ser desenhado por si só, mas também é um bom complemento para um
boxplot ou violinplot nos casos em que você deseja mostrar todas as observações junto com
alguma representação da distribuição subjacente.

swarmplot() é semelhante ao stripplot(), mas os pontos são ajustados (apenas ao


longo do eixo categórico) para que não se sobreponham. Isso fornece uma melhor representa-
ção da distribuição dos valores, embora não seja escalável também para um grande número de
observações (tanto em termos da capacidade de mostrar todos os pontos quanto em termos da
computação necessária para organizá-los).

[13]: sns.stripplot(x="day", y="total_bill", data=tips)

[13]: <matplotlib.axes._subplots.AxesSubplot at 0x2141084a3c8>


124

Figura 59: Seaborn - Função stripplot()

[14]: sns.stripplot(x="day", y="total_bill", data=tips,jitter=True)

[14]: <matplotlib.axes._subplots.AxesSubplot at 0x214108b3ef0>

Figura 60: Seaborn - Função stripplot()


125

[15]: sns.stripplot(x="day", y="total_bill",␣


,→data=tips,jitter=True,hue='sex',palette='Set1')

[15]: <matplotlib.axes._subplots.AxesSubplot at 0x214108fe080>

Figura 61: Seaborn - Função stripplot() - Customizado

[16]: sns.stripplot(x="day", y="total_bill",␣


,→data=tips,jitter=True,hue='sex',palette='Set1',dodge=True)

[16]: <matplotlib.axes._subplots.AxesSubplot at 0x21410974f98>


126

Figura 62: Seaborn - Função stripplot() - Customizado

[17]: sns.swarmplot(x="day", y="total_bill", data=tips)

[17]: <matplotlib.axes._subplots.AxesSubplot at 0x214109ee5c0>

Figura 63: Seaborn - Função swarmplot()


127

[18]: sns.swarmplot(x="day", y="total_bill",hue='sex',data=tips,␣


,→palette="Set1", dodge=True)

[18]: <matplotlib.axes._subplots.AxesSubplot at 0x21410a3f5f8>

Figura 64: Seaborn - Função swarmplot() - Customizado

catplot() é a forma mais geral de um gráfico categórico. Passamos pra ele um parâmetro
kind para escolher o tipo de gráfico.

[20]: sns.catplot(x='sex',y='total_bill',data=tips, kind='bar')

[20]: <seaborn.axisgrid.FacetGrid at 0x21410aa2828>


128

Figura 65: Seaborn - Função catplot()

[21]: sns.catplot(x='sex',y='total_bill',data=tips,kind='box')

[21]: <seaborn.axisgrid.FacetGrid at 0x214109747b8>


129

Figura 66: Seaborn - Função catplot()

6.3 Combinando gráficos categóricos


Para combinar gráficos, simplesmente chamamos as funções correspondentes na sequência:

[19]: sns.violinplot(x="tip", y="day", data=tips,palette='rainbow')


sns.swarmplot(x="tip", y="day", data=tips,color='black',size=3)

[19]: <matplotlib.axes._subplots.AxesSubplot at 0x214109ee0b8>


130

Figura 67: Seaborn - Combinação gráfica violinplot() e swarmplot()

6.4 Gráficos de matrizes


Podemos visualizar os dados de matrizes também com o seaborn. Diversas funcionalidades estão
disponíveis.

[1]: import seaborn as sns


%matplotlib inline

Vamos utilizar os datasets flights e tips para exemplificar

[2]: flights = sns.load_dataset('flights')

[3]: tips = sns.load_dataset('tips')

[4]: tips.head()

[4]: total_bill tip sex smoker day time size


0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4
131

[5]: flights.head()

[5]: year month passengers


0 1949 January 112
1 1949 February 118
2 1949 March 132
3 1949 April 129
4 1949 May 121

6.4.1 Heatmap

Para que o heatmap (ou mapa de calor) funcione corretamente, seus dados já devem estar em
um formato de matriz, a função sns.heatmap() apenas os colore para você.

[6]: tips.head()

[6]: total_bill tip sex smoker day time size


0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

[7]: # matriz de correlação


tips.corr()

[7]: total_bill tip size


total_bill 1.000000 0.675734 0.598315
tip 0.675734 1.000000 0.489299
size 0.598315 0.489299 1.000000

[8]: sns.heatmap(tips.corr())

[8]: <matplotlib.axes._subplots.AxesSubplot at 0x1a4d4bb1828>


132

Figura 68: Seaborn - Gráfico heatmap()

[9]: sns.heatmap(tips.corr(),cmap='coolwarm',annot=True)

[9]: <matplotlib.axes._subplots.AxesSubplot at 0x1a4d4efcf60>

Figura 69: Seaborn - Gráfico heatmap()


133

[10]: flights.pivot_table(values='passengers',index='month',columns='year')

[10]: year 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 ␣
,→1959 \
month
January 112 115 145 171 196 204 242 284 315 340 ␣
,→360

February 118 126 150 180 196 188 233 277 301 318 ␣
,→342

March 132 141 178 193 236 235 267 317 356 362 ␣
,→406

April 129 135 163 181 235 227 269 313 348 348 ␣
,→396

May 121 125 172 183 229 234 270 318 355 363 ␣
,→420

June 135 149 178 218 243 264 315 374 422 435 ␣
,→472

July 148 170 199 230 264 302 364 413 465 491 ␣
,→548

August 148 170 199 242 272 293 347 405 467 505 ␣
,→559

September 136 158 184 209 237 259 312 355 404 404 ␣
,→463

October 119 133 162 191 211 229 274 306 347 359 ␣
,→407

November 104 114 146 172 180 203 237 271 305 310 ␣
,→362

December 118 140 166 194 201 229 278 306 336 337 ␣
,→405

year 1960
month
January 417
February 391
March 419
134

April 461
May 472
June 535
July 622
August 606
September 508
October 461
November 390
December 432

[11]: pvflights = flights.


,→pivot_table(values='passengers',index='month',columns='year')

sns.heatmap(pvflights)

[11]: <matplotlib.axes._subplots.AxesSubplot at 0x1a4d4fccb38>

Figura 70: Seaborn - Gráfico heatmap()

[12]: sns.heatmap(pvflights,cmap='magma',linecolor='white',linewidths=1)

[12]: <matplotlib.axes._subplots.AxesSubplot at 0x1a4d507a1d0>


135

Figura 71: Seaborn - Gráfico heatmap()

6.5 Grids: PairGrid(), pairplot(), FacetGrid() e JointGrid()


Grids, ou simplesmente grades são tipos gerais que permitem mapear tipos de gráficos para linhas
e colunas, ajudando a criar gráficos semelhantes separadas por recursos.

[1]: import seaborn as sns


import matplotlib.pyplot as plt
%matplotlib inline

Vamos utilizar o conjunto de dados iris que contém medidas de partes de flores e suas
respectivas espécies

[2]: iris = sns.load_dataset('iris')

[3]: iris.head()

[3]: sepal_length sepal_width petal_length petal_width species


0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosa
136

Pairgrid() gera uma grade de onde é possível plotar relacionamentos em pares em um


conjunto de dados.

[4]: # apenas a grade primeiro


sns.PairGrid(iris)

[4]: <seaborn.axisgrid.PairGrid at 0x261e7dffb00>

Figura 72: Seaborn - Gráfico Pairgrid()

[5]: # então você escolhe o tipo de gráfico a ser inserido na grade


g = sns.PairGrid(iris)
g.map(plt.scatter)

[5]: <seaborn.axisgrid.PairGrid at 0x261e87b5278>


137

Figura 73: Seaborn - Gráficos variados

[6]: # Mapeamento da parte superior, inferior e da diagona da grade


g = sns.PairGrid(iris)
g.map_diag(plt.hist)
g.map_upper(plt.scatter)
g.map_lower(sns.kdeplot)

[6]: <seaborn.axisgrid.PairGrid at 0x261e8f144a8>


138

Figura 74: Seaborn - Gráficos Variados - Pairgrid()

O pairplot() é uma versão mais simples do PairGrid().

[7]: sns.pairplot(iris)

[7]: <seaborn.axisgrid.PairGrid at 0x261e9a09400>


139

Figura 75: Seaborn - Gráficos Variados - Pairgrid()

[8]: sns.pairplot(iris,hue='species',palette='rainbow')

[8]: <seaborn.axisgrid.PairGrid at 0x261eb4730b8>


140

Figura 76: Seaborn - Gráficos Variados - pairgrid()

O FacetGrid() é a maneira geral de criar grades de gráficos com base em um recurso.

[9]: tips = sns.load_dataset('tips')

[10]: tips.head()

[10]: total_bill tip sex smoker day time size


0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

[11]: # Just the Grid


g = sns.FacetGrid(tips, col="time", row="smoker")
141

Figura 77: Seaborn - Gráfico FacetGrid()

[12]: g = sns.FacetGrid(tips, col="time", row="smoker")


g = g.map(plt.hist, "total_bill")
142

Figura 78: Seaborn - Gráfico FacetGrid()

[13]: g = sns.FacetGrid(tips, col="time", row="smoker",hue='sex')


# os argumentos aparecem após a chamada do plt.scatter
g = g.map(plt.scatter, "total_bill", "tip").add_legend()
143

Figura 79: Seaborn - Gráfico FacetGrid()

JointGrid() é a versão geral para grades do tipo jointplot.

[14]: g = sns.JointGrid(x="total_bill", y="tip", data=tips)


144

Figura 80: Seaborn - Gráfico JointGrid()

[15]: g = sns.JointGrid(x="total_bill", y="tip", data=tips)


g = g.plot(sns.regplot, sns.distplot)
145

Figura 81: Seaborn - Gráfico JointGrid()

6.6 Regressão: lmplot()


O Seaborn possui muitos recursos internos para gráficos de regressão, no entanto, não discuti-
remos realmente a regressão, pois já está fora do escopo do curso. Maiores informações podem
ser obtidas nos cursos de Machine Learning do Fit Tech Academy. Abordaremos apenas algumas
funções para visualização.

[1]: import seaborn as sns


%matplotlib inline

[2]: tips = sns.load_dataset('tips')

[3]: tips.head()
146

[3]: total_bill tip sex smoker day time size


0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

lmplot() permite exibir modelos lineares, mas também convenientemente permite dividir
esses gráficos com base nos recursos.

[4]: sns.lmplot(x='total_bill',y='tip',data=tips)

[4]: <seaborn.axisgrid.FacetGrid at 0x1d9e44d7198>

Figura 82: Seaborn - Gráfico lmplot()

[5]: sns.lmplot(x='total_bill',y='tip',data=tips,hue='sex')
147

[5]: <seaborn.axisgrid.FacetGrid at 0x1d9e4814550>

Figura 83: Seaborn - Gráfico lmplot()

[6]: sns.lmplot(x='total_bill',y='tip',data=tips,hue='sex',palette='coolwarm')

[6]: <seaborn.axisgrid.FacetGrid at 0x1d9e48b8f60>


148

Figura 84: Seaborn - Gráfico lmplot()

6.7 Formatação, estilos e cores


Por fim, podemos alterar outros parâmetros estéticos dos gráficos, como por exemplo as cores e
estilos dos objetos gráficos apresentados.

[1]: import seaborn as sns


import matplotlib.pyplot as plt
%matplotlib inline
tips = sns.load_dataset('tips')

6.7.1 Marcadores

Podemos customizar os marcadores no lmplot()co o parâmetro markers

[7]: # http://matplotlib.org/api/markers_api.html
sns.lmplot(x='total_bill',y='tip',data=tips,hue='sex',palette='coolwarm',
markers=['o','v'],scatter_kws={'s':100})

[7]: <seaborn.axisgrid.FacetGrid at 0x1d9e49330f0>


149

Figura 85: Seaborn - Gráfico lmplot() - Marcadores

6.7.2 Inserindo uma grade

Podemos tornar melhor a separação de variáveis através de colunas e linhas com o uso de uma
grade. Apenas indique isso com os argumentos col e/ou row.

[8]: sns.lmplot(x='total_bill',y='tip',data=tips,col='sex')

[8]: <seaborn.axisgrid.FacetGrid at 0x1d9e49ae9b0>


150

Figura 86: Seaborn - Gráfico lmplot() - Grade

[9]: sns.lmplot(x="total_bill", y="tip", row="sex", col="time",data=tips)

[9]: <seaborn.axisgrid.FacetGrid at 0x1d9e4a6a7f0>


151

Figura 87: Seaborn - Gráfico lmplot() - Grade

[10]: sns.
,→lmplot(x='total_bill',y='tip',data=tips,col='day',hue='sex',palette='coolwarm')

[10]: <seaborn.axisgrid.FacetGrid at 0x1d9e4ddc5c0>

Figura 88: Seaborn - Gráfico lmplot()

6.7.3 Proporção e tamanho

Seaborn pode ter seu tamanho e proporção ajustados com os parâmetros height e aspect:
152

[11]: sns.
,→lmplot(x='total_bill',y='tip',data=tips,col='day',hue='sex',palette='coolwarm',

aspect=0.6,height=8)

[11]: <seaborn.axisgrid.FacetGrid at 0x1d9e5378048>

Figura 89: Seaborn - Gráfico lmplot() - Proporção e tamanho

[2]: sns.countplot(x='sex',data=tips)

[2]: <matplotlib.axes._subplots.AxesSubplot at 0x2177b0b3048>

Figura 90: Seaborn - Gráfico countplot() - Estilo


153

[3]: sns.set_style('darkgrid')
sns.countplot(x='sex',data=tips)

[3]: <matplotlib.axes._subplots.AxesSubplot at 0x2177b3aa3c8>

Figura 91: Seaborn - Gráfico countplot() - Estilo grade

[4]: sns.set_style('dark')
sns.countplot(x='sex',data=tips,palette='deep')

[4]: <matplotlib.axes._subplots.AxesSubplot at 0x2177b445c18>


154

Figura 92: Seaborn - Gráfico countplot() - Estilo

[5]: sns.countplot(x='sex',data=tips)
sns.despine()

Figura 93: Seaborn - Gráfico countplot() - Estilo

[6]: sns.countplot(x='sex',data=tips)
sns.despine(left=True)
155

Figura 94: Seaborn - Gráfico countplot() - Estilo

É possível usar plt.figure(figsize = (largura, altura)) para alterar o tamanho


da maioria dos gráficos do Seaborn. Você também pode controlar o tamanho e a proporção da
maioria dos gráficos, transmitindo parâmetros: height e aspect.

[7]: # Non Grid Plot


plt.figure(figsize=(12,3))
sns.countplot(x='sex',data=tips)

[7]: <matplotlib.axes._subplots.AxesSubplot at 0x2177b5475c0>

Figura 95: Seaborn - Gráfico countplot() - Tamanho

[8]: # Grid Type Plot


sns.lmplot(x='total_bill',y='tip',height=2,aspect=4,data=tips)
156

[8]: <seaborn.axisgrid.FacetGrid at 0x2177b539438>

Figura 96: Seaborn - Gráfico lmplot() - Tamanho

O método set_context() permite substituir os parâmetros padrão.

[9]: sns.set_context('poster',font_scale=0.6)
sns.countplot(x='sex',data=tips,palette='coolwarm')

[9]: <matplotlib.axes._subplots.AxesSubplot at 0x2177b5e9c50>

Figura 97: Seaborn - Gráfico set_context() - Substituir parâmetros


157

7 Visualização com pandas

Vamos agora explorar os conceitos de dados em conjunto com ferramentas de visualização.

[1]: import numpy as np


import pandas as pd
%matplotlib inline

Vamos obter os dados de alguns arquivos .csv

[2]: df1 = pd.read_csv('df1',index_col=0)


df2 = pd.read_csv('df2')

df1.head()

[2]: A B C D
2000-01-01 1.339091 -0.163643 -0.646443 1.041233
2000-01-02 -0.774984 0.137034 -0.882716 -2.253382
2000-01-03 -0.921037 -0.482943 -0.417100 0.478638
2000-01-04 -1.738808 -0.072973 0.056517 0.015085
2000-01-05 -0.905980 1.778576 0.381918 0.291436

O primeiro passo em toda exploração de dados é obter um histograma para ter ideia da
distribuição dos dados.

[3]: df1['A'].hist()

[3]: <matplotlib.axes._subplots.AxesSubplot at 0x13f498c15c0>


158

Figura 98: Visualização Pandas - Histograma

Podemos mudar o estilo do gráfico com a função style.use()

[4]: import matplotlib.pyplot as plt


plt.style.use('ggplot')

[5]: df1['A'].hist()

[5]: <matplotlib.axes._subplots.AxesSubplot at 0x13f49c1e0b8>


159

Figura 99: Visualização Pandas - Histograma Estilo

[6]: plt.style.use('bmh')
df1['A'].hist()

[6]: <matplotlib.axes._subplots.AxesSubplot at 0x13f49c9ee48>

Figura 100: Visualização Pandas - Histograma Estilo


160

[7]: plt.style.use('dark_background')
df1['A'].hist()

[7]: <matplotlib.axes._subplots.AxesSubplot at 0x13f49cd67f0>

Figura 101: Visualização Pandas - Histograma Estilo

[8]: plt.style.use('fivethirtyeight')
df1['A'].hist()

[8]: <matplotlib.axes._subplots.AxesSubplot at 0x13f49d96da0>


161

Figura 102: Visualização Pandas - Histograma Estilo

[9]: plt.style.use('ggplot')

7.1 Tipos de gráficos


• df.plot.area
• df.plot.barh
• df.plot.density
• df.plot.hist
• df.plot.line
• df.plot.scatter
• df.plot.bar
• df.plot.box
• df.plot.hexbin
• df.plot.kde
• df.plot.pie

Você também pode utilizar df.plot(kind='hist') ou qualquer outro argumento que


faz referência ao tipo de gráfico ( 'box', 'barh', etc..)

[10]: df2.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
162

Data columns (total 4 columns):


a 10 non-null float64
b 10 non-null float64
c 10 non-null float64
d 10 non-null float64
dtypes: float64(4)
memory usage: 448.0 bytes

[11]: df2.head()

[11]: a b c d
0 0.039762 0.218517 0.103423 0.957904
1 0.937288 0.041567 0.899125 0.977680
2 0.780504 0.008948 0.557808 0.797510
3 0.672717 0.247870 0.264071 0.444358
4 0.053829 0.520124 0.552264 0.190008

[12]: df2.plot.area(alpha=0.4)

[12]: <matplotlib.axes._subplots.AxesSubplot at 0x13f49e26908>

Figura 103: Visualização Pandas - Estilo Gráfico 1

[13]: df2.plot.bar()
163

[13]: <matplotlib.axes._subplots.AxesSubplot at 0x13f49ebb780>

Figura 104: Visualização Pandas - Estilo Gráfico 2

[14]: df2.plot.bar(stacked=True)

[14]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4af50390>

Figura 105: Visualização Pandas - Estilo Gráfico 3


164

[15]: df1['A'].plot.hist(bins=50)

[15]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b003240>

Figura 106: Visualização Pandas - Estilo Gráfico 4

[16]: df1.head()

[16]: A B C D
2000-01-01 1.339091 -0.163643 -0.646443 1.041233
2000-01-02 -0.774984 0.137034 -0.882716 -2.253382
2000-01-03 -0.921037 -0.482943 -0.417100 0.478638
2000-01-04 -1.738808 -0.072973 0.056517 0.015085
2000-01-05 -0.905980 1.778576 0.381918 0.291436

[17]: df1.plot.line(y='B',figsize=(12,3),lw=1)

[17]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b003828>


165

Figura 107: Visualização Pandas - Estilo Gráfico 5

[18]: df1.plot.scatter(x='A',y='B')

[18]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b1b3080>

Figura 108: Visualização Pandas - Estilo Gráfico 6

Você pode alterar a cor com o parâmetro c ou usar cmap para um mapa de cores.

[19]: df1.plot.scatter(x='A',y='B',c='C',cmap='coolwarm')

[19]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b23d160>


166

Figura 109: Visualização Pandas - Estilo Gráfico 7

Também é possivel mapear valores numéricos no tamanho do marcadadores com o parâ-


metro s, o qual deve receber os valores de uma coluna com dados numéricos.

[20]: df1.plot.scatter(x='A',y='B',s=df1['C']*50)

C:\Users\jagapadi\AppData\Local\Continuum\anaconda3\envs\jupyter\lib\site-
packages\matplotlib\collections.py:857: RuntimeWarning: invalid value
encountered in sqrt
scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor

[20]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b300320>


167

Figura 110: Visualização Pandas - Estilo Gráfico 8

[21]: df2.plot.box() # Can also pass a by= argument for groupby

[21]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b350128>

Figura 111: Visualização Pandas - Estilo Gráfico 9

hexbin() é uma alternativa para dados bivariados.


168

[22]: df = pd.DataFrame(np.random.randn(1000, 2), columns=['a', 'b'])


df.plot.hexbin(x='a',y='b',gridsize=25,cmap='Oranges')

[22]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b41d0f0>

Figura 112: Visualização Pandas - Estilo Gráfico 10

Kernel Density Estimation (KDE) é uma estimativa da distribuição da variável, cujo gráfico
é obtido de kde()

[23]: df2['a'].plot.kde()

[23]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4b4d69e8>


169

Figura 113: Visualização Pandas - Estilo Gráfico 11

[24]: df2.plot.density()

[24]: <matplotlib.axes._subplots.AxesSubplot at 0x13f4d19eac8>

Figura 114: Visualização Pandas - Estilo Gráfico 12


170

7.2 Exercícios Extras


Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta.

[1]: import pandas as pd


import matplotlib.pyplot as plt
df3 = pd.read_csv('df3')
%matplotlib inline

[2]: df3.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 500 entries, 0 to 499
Data columns (total 4 columns):
a 500 non-null float64
b 500 non-null float64
c 500 non-null float64
d 500 non-null float64
dtypes: float64(4)
memory usage: 15.8 KB

[3]: df3.head()

[3]: a b c d
0 0.336272 0.325011 0.001020 0.401402
1 0.980265 0.831835 0.772288 0.076485
2 0.480387 0.686839 0.000575 0.746758
3 0.502106 0.305142 0.768608 0.654685
4 0.856602 0.171448 0.157971 0.321231

1. Obtenha um scatter plot das variáveis a e b.

[ ]:

2. Crie um histogram da coluna a.

[ ]:

3. Crie um boxplot para comparar as colunas a e b.

[ ]:
171

4. Crie um kde plot da coluna d.

[ ]:

5. Crie um gráfico utilizando apenas as 30 primeiras linhas. (dica: use ix).

[ ]:
172

7.3 Exercícios Extras Resolvido


1. importe os dados do arquivo df3

[5]: import pandas as pd


import matplotlib.pyplot as plt

%matplotlib inline

[9]: df3 = pd.read_csv('df3')

df.head()

[9]: a b c d
0 0.336272 0.325011 0.001020 0.401402
1 0.980265 0.831835 0.772288 0.076485
2 0.480387 0.686839 0.000575 0.746758
3 0.502106 0.305142 0.768608 0.654685
4 0.856602 0.171448 0.157971 0.321231

[10]: df.describe()

[10]: a b c d
count 500.000000 500.000000 500.000000 500.000000
mean 0.485294 0.504049 0.506183 0.517390
std 0.290985 0.272966 0.295953 0.293166
min 0.000410 0.010649 0.000575 0.002851
25% 0.225024 0.270928 0.243931 0.281738
50% 0.479164 0.510915 0.507474 0.533044
75% 0.755088 0.728839 0.769660 0.788106
max 0.998111 0.996740 0.999709 0.989946
173

2. Obtenha um scatter plot das variáveis a e b

[11]: df3.plot.scatter(x='a', y='b', c='c', cmap='afmhot_r', figsize=(10, 10),␣


,→s=df3['c'].apply(lambda x : x ** 2)*50)

[11]: <AxesSubplot:xlabel='a', ylabel='b'>

3. Crie um histogram da coluna a

[12]: df3['a'].plot.hist(bins=20)

[12]: <AxesSubplot:ylabel='Frequency'>
174

4. Crie um boxplot para comparar as colunas a e b.

[13]: df3[['a', 'b']].plot.box()

[13]: <AxesSubplot:>
175

5. Crie um kde plot da coluna d

[14]: df3['d'].plot.kde()
df3['d'].plot.hist(density=True, bins=15)

[14]: <AxesSubplot:ylabel='Frequency'>

6. Crie um gráfico utilizando apenas as 30 primeiras linhas. (dica: use df3.iloc).

[15]: df3.iloc[-30:].plot.hexbin(x='a', y='b', C='c', gridsize=10,␣


,→cmap='Oranges', figsize=(12,10))

[15]: <AxesSubplot:xlabel='a', ylabel='b'>


176
177

8 Avaliação 2 - Matplotlib e Seaborn

8.1 Exercícios Avaliativo Matplotlib


Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta.

1. Importe as bibliotecas necessárias.

[37]:

2. Crie os dados e plote-os em um objeto axes. Ajuste os rótulos e o título do gráfico.

[ ]:

3. Crie um objeto do tipo figure e coloque dois axes no mesmo, localizados em [0, 0, 1, 1] e
[0.2, 0.5, .2, .2]. Então plote os mesmos dados em ambos.

[ ]:

4. Crie dois gráficos em um mesmo figure.

[ ]:
178

8.2 Exercícios Avaliativo Seaborn


Apenas deve-se colocar o enunciado na plataforma, sem campo de resposta.

Primeiramente importamos as bibliotecas e os dados necessários. Vamos utilizar o conjunto


de dados dos passageiros do navio Titanic.

[ ]: import seaborn as sns


import matplotlib.pyplot as plt
%matplotlib inline

[ ]: sns.set_style('whitegrid')

[ ]: titanic = sns.load_dataset('titanic')

[ ]: titanic.head()

1. Obtenha um jointplot das variáveis fare e age.

[ ]:

2. Obtenha um distplot da variável fare.

[ ]:

3. Exiba um boxplot com os seguintes parâmetros: x='class' e y='age'.

[ ]:

4. Exiba um swarmlot com os seguintes parâmetros: x='class' e y='age'.

[ ]:

5. Exiba um countplot da variável sex.

[ ]:

6. Obtenha o heatmap do conjunto de dados.

[ ]:

7. Mostre um FacetGrid com dois histogramas das idades, um para cada sexo.

[ ]:
179

9 Categoria das Notas


Tabela 2: Categoria das notas

CATEGORIAS
IDENTIFICADOR DESCRIÇÃO
NOME CONTEÚDO DAS SEÇÕES 1, 2 e 3
PESO 60% DA NOTA
QUANTIDADE DE PERGUNTAS E RESPOSTAS 1

NOME CONTEÚDO DAS SEÇÕES 5, 6 e 7


PESO 40% DA NOTA
QUANTIDADE DE PERGUNTAS E RESPOSTAS 1
180

10 Conclusão

Obrigado por chegar ao final do nosso curso! Esperamos vocês nos próximos cursos, onde
veremos algoritmos mais complexos e aplicações mais próximos do estado da arte em Inteligência
Artificial, visão computacional e processamento de linguagem natural.

Gostaria de agradecer ao Davi Lobo de Melo autor da primeira versão dessa apostila.
181

Referências
[1] Anaconda. https://www.anaconda.com/, 2021. Acessado: 21-09-2021.

[2] Collaboratory. https://research.google.com/colaboratory/, 2021. Acessado: 21-


09-2021.

[3] Kaggle. https://www.kaggle.com, 2021. Acessado: 21-09-2021.

[4] Kaggle - SF Salaries. https://www.kaggle.com/kaggle/sf-salaries, 2021. Aces-


sado: 21-09-2021.

[5] Matplotlib. https://matplotlib.org/, 2021. Acessado: 21-09-2021.

[6] Medium. https://medium.com/, 2021.

[7] NumPy. https://numpy.org/doc/, 2021. Acessado: 21-09-2021.

[8] Pandas. https://pandas.pydata.org/docs/, 2021. Acessado: 21-09-2021.

[9] Programiz. https://www.programiz.com/python-programming, 2021. Acessado: 21-


09-2021.

[10] Seaborn. https://seaborn.pydata.org/, 2021. Acessado: 21-09-2021.

[11] Tiobe. https://www.tiobe.com/tiobe-index/, 2021. Acessado: 21-09-2021.

[12] Udemy. https://www.udemy.com/, 2021. Acessado: 21-09-2021.

[13] W3schools. https://www.w3schools.com/python/default.asp, 2021. Acessado: 21-


09-2021.
182

11 Controle de revisão do documento

Revisão Descrição Razão Autor Data


Review Description Reason Author Date
A - Revisão inicial Larissa Alves 29/09/21
B Alteração de logotipia do ro- Revisão do mo- Adson Alves 01/07/22
dapé do documento delo do formulá-
rio FITF.24.1.01-
04Rev. B

Você também pode gostar