Open In Colab

Básico: Colab, Python, NumPy e Pandas


Para uma introdução à visualização de dados com Python é esperado que você tenha alguma familiaridade com linguages de programação, Python e mesmo alguns pacotes como o NumPy e o Pandas. Isso é essencial se você estiver fazendo a trilha de programação de leitura deste livro. De qualquer modo, cobriremos aqui os principais recursos e funções do Python, NumPy e Pandas que empregaremos neste livro e você pode recorrer à documentação ou outras referências online desses pacotes para maiores detalhes. Há também uma introdução ao ambiente Google Colab que empregamos para criar este livro e que você pode empregar para executar e explorar os códigos aqui apresentados.

Caso você já domine ou esteja confortável com esses recursos você pode pular este capítulo e seguir para o próximo.

Ambiente Google Colaboratory ou Colab

O Google Colaboratory ou Colab é um ambiente que permite você escrever código Python diretamente em seu navegador, sem nenhuma configuração ou instalação de software, e que ainda fornece acesso a recursos para processamento e compartilhamento fácil de código (GitHub, Google Drive etc.). Para acesso a esse ambiente basta você entrar no seu navegador https://colab.research.google.com/.

Python Notebooks

Python notebooks (ou Jupyter notebooks) combinam em um único documento código executável, texto e saídas dos programas e podem incluir imagens, HTML e até textos $\LaTeX$. Em um ambiente interativo, como o Colab, você pode editar os códigos e textos, e executar os programas produzindos as saídas no próprio documento. É uma forma bastante útil de criar e publicar códigos e todo o material deste livro foi criado em Python notebooks para que você possa reproduzir e alterar os códigos que são fornecidos.

Se você estiver acessando um Python notebooks, aqui está uma célula de código com um breve script Python que você poderá executar calculando um valor, armazenando-o em uma variável e exibindo em seguida o resultado:

In [ ]:
segundos_do_dia = 24 * 60 * 60
segundos_do_dia
Out[ ]:
86400

Células de Código

As células de código podem conter qualquer script ou conjunto de comandos Python.

In [ ]:
# imports
import numpy as np
import matplotlib.pyplot as plt

cores = 'rgbcmyk'
label = ['red','green','blue','cyan','magenta','yellow','black']

# 'input' não suportado para edição de JupyterBooks, comente e tire os comentários conforme indicado para execução no Colab

# n = int( input('Entre com um número inteiro: ') )  # Tire o comentário
n = 12                                               # Comente aqui

cor = n % len(cores)

x = 200 + np.random.randn(100)
plt.plot(x,color=cores[cor])

plt.title(label[cor].upper(),fontsize=14)
plt.show()

$\bigstar \text{ }$ Alerta importante: ao trabalhar com um Python notebook todas as células compartilham o mesmo espaço de execução. Assim as variáveis de criadas e alteradas em uma célula são imediatamente acessíveis a todas as demais células. Independente da ordem em que aparecem.

As células de código não são programas independentes e seus resultados persistem após cada execução. Como você pode executar qualquer célula a qualquer momento a ideia execução sequencial do programa é aqui um pouco modificada.

In [ ]:
x = np.random.randint(10) # gera um valor aleatório entre 0 e 100
In [ ]:
# Você pode executar essa célula uma vez, mas ganhará um erro ao executá-la novamente
print(x) 
del x
3

Células de Texto

As células de texto são criadas em formato Markdown. Se você estiver empregando o Colab pode clicar duas vezes no texto para editar uma célula e empregar barra de ferramentas para formatar o texto ou, se estiver mais familiarizado com a notação Markdown, pode escrever diretamente a formatação.

Formatando Títulos


### **Título 3**
#### **Título 4**
##### **Título 5**

Produz:

Título 3

Título 4

Título 5

Formatando Textos


**bold**

*italic*

Produz:

bold

italic

Identação


'>' (ident) não suportado para edição de JupyterBooks, tire os comentários ``` para execução no Colab.

> indent 1

>> indent 2

Formatando Listas


* item  
* item
* item
ou
1. item 1
2. item 2
3. item 3

Produz:

  • item
  • item
  • item ou
  1. item 1
  2. item 2
  3. item 3

Você ainda pode editar textos em formato HTML ou $\LaTeX$ e para saber mais você pode explorar a barra de ferramentas do Colab ou consultar os tutoriais disponíveis do Colab.

Salvando e abrindo um Colab notebook

Seus Python notebooks podem ser salvos no seu Google Drive ou ainda no GitHub. Eu dou preferência por usar o GitHub e lá você poderá acessar os códigos deste livro. Se empregar o Google Drive tenha em mente que as alterações do seu notebook são salvas automaticamente enquanto você edita. Se você não tem familiaridade com esses ambientes recomendo que você empregue a opção Arquivo > na barra de ferramentas para carregar e salvar seu notebooks em um arquivo .ipynb.

  • Arquivo > Fazer download > Fazer download do .ipynb
  • Arquivo > Fazer upload de um notebook

Python notebook $\times$ IDE's

O uso de Python notebooks é de fácil acesso, compartilha em um só documento código, texto e as saídas dos programas, e facilita o trabalho colaborativo permitindo o compartilhamento de código na internet (Google Drive, GitHub). É uma opção bastante aplicada para Ciência de Dados e vem sendo a opção preferencial para aplicações no ensino e, por isso, empregamos ela aqui em todo o desenvolvimento do texto.

Projetos mais complexos, com vários programas e programas com centenas de linhas de código, podem entretanto exigir o uso de ambientes integrados de desenvolvimento (IDE's) como o PyCharm, Visual Code ou o Spyder para maior produtividade. Note que scripts Python e Python notebooks são arquivos criados com extensões diferentes:

  • notebooks Python, extensão .ipynb
  • scripts Python, extensão .py

Caso você opte em explorar os códigos deste livro em um ambiente Python local recomendo a instalação do ambiente Anaconda, um eco sistema profissional de desenvolvimento Python que inclui, além da linguagem Python ambientes para edição de notebooks local e o IDE Spyder dentre outros pacotes, e você pode encontrar os links para download no final do livro.

Python

Python é uma linguagem bastante poderosa e com muitos recursos. Nessa introdução de Python vamos apenas apresentar um conjunto de recursos essenciais para que possamos prosseguir na visualização de dados com Python e você pode consultar diversas fontes online e livros de introdução ao Python para saber mais sobe a linguagem.

Imports básicos

Os import de bibliotecas permite estender o Python adicionando as funcionalidades de uma biblioteca ou pacote Python. Para nós os seguintes imports serão suficientes para a maior parte deste livro.

In [ ]:
import pandas as pd                  # Pandas para acesso e manipulação de dados
import numpy as np                   # NumPy para operações de vetores e matrizes numéricas (arrays)
import matplotlib.pyplot as plt      # Bibliotecas de gráficos e visuallização de dados
import matplotlib as mpl
# import seaborn as sns
%matplotlib inline

Variáveis e Atribuições

O Python implementa tipos fracos, isto é, você não precisa declarar uma variável antes de empregá-la. Ele será criada e seu tipo definido automaticamente na primeira atribuição a um rótulo (nome da variável).

In [ ]:
inteiro = 123
real = np.pi
texto1 = '123'
texto2 = 'Led Zeppelin'

print(type(inteiro), inteiro)
print(type(real), real)
print(type(texto1), texto1)    
print(type(texto2), texto2)  
<class 'int'> 123
<class 'float'> 3.141592653589793
<class 'str'> 123
<class 'str'> Led Zeppelin

Caracteres e Valores Numéricos

O Python implementa valores numéricos inteiros e de ponto flutuante com as operações básicas, e cadeias de caracteres (strings).

In [ ]:
inteiro = inteiro + 1
real = real + 1
texto1 = texto1 + '4'
texto2 = texto2 + ': Stairway to Heaven'

print(type(inteiro), inteiro)
print(type(real), real)
print(type(texto1), texto1)    
print(type(texto2), texto2)  

# edição de valores no estilo C com controles de linha e formatação
print(inteiro, '\n', '\t'*4 , texto2)          
print('Valor real {:0.2f}'.format(real))
<class 'int'> 124
<class 'float'> 4.141592653589793
<class 'str'> 1234
<class 'str'> Led Zeppelin: Stairway to Heaven
124 
 				 Led Zeppelin: Stairway to Heaven
Valor real 4.14

Integer, Float-point, Boolean

In [ ]:
print(3 * 4, 3 + 4, 3 - 4, 3 / 4, 3.14, 4.2e-4 ) 
print(type(3 * 4), type(3.14), type(4.2e-4) ) 
print(3 ** 2, 3 // 4, 3 % 4 )                       # potência, divisão inteira e resto da divisão (mod)
print(4 > 3, 4 >= 3, 3 == 3.0, 3 != 4, 3 <= 4 )
print(1 < 2 < 9)                                    # boolean
12 7 -1 0.75 3.14 0.00042
<class 'int'> <class 'float'> <class 'float'>
9 0 3
True True True True True
True

NumPy functions

As funções básicas estão disponíveis nativamente, mas para muitas funções matemáticas como funções trigonométricas, randomização e constantes como o $\pi$ e $e$ é necessário recorrer a bibliotecas numéricas como o NumPy ou math e, em geral, empregaremos o NumPy.

In [ ]:
import numpy as np
              
print(np.pi)            # pi 
print(np.exp(1))        # e

print(5 % 2)
# o mesmo que
print(np.mod(5,2))

print(np.random.rand(1))
print(np.random.sample(10))
3.141592653589793
2.718281828459045
1
1
[0.11077583]
[0.70828206 0.98569622 0.41165035 0.07971794 0.6341663  0.34175151
 0.68575985 0.38810094 0.32550541 0.60233199]

Strings

As strings em Python são como arrays de caracteres. Em Python elas são estruturas imutáveis, isto significa que você não poderá atribuir um valor a uma posição específica de um array em uma string.

A indexação de slices de strings é feita do seguinte modo:

str[ inicio : tamanho ] ou str[ inicio : fim+1 ]

$\bigstar \text{ }$ As strings iniciam são arrays que iniciam em 0. Em Python o limite superior indica um valor $<$ do índice do caracter que será exibido e não um índice $\le$ como em outras linguagens como C ou Java.

In [ ]:
print(texto2[0:7])
print('0123456789012'[0:7])

# e, 

# texto2[1] = 'x'
# não funciona uma vez que uma string é imutável em Python
Led Zep
0123456

Operações com Strings

As operações com strings são implementadas como métodos da classe string. Empregue o comando help(str) para listar os métodos da classe string, ou dir(var) para os métodos de uma variável. Não faremos grandes operações com strings de dados aqui e os métodos essenciais que precisamos encontram-se abaixo.

In [ ]:
str1 ='A arte existe porque a vida não basta. – Ferreira Gullar'

print(str1.find('arte'))
print(str1.lower())

str2 = str1.replace('arte','life')
print(str2)
2
a arte existe porque a vida não basta. – ferreira gullar
A life existe porque a vida não basta. – Ferreira Gullar

O comando input permite a entrada de dados pelo terminal mesmo na execução de Python notebooks. O print exibe a saída de caracteres e emprega caracteres de controle como \n para salto de linha, \t para tab etc. bem como a formatação de valores ao estilo da linguagem C.

In [ ]:
# Print & Input...

# 'input' não suportado para edição de JupyterBooks, comente e tire os comentários conforme indicado para execução no Colab

# text = input('Entre com um texto: ')  # Tire o comentário aqui
text = 'Texto'                          # Comente aqui
print(type(text))

# numero = float(input('Entre com um número: '))  # Tire o comentário aqui
numero = 2.25                                     # Comente aqui

print('Seu texto: ', text, '\n', 'Seu número: ', '%0.2f'%numero)
Entre com um texto: Texto
<class 'str'>
Entre com um número: 2.25
Seu texto:  Texto 
 Seu número:  2.25

Controles de Fluxo nos Programa

If-Then-Else

Em Python as instruções aninhadas são identadas (tab), o que corresponde ao {} de linguagens como Java e C. Assim, instruções aninhadas à condição ou laço do programa devem estar à direita da instrução inicial da condição ou laço.

Condição 1 ...
 Instrução 1.1 ...
 Instrução 2.1 ...
 Condição 2 ...
   Instrução 2.1 ...

 Instrução 3.1...

Instrução N

Instrução 3.1 executará dentro da condição 1, mas fora da condição 2.

In [ ]:
a = 1964
b = 1984
if b > a:
  print("b is greater than a")
else:
  print("a is greater than b")  

if b > a:
  print("b is greater than a")
elif a == b:
  print("a and b are equal")
else:
  print("a is greater than b")
b is greater than a
b is greater than a

$\bigstar \text{ }$ Fique atento a identação do seu código. Em Python é ela que faz o aninhamento de instruções de código, tendo assim o mesmo papel dos { } que empregamos em Java ou C.

For & While

For e While empregados para implementar loops ou laços nos programas. Neste livro na maior parte dos casos empregaremos o for para criar laços de programa. O comando range(inicio, fim, incremento) pode ser empregado para definir os limites e o incremento de uma variável em um laço do tipo for. Do mesmo modo que na indexação de strings o limite indicado é um limite superior ($<$ e não $\le$) e, portanto, o último valor que nunca é atingido.

In [ ]:
for i in range(5): 
  print(i)
  if i == 3:
    break
In [ ]:
i = 1
while i < 6:
  print(i)
  if i == 3:
    break
  i += 1

As iterações também podem ser feitas sobre listas de valores, numéricos ou não.

In [ ]:
for i in [12,18,84]:
  print(i)

for nome in ['Adriana','Daniel','Henrique']:
  print(nome)    
12
18
84
Adriana
Daniel
Henrique

Funções

Funções em Python são definidas com a instrução def. As variáveis de uma função tem escopo local, mas as funções podem também acessar variáveis globais do seu programa.

In [ ]:
def mymax(a,b):
  if a > b:
    return a
  else:
    return b

mymax(1984,1964)
Out[ ]:
1984

Coleções de Dados Básicas

Coleções de dados como Lists, Sets, Tuples e Dictionary desempenham um papel importante tanto para a programação em geral como para aplicações de análise de dados.

O Python implementa quatro tipos básicos de coleções de dados:

  • Lista (list( ), [ ]) é uma coleção que é ordenada e mutável podendo ter membros duplicados.
  • Tupla (tuple( ), ( )) é uma coleção que é ordenada e imutável podendo ter membros duplicados.
  • Conjunto (set( ), { }) é uma coleção não ordenada e não indexada que não permite membros duplicados.
  • Dicionário (dict( ), {'key':value} ) é uma coleção desordenada de itens, mutável e indexada, e que não permite membros duplicados.

Vamos nos deter apenas nas estruturas de listas e dicionários que terão mais utilidade aqui.

List

Lista (list) é uma coleção que é ordenada e mutável, e permite haver membros duplicados. Associado a listas você encontra uma série métodos úteis para esses objetos como adição, busca e remoção de elementos.

In [ ]:
mylist = ['A', 'B', 'C', 'A', 'B']

'''
Empregue...
> help(mylist) 
para ver todos os métodos associados a listas

Help on list object:
 | class list(object)
 |  list(iterable=(), /)
 |  
 |  Built-in mutable sequence.
 |  
 |  If no argument is given, the constructor creates a new empty list.
 |  The argument must be an iterable if specified.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 
'''
In [ ]:
# Métodos comuns associados a listas
len(mylist)                     # tamanho

print(mylist.count('B'))        # quantos 'B's      
print(mylist.index('B'))        # índice do primeiro 'B'   
print(mylist.index('B', 2))     # índice do primeiro 'B' a partir do índice 2

mylist.append('D')               
print(mylist, 'depois de inserir D')

mylist.sort()  
print(mylist, 'depois de ordenar a lista')

mylist[1] = 'ZZ'
print(mylist, 'depois de alterar o elementos de índice 1')

print('A' in mylist)      
if 'A' in mylist:
  print('Sim, A está na lista')
2
1
4
['A', 'B', 'C', 'A', 'B', 'D'] depois de inserir D
['A', 'A', 'B', 'B', 'C', 'D'] depois de ordenar a lista
['A', 'ZZ', 'B', 'B', 'C', 'D'] depois de alterar o elementos de índice 1
True
Sim, A está na lista

Listas podem conter quaisquer tipos de elementos, incluindo outras listas, e podem ser empregadas para implementar arrays numéricos em Python. Entretanto, para operações eficientes sobre arrays numéricos será preferível empregar arrays do pacote NumPy.

$\bigstar \text{ }$ Para operações eficientes sobre arrays numéricos é preferível empregar arrays do pacote NumPy.

In [ ]:
# Arrays numéricos
mylist = [[1,2,3], [11,22,33], [9,9,9]]
print(mylist[1])  # [11,22,33]
print(mylist[1][0])  # 11

# Arrays de quaisquer tipos de dados
print([ [1,2,3], ['Adriana','Daniel','Henrique'], 3, 'Anna', 2.5 ])
[11, 22, 33]
11
[[1, 2, 3], ['Adriana', 'Daniel', 'Henrique'], 3, 'Anna', 2.5]

Percorrendo listas

Percorrer listas é uma operação que empregaremos bastante. Existem basicamente duas forma de percorrer uma lista.

  • Por índice, empregamos essa forma quando precisamos do índice (posição) ou precisamos alterar os elementos da lista

  • Por iterador, empregamos essa forma quando desejamos apenas recuperar (ler) os elementos. Ela não permite alterar os elementos enquanto percorremos a lista

A segunda forma é um modo elegante que o Python implementa e você não encontrará esse modo em linguagens como C ou Java. Se não for necessário alterar os elementos ou obter o índice ao percorrer a lista esta será a melhor forma a ser empregada.

In [ ]:
mylist = ['A', 'B', 'C', 'A', 'B']
 
for i in range(len(mylist)):    # empregue esse modo para obter o índice ou alterar os elementos ao percorrer a lista
    print(i, mylist[i])

for item in mylist:             # prefira esse modo se não precisar do índice ou alterar os elementos ao percorrer a lista
    print(item) 
    
   
0 A
1 B
2 C
3 A
4 B
A
B
C
A
B

Também é útil entendermos como popular uma lista com o método append().

In [ ]:
mylist = []                                                   # cria a lista vazia 
 
for elem in ['Beatriz', 'Henrique', 'Adriana', 'Daniel']:
    mylist.append(elem)                                       # adiciona um elemento no final da lista

print(mylist)

  
['Beatriz', 'Henrique', 'Adriana', 'Daniel']

Dictionary

Dicionários (dictionary) são uma coleção desordenada, mutável e indexada em formato de chave: valor. Elas não aceitam elementos duplicados (chaves), e se você já teve contato com uma estrutura de dados do tipo JSON essa é uma estrutura bastante semelhante em Python. A principal vantagem dos dicionários é permitir recuperar os valores diretamente a partir do valor da chave.

In [ ]:
aniversarios = {'Beatriz':1978, 'Henrique':2004, 'Adriana':1984, 'Daniel':1996} 
  
print(aniversarios.keys())
print(aniversarios['Adriana'])   
dict_keys(['Beatriz', 'Henrique', 'Adriana', 'Daniel'])
1984

Assim como nas listas, os dicionários suportam quaiquer tipos de dados no campo valor, incluindo listas e outros dicionários.

In [ ]:
contatos = { 'Adriana': { 'aniversario': 1984, 'telefone': '6767-6868' , 'amigos': {'Henrique':2004, 'Anna':1988} } }

print(contatos.keys())
print(contatos['Adriana'])             
print(contatos['Adriana']['amigos'])   
dict_keys(['Adriana'])
{'aniversario': 1984, 'telefone': '6767-6868', 'amigos': {'Henrique': 2004, 'Anna': 1988}}
{'Henrique': 2004, 'Anna': 1988}

Percorrendo um Dicionário

Podemos percorrer os elementos de um dicionário de diversas formas que combinam percorrer as chaves, os valores ou ambos:

In [ ]:
for key, item in aniversarios.items():
    print(key, item)
# ou
for item in aniversarios:
    print(item, aniversarios[item])    
# ou      
for key in aniversarios.keys():
    print(key)   
# ou      
for item in aniversarios.values():
    print(item)   
Beatriz 1978
Henrique 2004
Adriana 1984
Daniel 1996
Beatriz 1978
Henrique 2004
Adriana 1984
Daniel 1996
Beatriz
Henrique
Adriana
Daniel
1978
2004
1984
1996

Populando um Dicionário

Diferente das listas os dicionários não têm um método próprio para adição de uma chave ou valor, e basta fazer uma atribuição ao dicionário.

In [ ]:
lista_nomes = [ 'Carolina', 'Henrique' ]
lista_niver = [ 2001, 2005 ]

mydict = {}

for i in range(len(lista_nomes)): 
  if lista_nomes[i] not in mydict.keys(): # Se não está no dicionário acrescenta
    mydict[lista_nomes[i]] = lista_niver[i]

if 'Kate' not in mydict.keys():           # Se não está no dicionário acrescenta
  mydict['kate'] = 2002

print(mydict)
{'Carolina': 2001, 'Henrique': 2005, 'kate': 2002}

$\bigstar \text{ }$ Note que [ ] é o construtor de uma lista, e o mesmo que list(), enquanto { } é o construtor de um dicionário, o o mesmo que dict(). Ambos, entretanto, têm os elementos referenciados empregando [ ].

File Handling

Operações com arquivos tipo texto terão pouco uso aqui. Na maior parte dos casos obtemos dados de tabelas e bases de dados em DataFrames Pandas. De qualquer modo isso pode ser útil para você em algum caso e um exemplo simples de gravação e leitura deve bastar.

In [ ]:
note = ['This is a note'] 

f = open("note.txt", "w") 
for line in note:
    f.write(line)
f.close()

f = open("note.txt", "r")
for line in f:
    print(line)
    
This is a note

Para acesso a arquivos tipo texto via internet, que não estão locais em um diretório da sua máquina ou ambiente virtual como o Colab, você pode empregar a classe urllib.request ou, se tiver familiaridade com comando Linux, o comando !wget para fazer o download do arquivo e empregá-lo local como fizemos acima.

In [ ]:
import urllib.request  

data = urllib.request.urlopen('https://raw.githubusercontent.com/Rogerio-mack/Visualizacao-de-Dados-em-Python/main/data/PlayBallcsv.csv')

for line in data:
    print(line.decode('utf-8'))
    break
Day,Outlook,Temperature,Humidity,Wind,Play ball


NumPy

O NumPy é um pacote para computação científica em Python que dá suporte para arrays e matrizes multidimensionais e faz operações e funções matemáticas de modo eficiente.

Na maior parte dos casos empregaremos as funções matemáticas do NumPy como operações para manipulação de matrizes e vetores, funções trigonométricas, estatísticas e de randomização. O Pandas, pacote de manipulação de dados que empregamos, é construído sobre o NumPy.

Teremos necessidade aqui de entender apenas algumas poucas classes de NumPy e, assim, um pequeno conjunto de exemplos será suficiente para nossos propósitos.

Criando arrays

Os arrays podem ser de uma ou mais dimensões mas, diferentemente das listas, e como matrizes numéricas, todos elementos devem ter o mesmo tamanho e tipo. Eles também são indexados iniciando por 0 e seguem as mesmas regras de indexação de listas e strings, isto é, o limite superior indica o limite $<$ do range de valores a ser selecionado.

In [ ]:
import numpy as np

array1D = np.array([1,2,3])
array2D = np.array([[1,2,3,4],[11,12,13,14],[21,22,23,24]])

print(array1D.ndim, array2D.ndim) # dimensões
print(array1D.shape, array2D.shape) # tamanho de cada dimensão

print(array1D)
print(array2D)

print(array1D[1])
print(array2D[1:3])
print(array2D[1][3])
1 2
(3,) (3, 4)
[1 2 3]
[[ 1  2  3  4]
 [11 12 13 14]
 [21 22 23 24]]
2
[[11 12 13 14]
 [21 22 23 24]]
14

Os arrays NumPy operam como listas indexadas e você pode empregar as mesmas formas de índices e iteração que empregamos em listas para percorrer arrays NumPy.

In [ ]:
for i in range(array1D.shape[0]):    
    print(i, array1D[i])

for i in range(array2D.shape[0]):       # percorre as linhas 
  for j in range(array2D.shape[1]):     # percorre as colunas      
    print(i, j, array2D[i,j])

for elem in array1D:    
    print(elem)

for linha in array2D:                   # percorre as linhas 
  for coluna in linha:                  # percorre as colunas      
    print(coluna)
0 1
1 2
2 3
0 0 1
0 1 2
0 2 3
0 3 4
1 0 11
1 1 12
1 2 13
1 3 14
2 0 21
2 1 22
2 2 23
2 3 24
1
2
3
1
2
3
4
11
12
13
14
21
22
23
24

Operações sobre arrays NumPy

Um dos recursos mais úteis do NumPy que não encontramos em arrays de outras linguagens como C e Java é que diversas operações podem ser executadas diretamente sobre toda a coleção de dados sem a necessidade de implementar iterações ou laços de programa.

In [ ]:
x = np.array([1,2,3])
print( np.mean(x), np.sum(x), np.power(x,2) )
print( 2*x, x+x, x**2 + 2*x + 1, np.log(x) )
2.0 6 [1 4 9]
[2 4 6] [2 4 6] [ 4  9 16] [0.         0.69314718 1.09861229]

Outras Operações Úteis

Finalmente, abaixo, algumas operações de conversão, randomização e criação de sequencias de valores serão muito úteis e empregadas ao longo de todo o livro.

In [ ]:
x = np.array([1,2,3])

x_list = x.tolist()  # convertendo um NumPy array para uma lista `Python`
print(x, x_list)

np.random.seed(1984)                                    # semente de geração aleatória 
print( np.random.randint(low=1, high=6, size=10) )      # gerando inteiros aleatórios
print( np.random.rand(4) )                              # gerando valores aleatórios entre [0,1]
print( np.random.sample(5) )                            # gerando um sample de dados aleatórios

print( np.arange( 10, 20, 2) )     # gerando uma lista de valores no intervalo [10,20[ com incrementos de 2 

print( np.linspace( 10, 20, 50) )  # gerando uma lista de valores de 50 valores no intervalo [10,20[
[1 2 3] [1, 2, 3]
[5 4 2 1 1 3 3 2 3 1]
[0.99873856 0.89441845 0.26139183 0.73330439]
[0.14629798 0.17234917 0.61481704 0.59564882 0.68232631]
[10 12 14 16 18]
[10.         10.20408163 10.40816327 10.6122449  10.81632653 11.02040816
 11.2244898  11.42857143 11.63265306 11.83673469 12.04081633 12.24489796
 12.44897959 12.65306122 12.85714286 13.06122449 13.26530612 13.46938776
 13.67346939 13.87755102 14.08163265 14.28571429 14.48979592 14.69387755
 14.89795918 15.10204082 15.30612245 15.51020408 15.71428571 15.91836735
 16.12244898 16.32653061 16.53061224 16.73469388 16.93877551 17.14285714
 17.34693878 17.55102041 17.75510204 17.95918367 18.16326531 18.36734694
 18.57142857 18.7755102  18.97959184 19.18367347 19.3877551  19.59183673
 19.79591837 20.        ]

Pandas

O Pandas é um pacote Python para manipulação e análise de dados orientada a colunas. Ela organiza os dados em dois tipos de estruturas, Séries e DataFrames e opera seleções e transformações sobre essas coleções de dados.

  • DataFrame: você pode imaginar como uma tabela de dados relacionais, com linhas e colunas nomeadas, como no Excel ou em SQL.
  • Series: é uma única coluna de dados, e o DataFrame contém um ou mais Series com um nome para cada uma delas.

O DataFrame, implementado em Python, é uma abstração comumente usada para manipulação de dados que tem origem na linguagem R, mas você encontrará implementações similares também em outras linguagens.

Import da biblioteca

In [ ]:
import pandas as pd
import numpy as np

Criando um pd.Series e um pd.DataFrame

Uma pd.Series pode ser criada a partir de uma lista e um pd.Dataframe pode ser criado empregando-se uma estrutura de dicionário.

In [ ]:
# Séries
student_names = pd.Series(['Adriana', 'Carol', 'Daniel'])
age = pd.Series([18, 19, 19])

# DataFrame
students = pd.DataFrame({ 'Student Name': student_names, 'Age': age })
students
Out[ ]:
Student Name Age
0 Adriana 18
1 Carol 19
2 Daniel 19

Lendo um DataFrame

O uso mais comum do Pandas que faremos é para o acesso a arquivos e bases de dados e o Pandas permite ler e gravar dados de diferetes fontes como arquivos .csv, .json, .xlsx e arquivos de bancos de dados sql, Mongo etc.

Format Read Save
csv pd.read_csv() df.to_csv()
json pd.read_json() df.to_json()
xlsx pd.read_excel() df.to_excel()
hdf pd.read_hdf() df.to_hdf()
sql pd.read_sql() df.to_sql()

que podem ser acessados local ou pela internet.

In [ ]:
tips = pd.read_csv('https://raw.githubusercontent.com/Rogerio-mack/Visualizacao-de-Dados-em-Python/main/data/tips.csv')
tips.head()
Out[ ]:
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

O comando df.head() permite exibir o aspecto inicial dos dados a partir de suas primeiras linhas.

Explorando a estrutura básica dos dados

Antes de explorarmos o conteúdo dos dados é útil termos algumas informações sobre a estrutura dos dados que estamos lidando como os valores que assumem os dados, quantas linhas temos em uma tabela, o número de atributos, o tipo de dados etc.

In [ ]:
tips.shape # nr de linhas e colunas
Out[ ]:
(244, 7)
In [ ]:
len(tips) # número de linhas
Out[ ]:
244
In [ ]:
tips.columns.to_list() # ou tips.columns
Out[ ]:
['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size']
In [ ]:
tips.dtypes # tipo dos atributos
Out[ ]:
total_bill    float64
tip           float64
sex            object
smoker         object
day            object
time           object
size            int64
dtype: object

O comando describe() exibe informações estatísticas sumarizadas dos dados.

In [ ]:
tips.describe(include='all')
Out[ ]:
total_bill tip sex smoker day time size
count 244.000000 244.000000 244 244 244 244 244.000000
unique NaN NaN 2 2 4 2 NaN
top NaN NaN Male No Sat Dinner NaN
freq NaN NaN 157 151 87 176 NaN
mean 19.785943 2.998279 NaN NaN NaN NaN 2.569672
std 8.902412 1.383638 NaN NaN NaN NaN 0.951100
min 3.070000 1.000000 NaN NaN NaN NaN 1.000000
25% 13.347500 2.000000 NaN NaN NaN NaN 2.000000
50% 17.795000 2.900000 NaN NaN NaN NaN 2.000000
75% 24.127500 3.562500 NaN NaN NaN NaN 3.000000
max 50.810000 10.000000 NaN NaN NaN NaN 6.000000

Selecionando Dados

Seleções dos dados são bastante importantes. Você nem sempre estará interessado em exibir ou analisar todos os dados. Por exemplo, você pode ter dados de produção de várias unidades de uma fábrica, mas estar interessado somente em dados das unidades de São Paulo (seleção de linhas ou casos). Ou, você pode ter dados de vendas com diversas informações dos produtos (cor, modelo etc.) e dos clientes (nome, CPF etc.) e querer apenas dados de peso e dimensões do produto, e da origem e destino da compra para analisar os preços de frete (seleção de colunas ou atributos). Mais frequentemente ainda você vai realizar as duas seleções criando slices dos dados.

Seleção de Colunas, Seleção de Linhas e de Linhas e Colunas

Selecionando colunas de dados como pd.Series

Como vimos, as colunas de um DataFrame são séries do Pandas e podemos selecionar e operar com cada uma das séries de um DataFrame. Existem dois modos de seleção

df.<nome do atributo>

df['<nome do atributo>']

eles retornam o mesmo resultado e a segunda forma é sempre necessária quando temos nomes de atributos com espaços ou caracteres especiais.

In [ ]:
print(tips.tip)
# ou
# print(tips['tip'])
0      1.01
1      1.66
2      3.50
3      3.31
4      3.61
       ... 
239    5.92
240    2.00
241    2.00
242    1.75
243    3.00
Name: tip, Length: 244, dtype: float64

Esse conjunto de dados é um pd.Series e podemos fazer uma série de operações sobre essa coleção de dados, como calcular a soma ou a média de valores.

In [ ]:
tip_series = tips['tip']
print(f'Média das gorjetas: USD {tip_series.mean() :.2f} e Total das gorjetas: USD {tip_series.sum() :.2f}')
Média das gorjetas: USD 3.00 e Total das gorjetas: USD 731.58

Pode ser útil também você transformar uma pd.Series em uma lista Python para que você possa realizar as operações de listas que você já conhece.

In [ ]:
dias = tips.day
dias = dias.to_list()
dias.count('Sat')
Out[ ]:
87

Selecionando uma ou Mais Colunas como pd.DataFrame

Mas você pode estar interessado na seleção de mais que uma coluna de dados. Para isso você pode simplesmente informar para o Pandas uma lista de atributos a serem selecionados.


df [ [ <lista-de-colunas> ] ]

Diferentemente da seleção anterior que retorna um Série do Pandas, a seleção desse modo, com uma ou mais colunas informadas em uma lista, retorna um DataFrame.

A seleção como DataFrame permite a seleção de várias séries de dados (atributos) para construírmos subconjuntos de dados de interesse. Essas seleções de dados também são DataFrame e todas as operações de DataFrame são aplicáveis.

In [ ]:
tips.columns
Out[ ]:
Index(['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size'], dtype='object')
In [ ]:
selected_tips = tips[['total_bill', 'tip', 'size']]

selected_tips.head() # um novo dataframe com atributos selecionados
Out[ ]:
total_bill tip size
0 16.99 1.01 2
1 10.34 1.66 3
2 21.01 3.50 3
3 23.68 3.31 2
4 24.59 3.61 4

$\bigstar \text{ }$ A seleção com uma ou mais colunas informadas em uma lista, retorna um DataFrame. Note que df['tip'] retorna um pd.Series, enquanto, selecionar df[['tip']] retorna um pd.DataFrame de uma única coluna.

De modo geral, você pode empreguar a seleção de pd.Series para selecionar um único atributo, e empregar a seleção pd.DataFrame quando estiver interessado na criação de subconjuntos de dados.

Selecionando Maiores e Menores

Veremos mais adiante como fazer seleção de linhas, mas aqui é oportuno vermos como selecionar linhas que contenham os maiores e os menores valores da coleção.

In [ ]:
tips.nsmallest(5,'total_bill')
Out[ ]:
total_bill tip sex smoker day time size
67 3.07 1.00 Female Yes Sat Dinner 1
92 5.75 1.00 Female Yes Fri Dinner 2
111 7.25 1.00 Female No Sat Dinner 1
172 7.25 5.15 Male Yes Sun Dinner 2
149 7.51 2.00 Male No Thur Lunch 2
In [ ]:
tips_top3 = tips.nlargest(3,'total_bill')
tips_top3
Out[ ]:
total_bill tip sex smoker day time size
170 50.81 10.00 Male Yes Sat Dinner 3
212 48.33 9.00 Male No Sat Dinner 4
59 48.27 6.73 Male No Sat Dinner 4

Alterando e Incluindo Colunas de Dados

Muitas vezes é necessário você criar atributos derivados a partir dos dados originais, como converter os valores para R\$ , criar um atributo com o valor das contas descontado a gorjeta ou o valor da conta divido pelos participantes da mesa. Essa é uma grande facilidade do Pandas que, a exemplo do NumPy, permite fazer essas operações com um único comando sobre toda uma coleção de dados sem a necessidade de laços de programa.

In [ ]:
dolar_real_rate = 5.8
tips['total_bill'] = tips['total_bill'] * dolar_real_rate         # alterando    
tips['tip'] = tips['tip'] * dolar_real_rate                       # alterando

tips['total_bill_minus_tips'] = tips['total_bill'] - tips['tip']    # incluindo um novo atributo
tips['bill_by_head'] = tips['total_bill'] / tips['size']            # incluindo um novo atributo
tips.head()
Out[ ]:
total_bill tip sex smoker day time size total_bill_minus_tips bill_by_head
0 98.542 5.858 Female No Sun Dinner 2 92.684 49.271000
1 59.972 9.628 Male No Sun Dinner 3 50.344 19.990667
2 121.858 20.300 Male No Sun Dinner 3 101.558 40.619333
3 137.344 19.198 Male No Sun Dinner 2 118.146 68.672000
4 142.622 20.938 Female No Sun Dinner 4 121.684 35.655500

Selecionar Linhas

A seleção de linhas é mais interessante por que podemos especificar condições para os valores que buscamos. Por exemplo, você pode selecionar o tipo de peças que deseja ver em um DataFrame com dados de vários componentes, ou selecionar a as unidades de fábrica de uma certa cidade que você tem os dados de produção.

O critério de seleção é um predicado lógico e você deve empregar a seguinte sintaxe:

df [ <critério de seleção> ]

Exemplos

df [ nome_coluna == valor ]
df [ nome_coluna != valor ]
df [ nome_coluna > valor ]

Assim, podemos selecionar os dados somente dos não fumantes ou não fumantes:

In [ ]:
tips_nao_fumantes = tips[ tips.smoker == 'No' ]
tips_fumantes = tips[ tips.smoker == 'Yes' ]

E podemos com isso já responder algumas questões interessantes que envolvem a proporção dos dados de fumantes e não fumantes.

In [ ]:
print(f'Percentual de Clientes Fumantes {len( tips_fumantes ) / len( tips ) :.2f} %')
Percentual de Clientes Fumantes 0.38 %

Seleção de Linhas e Colunas

O uso mais geral das seleções é quando fazemos seleções de linhas e colunas dos dados, e às vezes nos referimos a esse subconjunto dos dados de slice (fatia) dos dados.

A boa prática indica que sempre faremos primeiro a seleção das linhas,

df [ <critério de seleção> ] ...

...Selecionando uma coluna
df [ <critério de seleção> ].nome_coluna                  pd.Series
df [ <critério de seleção> ]['nome_coluna']

...Selecionando uma ou mais colunas
df [ <critério de seleção> ][ [<lista-de-colunas>] ]      pd.DataFrame

Com isso podemos fazer inúmeras seleções de dados que temos interesse em visualizar ou analisar, e responder a muitas perguntas sobre os dados.

Fumantes ou Mulheres, pagam mais gorjeta (em média) ?

In [ ]:
tips[ tips.smoker == 'Yes' ]['tip'].mean() > tips[ tips.smoker == 'No' ]['tip'].mean()  
Out[ ]:
True
In [ ]:
tips[ tips.sex == 'Female' ]['tip'].mean() > tips[ tips.sex == 'Male' ]['tip'].mean()  
Out[ ]:
False

As selecões de subconjuntos de dados, com veremos, tem uma papel importante na construção de visualizações e entendimento dos dados pois, muitas vezes, estamos interessados em comparar diferentes classes ou subconjuntos dados, como no exemplo abaixo em que observamos os valores das gorjetas de homens e mulheres.

In [ ]:
import matplotlib.pyplot as plt
plt.hist(tips[ tips.sex == 'Male' ]['tip'], label='Homens')
plt.hist(tips[ tips.sex == 'Female' ]['tip'], label='Mulheres')

plt.xlabel('Valor das Gorjetas')
plt.ylabel('Quantidades Pagas')
plt.title('Distribuição das Gorjetas', fontsize=14, weight='bold')
plt.legend(title='$\\bf{Gorjetas}$')
plt.show()

O Pandas ainda conta com uma série de operações para manipulação e transformação dos dados como funções de joins e merge de tabelas, groupby etc. empregaremos eventualmente essas operações ao longo do texto e para maiores detalhes você poderá consultar a documentação do Pandas ou outras referências online.