Tabelas e Tipos de Dados

Aprendendo como criar e manipular tabelas.

Resultados Esperados

  1. Aprender o básico de Pandas
  2. Entender diferentes tipos de dados
  3. Básico de filtros e seleções
  4. Aplicação de filtros básicos para gerar insights nos dados de dados tabulares

Sumário

  1. Tabelas e Tipos de Dados
    1. Introdução
      1. Imports básicos
    2. Series
    3. Data Frames
    4. Slicing
    5. Modificando DataFrames
    6. Arquivos
    7. Baby Names
    8. Groupby
    9. NBA Salaries e Indexação Booleana
    10. Exercícios

Introdução

Neste notebook vamos explorar um pouco de dados tabulares, ou seja, tabelas. Tabelas de dados representam um dos tipos de dados mais comuns para o cientista de dados. Pense nas inúmeras tabelas Excell que você já trabalhou com.

A principal biblioteca para leitura de dados tabulares em Python se chama pandas. A mesma é bastante poderosa implementando uma série de operações de bancos de dados (e.g., groupby e join). Nossa discussão será focada em algumas das funções principais do pandas que vamos explorar no curso. Existe uma série ampla de funcionalidades que a biblioteca (além de outras) vai trazer.

Caso necessite de algo além da aula, busque na documentação da biblioteca. Por fim, durante esta aula, também vamos aprender um pouco de bash.

Imports básicos

A maioria dos nossos notebooks vai iniciar com os imports abaixo.

  1. pandas: dados tabulates
  2. matplotlib: gráficos e plots

A chamada plt.ion habilita gráficos do matplotlib no notebook diretamente. Caso necesse salvar alguma figura, chame plt.savefig após seu plot.

#In: 
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
Código de Configurar Plot (Oculto) ```python #In: plt.rcParams['figure.figsize'] = (16, 10) plt.rcParams['axes.axisbelow'] = True plt.rcParams['axes.grid'] = True plt.rcParams['axes.labelsize'] = 16 plt.rcParams['axes.linewidth'] = 2 plt.rcParams['axes.spines.bottom'] = True plt.rcParams['axes.spines.left'] = True plt.rcParams['axes.titlesize'] = 16 plt.rcParams['axes.ymargin'] = 0.1 plt.rcParams['font.family'] = 'serif' plt.rcParams['grid.color'] = 'lightgrey' plt.rcParams['grid.linewidth'] = .1 plt.rcParams['xtick.bottom'] = True plt.rcParams['xtick.direction'] = 'out' plt.rcParams['xtick.labelsize'] = 16 plt.rcParams['xtick.major.size'] = 12 plt.rcParams['xtick.major.width'] = 1 plt.rcParams['xtick.minor.size'] = 6 plt.rcParams['xtick.minor.width'] = 1 plt.rcParams['xtick.minor.visible'] = True plt.rcParams['ytick.direction'] = 'out' plt.rcParams['ytick.labelsize'] = 16 plt.rcParams['ytick.left'] = True plt.rcParams['ytick.major.size'] = 12 plt.rcParams['ytick.major.width'] = 1 plt.rcParams['ytick.minor.size'] = 6 plt.rcParams['ytick.minor.width'] = 1 plt.rcParams['ytick.minor.visible'] = True plt.rcParams['legend.fontsize'] = 16 plt.rcParams['lines.linewidth'] = 4 plt.rcParams['lines.markersize'] = 80 ``` ```python #In: plt.style.use('tableau-colorblind10') plt.ion(); ```

Series

Existem dois tipos base de dados em pandas. O primeiro, Series, representa uma coluna de dados. Um combinação de Series vira um DataFrame (mais abaixo). Diferente de um vetor numpy, a Series de panda captura uma coluna de dados (ou vetor) indexado. Isto é, podemos nomear cada um dos valores.

#In: 
data = pd.Series(
    [0.25, 0.5, 0.75, 1.0],
    index=['a', 'b', 'c', 'd']
)
#In: 
data
a    0.25
b    0.50
c    0.75
d    1.00
dtype: float64

Note que podemos usar como um vetor

#In: 
data[0]
0.25

Porém o índice nos ajuda. Para um exemplo trivial como este não será tão interessante, mas vamos usar o mesmo.

#In: 
data.index
Index(['a', 'b', 'c', 'd'], dtype='object')

Com .loc acessamos uma linha do índice com base no nome. Então:

  1. series.loc[objeto_python] - valor com o devido nome.
  2. series.iloc[int] - i-ésimo elemento da Series.
#In: 
data.loc['a']
0.25
#In: 
data.loc['b']
0.5

Com iloc acessamos por número da linha, estilho um vetor.

#In: 
data.iloc[0]
0.25
#In: 
data[0]
0.25

Data Frames

Ao combinar várias Series com um índice comum, criamos um DataFrame. Não é tão comum gerar os mesmos na mão como estamos fazendo, geralmente carregamos DataFrames de arquivos .csv, .json ou até de sistemas de bancos de dados mariadb. De qualquer forma, use os exemplos abaixo para entender a estrutura de um dataframe.

Lembre-se que {}/dict é um dicionário (ou mapa) em Python. Podemos criar uma série a partir de um dicionário index->value

#In: 
area_dict = {'California': 423967,
             'Texas': 695662,
             'New York': 141297,
             'Florida': 170312,
             'Illinois': 149995}

A linha abaixo pega todas as chaves.

#In: 
list(area_dict.keys())
['California', 'Texas', 'New York', 'Florida', 'Illinois']

Agora todas as colunas

#In: 
list(area_dict.values())
[423967, 695662, 141297, 170312, 149995]

Acessando um valor.

#In: 
area_dict['California']
423967

Podemos criar a série a partir do dicionário, cada chave vira um elemento do índice. Os valores viram os dados do vetor.

#In: 
area = pd.Series(area_dict)
area
California    423967
Texas         695662
New York      141297
Florida       170312
Illinois      149995
dtype: int64

Agora, vamos criar outro dicionário com a população dos estados.

#In: 
pop_dict = {'California': 38332521,
            'Texas': 26448193,
            'New York': 19651127,
            'Florida': 19552860,
            'Illinois': 12882135}
pop = pd.Series(pop_dict)
pop
California    38332521
Texas         26448193
New York      19651127
Florida       19552860
Illinois      12882135
dtype: int64

Por fim, observe que o DataFrame é uma combinação de Series. Cada uma das Series vira uma coluna da tabela de dados.

#In: 
data = pd.DataFrame({'area':area, 'pop':pop})
data
areapop
California42396738332521
Texas69566226448193
New York14129719651127
Florida17031219552860
Illinois14999512882135

Agora o use de .loc e .iloc deve ficar mais claro, observe os exemplos abaixo.

#In: 
data.loc['California']
area      423967
pop     38332521
Name: California, dtype: int64
#In: 
data.loc[['California', 'Texas']]
areapop
California42396738332521
Texas69566226448193

Note que o uso de iloc retorna a i-ésima linha. O problema é que nem sempre nos dataframes esta ordem vai fazer sentido. O iloc acaba sendo mais interessante para iteração (e.g., passar por todas as linhas.)

#In: 
data.iloc[0]
area      423967
pop     38332521
Name: California, dtype: int64

Slicing

Agora, podemos realizar slicing no DataFrame. Slicing é uma operação Python que retorna sub-listas/sub-vetores. Caso não conheça, tente executar o exemplo abaixo:

#In: 
l = []
l = [7, 1, 3, 5, 9]
print(l[0])
print(l[1])
print(l[2])

# Agora, l[bg:ed] retorna uma sublista iniciando em bg e terminando em ed-1
print(l[1:4])
#In: 
l = []
l = [7, 1, 3, 5, 9]
print(l[0])
print(l[1])
print(l[2])

# Agora, l[bg:ed] retorna uma sublista iniciando em bg e terminando em ed-1
print(l[1:4])
7
1
3
[1, 3, 5]

Voltando para o nosso dataframe, podemos realizar o slicing usando o .iloc.

#In: 
data.iloc[2:4]
areapop
New York14129719651127
Florida17031219552860

Modificando DataFrames

Series e DataFrames são objetos mutáveis em Python. Podemos adicionar novas colunas em DataFrama facilmente da mesma forma que adicionamos novos valores em um mapa. Por fim, podemos também mudar o valor de linhas específicas e adicionar novas linhas.

#In: 
data['density'] = data['pop'] / data['area']
data.loc['Texas']
area       6.956620e+05
pop        2.644819e+07
density    3.801874e+01
Name: Texas, dtype: float64
#In: 
df = data
#In: 
df.index
Index(['California', 'Texas', 'New York', 'Florida', 'Illinois'], dtype='object')

Arquivos

Antes de explorar DataFrames em arquivos, vamos ver como um notebook na é um shell bastante poderoso. Ao usar uma exclamação (!) no notebook Jupyter, conseguimos executar comandos do shell do sistema. Em particular, aqui estamos executando o comando ls para indentificar os dados da pasta atual.

Tudo que executamos com ! é um comando do terminal do unix. Então, este notebook só deve executar as linhas abaixo em um Mac ou Linux.

#In: 
!ls .
01-causalidade.md     15-linear
02-tabelas	      15-linear_files
02-tabelas.ipynb      15-linear.ipynb
02-tabelas.md	      15-linear.md
03-viz		      16-vero
03-viz_files	      16-vero_files
03-viz.ipynb	      16-vero.ipynb
03-viz.md	      16-vero.md
04-stat		      17-gradiente
04-stat_files	      17-gradiente_files
04-stat.ipynb	      17-gradiente.ipynb
04-stat.md	      17-gradiente.md
05-prob		      18-multipla
05-prob_files	      18-multipla_files
05-prob.ipynb	      18-multipla.ipynb
05-prob.md	      18-multipla.md
06-risco	      19-logistica
06-risco_files	      19-logistica_files
06-risco.ipynb	      19-logistica.ipynb
06-risco.md	      19-logistica.md
07-tcl		      20-knn
07-tcl_files	      20-knn_files
07-tcl.ipynb	      20-knn.ipynb
07-tcl.md	      20-knn.md
08-amostragem	      21-pratica
08-amostragem_files   21-pratica_files
08-amostragem.ipynb   21-pratica.ipynb
08-amostragem.md      21-pratica.md
09-ics		      22-svd-e-pca
09-ics_files	      22-svd-e-pca_files
09-ics.ipynb	      22-svd-e-pca.ipynb
09-ics.md	      22-svd-e-pca.md
10-ab		      26b-tutorial-sklearn-classification.ipynb
10-ab_files	      26-tutorial-sklearn-regressao.ipynb
10-ab.ipynb	      27-revisao
10-ab.md	      27-revisao_files
11-hipoteses	      27-revisao.ipynb
11-hipoteses_files    27-revisao.md
11-hipoteses.ipynb    baby.csv
11-hipoteses.md       capital.json
12-causalidade	      colab_favicon.ico
12-causalidade_files  colab_favicon.png
12-causalidade.ipynb  colab_favicon_small.png
12-causalidade.md     compile_all.sh
13-poder	      compile_notebook.sh
13-poder_files	      dom-casmurro.txt
13-poder.ipynb	      drum.wav
13-poder.md	      f2.png
14-correlacao	      f.png
14-correlacao_files   proglanguages.json
14-correlacao.ipynb   states.txt
14-correlacao.md      walmart.csv

Com a opção -lha, mostramos meta-dados dos arquivos como o owner, tamanho e permissões. Note que todos os arquivos são .csv, isto é comma separated.

#In: 
! ls -lha .
total 180M
drwxr-xr-x 46 flaviovdf flaviovdf 4.0K Mar 21 18:36 .
drwxr-xr-x  9 flaviovdf flaviovdf 4.0K Mar 14 18:52 ..
-rw-r--r--  1 flaviovdf flaviovdf  618 Mar 14 18:20 01-causalidade.md
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 21 18:19 02-tabelas
-rw-r--r--  1 flaviovdf flaviovdf 107K Mar 21 18:36 02-tabelas.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  49K Mar 21 18:16 02-tabelas.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 21 18:36 03-viz
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 21 18:36 03-viz_files
-rw-r--r--  1 flaviovdf flaviovdf 1.2M Mar 21 18:36 03-viz.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  40K Mar 21 18:36 03-viz.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 04-stat
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 04-stat_files
-rw-r--r--  1 flaviovdf flaviovdf 360K Mar 14 18:20 04-stat.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  26K Mar 14 18:20 04-stat.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 05-prob
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 05-prob_files
-rw-r--r--  1 flaviovdf flaviovdf 892K Mar 14 18:20 05-prob.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  35K Mar 14 18:20 05-prob.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 06-risco
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 06-risco_files
-rw-r--r--  1 flaviovdf flaviovdf 291K Mar 14 18:20 06-risco.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  15K Mar 14 18:20 06-risco.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 07-tcl
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 07-tcl_files
-rw-r--r--  1 flaviovdf flaviovdf 445K Mar 14 18:20 07-tcl.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  14K Mar 14 18:20 07-tcl.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 08-amostragem
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 08-amostragem_files
-rw-r--r--  1 flaviovdf flaviovdf 232K Mar 14 18:20 08-amostragem.ipynb
-rw-r--r--  1 flaviovdf flaviovdf 117K Mar 14 18:20 08-amostragem.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 09-ics
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 09-ics_files
-rw-r--r--  1 flaviovdf flaviovdf 692K Mar 14 18:20 09-ics.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  91K Mar 14 18:20 09-ics.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 10-ab
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 10-ab_files
-rw-r--r--  1 flaviovdf flaviovdf 172K Mar 14 18:20 10-ab.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  17K Mar 14 18:20 10-ab.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 11-hipoteses
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 11-hipoteses_files
-rw-r--r--  1 flaviovdf flaviovdf 301K Mar 14 18:20 11-hipoteses.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  94K Mar 14 18:20 11-hipoteses.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 12-causalidade
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 12-causalidade_files
-rw-r--r--  1 flaviovdf flaviovdf  52K Mar 14 18:20 12-causalidade.ipynb
-rw-r--r--  1 flaviovdf flaviovdf 9.6K Mar 14 18:20 12-causalidade.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 13-poder
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 13-poder_files
-rw-r--r--  1 flaviovdf flaviovdf 837K Mar 14 18:20 13-poder.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  25K Mar 14 18:20 13-poder.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 14-correlacao
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 14-correlacao_files
-rw-r--r--  1 flaviovdf flaviovdf 1.8M Mar 14 18:20 14-correlacao.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  39K Mar 14 18:20 14-correlacao.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 15-linear
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 15-linear_files
-rw-r--r--  1 flaviovdf flaviovdf 992K Mar 14 18:20 15-linear.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  25K Mar 14 18:20 15-linear.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 16-vero
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 16-vero_files
-rw-r--r--  1 flaviovdf flaviovdf 1.0M Mar 14 18:20 16-vero.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  30K Mar 14 18:20 16-vero.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 17-gradiente
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 17-gradiente_files
-rw-r--r--  1 flaviovdf flaviovdf 731K Mar 14 18:20 17-gradiente.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  58K Mar 14 18:20 17-gradiente.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 18-multipla
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 18-multipla_files
-rw-r--r--  1 flaviovdf flaviovdf 671K Mar 14 18:20 18-multipla.ipynb
-rw-r--r--  1 flaviovdf flaviovdf 136K Mar 14 18:20 18-multipla.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 19-logistica
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 19-logistica_files
-rw-r--r--  1 flaviovdf flaviovdf 886K Mar 14 18:20 19-logistica.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  79K Mar 14 18:20 19-logistica.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 20-knn
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 20-knn_files
-rw-r--r--  1 flaviovdf flaviovdf 790K Mar 14 18:20 20-knn.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  19K Mar 14 18:20 20-knn.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 21-pratica
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 21-pratica_files
-rw-r--r--  1 flaviovdf flaviovdf 280K Mar 14 18:20 21-pratica.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  72K Mar 14 18:20 21-pratica.md
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 22-svd-e-pca
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 22-svd-e-pca_files
-rw-r--r--  1 flaviovdf flaviovdf 9.5M Mar 14 18:20 22-svd-e-pca.ipynb
-rw-r--r--  1 flaviovdf flaviovdf 6.7M Mar 14 18:20 22-svd-e-pca.md
-rw-r--r--  1 flaviovdf flaviovdf  47K Mar 14 18:20 26b-tutorial-sklearn-classification.ipynb
-rw-r--r--  1 flaviovdf flaviovdf 203K Mar 14 18:20 26-tutorial-sklearn-regressao.ipynb
drwxr-xr-x  3 flaviovdf flaviovdf 4.0K Mar 14 18:20 27-revisao
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 27-revisao_files
-rw-r--r--  1 flaviovdf flaviovdf  63K Mar 14 18:20 27-revisao.ipynb
-rw-r--r--  1 flaviovdf flaviovdf  17K Mar 14 18:20 27-revisao.md
-rw-r--r--  1 flaviovdf flaviovdf 148M Mar 21 18:02 baby.csv
-rw-r--r--  1 flaviovdf flaviovdf 172K Mar 14 18:20 capital.json
-rw-r--r--  1 flaviovdf flaviovdf  72K Mar 14 18:20 colab_favicon.ico
-rw-r--r--  1 flaviovdf flaviovdf 7.8K Mar 14 18:20 colab_favicon.png
-rw-r--r--  1 flaviovdf flaviovdf 2.2K Mar 14 18:20 colab_favicon_small.png
-rw-r--r--  1 flaviovdf flaviovdf   85 Mar 14 18:20 compile_all.sh
-rw-r--r--  1 flaviovdf flaviovdf 1.1K Mar 14 18:20 compile_notebook.sh
-rw-r--r--  1 flaviovdf flaviovdf 401K Mar 14 18:20 dom-casmurro.txt
-rw-r--r--  1 flaviovdf flaviovdf 331K Mar 14 18:20 drum.wav
-rw-r--r--  1 flaviovdf flaviovdf 125K Mar 14 18:20 f2.png
-rw-r--r--  1 flaviovdf flaviovdf  57K Mar 14 18:20 f.png
drwxr-xr-x  2 flaviovdf flaviovdf 4.0K Mar 14 18:20 .ipynb_checkpoints
-rw-r--r--  1 flaviovdf flaviovdf  29K Mar 14 18:20 .nbgrader.log
-rw-r--r--  1 flaviovdf flaviovdf 3.1K Mar 14 18:20 proglanguages.json
-rw-r--r--  1 flaviovdf flaviovdf 131K Mar 14 18:20 states.txt
-rw-r--r--  1 flaviovdf flaviovdf 715K Mar 14 18:20 walmart.csv

Vamos identificar qual a cara de um csv. O programa head imprime as primeiras n linhas de um arquivo.

#In: 
! head baby.csv
Id,Name,Year,Gender,State,Count
1,Mary,1910,F,AK,14
2,Annie,1910,F,AK,12
3,Anna,1910,F,AK,10
4,Margaret,1910,F,AK,8
5,Helen,1910,F,AK,7
6,Elsie,1910,F,AK,6
7,Lucy,1910,F,AK,6
8,Dorothy,1910,F,AK,5
9,Mary,1911,F,AK,12

Observe como o comando head nos ajuda a entender o arquivo .csv. Sabemos quais colunas e qual o separador do mesmo.

Baby Names

É bem mais comum fazer uso de DataFrames que já existem em arquivos. Note que o trabalho do cientista de dados nem sempre vai ter tais arquivos prontos. Em várias ocasiões, você vai ter que coletar e organizar os mesmos. Limpeza e coleta de dados é uma parte fundamental do seu trabalho. Durante a matéria, boa parte dos notebooks já vão ter dados prontos.

#In: 
df = pd.read_csv('https://media.githubusercontent.com/media/icd-ufmg/material/master/aulas/03-Tabelas-e-Tipos-de-Dados/baby.csv')
df = df.drop('Id', axis='columns') # remove a coluna id, serve de nada
df
NameYearGenderStateCount
0Mary1910FAK14
1Annie1910FAK12
2Anna1910FAK10
3Margaret1910FAK8
4Helen1910FAK7
..................
5647421Seth2014MWY5
5647422Spencer2014MWY5
5647423Tyce2014MWY5
5647424Victor2014MWY5
5647425Waylon2014MWY5

5647426 rows × 5 columns

O método head do notebook retorna as primeiras n linhas do mesmo. Use tal método para entender seus dados. Sempre olhe para seus dados. Note como as linhas abaixo usa o loc e iloc para entender um pouco a estrutura dos mesmos.

#In: 
df.head()
NameYearGenderStateCount
0Mary1910FAK14
1Annie1910FAK12
2Anna1910FAK10
3Margaret1910FAK8
4Helen1910FAK7

O método head do notebook retorna as primeiras n linhas do mesmo. Use tal método para entender seus dados. Sempre olhe para seus dados. Note como as linhas abaixo usa o loc e iloc para entender um pouco a estrutura dos mesmos.

#In: 
df.head(6)
NameYearGenderStateCount
0Mary1910FAK14
1Annie1910FAK12
2Anna1910FAK10
3Margaret1910FAK8
4Helen1910FAK7
5Elsie1910FAK6
#In: 
df[10:15]
NameYearGenderStateCount
10Ruth1911FAK7
11Annie1911FAK6
12Elizabeth1911FAK6
13Helen1911FAK6
14Mary1912FAK9
#In: 
df.iloc[0:6]
NameYearGenderStateCount
0Mary1910FAK14
1Annie1910FAK12
2Anna1910FAK10
3Margaret1910FAK8
4Helen1910FAK7
5Elsie1910FAK6
#In: 
df[['Name', 'Gender']].head(6)
NameGender
0MaryF
1AnnieF
2AnnaF
3MargaretF
4HelenF
5ElsieF
#In: 
df[['Name', 'Gender']].head(6)
NameGender
0MaryF
1AnnieF
2AnnaF
3MargaretF
4HelenF
5ElsieF

Groupby

Vamos responder algumas perguntas com a função groupby. Lembrando a ideia é separar os dados com base em valores comuns, ou seja, agrupar por nomes e realizar alguma operação. O comando abaixo agrupa todos os recem-náscidos por nome. Imagine a mesma fazendo uma operação equivalente ao laço abaixo:

#In: 
buckets = {}                    # Mapa de dados
names = set(df['Name'])         # Conjunto de nomes únicos
for idx, row in df.iterrows():  # Para cada linha dos dados
    name = row['Name']
    if name not in buckets:
        buckets[name] = []      # Uma lista para cada nome
    buckets[name].append(row)   # Separa a linha para cada nome

O código acima é bastante lento!!! O groupby é optimizado. Com base na linha abaixo, o mesmo nem retorna nehum resultado ainda. Apenas um objeto onde podemos fazer agregações.

#In: 
gb = df.groupby('Name')
type(gb)
pandas.core.groupby.generic.DataFrameGroupBy

Agora posso agregar todos os nomes com alguma operação. Por exemplo, posso somar a quantidade de vezes que cada nome ocorre. Em python, seria o seguinte código.

#In: 
sum_ = {}                       # Mapa de dados
for name in buckets:            # Para cada nomee
    sum_[name] = 0
    for row in buckets[name]:   # Para cada linha com aquele nome, aggregate (some)
        sum_[name] += row['Count']

Observe o resultado da agregação abaixo. Qual o problema com a coluna Year??

#In: 
gb[['Year', 'Count']].mean()
YearCount
Name
Aaban2013.5000006.000000
Aadan2009.7500005.750000
Aadarsh2009.0000005.000000
Aaden2010.01530617.479592
Aadhav2014.0000006.000000
.........
Zyrah2012.0000005.500000
Zyren2013.0000006.000000
Zyria2006.7142865.785714
Zyriah2009.6666676.444444
Zyshonne1998.0000005.000000

30274 rows × 2 columns

Não faz tanto sentido somar o ano, embora seja um número aqui representa uma categoria. Vamos somar as contagens apenas.

Observe como a chamada abaixo tem um enter depois de cada ponto. Isso é um truque para deixar o código mais legível

#In: 

# Leia dessa forma

(dados[['coluna1', 'coluna2']].    # selecione algumas colunas
 operacao_a().                     # realize uma operação
 operacao_b()                      # realize outra
)

# É o mesmo de

dados[['coluna1', 'coluna2']].operacao_a().operacao_b()

Cada chamada pandas retorna um DataFrame novo. Ao fazer . chamamos um novo método. Quebrando a linha no ponto fica mais fácil separa a lógica de cada operação. Compare os casos abaixo.

#In: 

# Leia dessa forma

(dados[['coluna1', 'coluna2']].    # selecione algumas colunas
 operacao_a().                     # realize uma operação
 operacao_b().                     # realize outra
 operaca_c().
 operaca_d().
 operaca_e().
 operaca_f().
)

# É o mesmo de

dados[['coluna1', 'coluna2']].operacao_a().operacao_c().operacao_d().operacao_e().operacao_f()

#In: 
(gb['Count'].
 sum().
 sort_values()
)
Name
Zyshonne          5
Makenlee          5
Makenlie          5
Makinlee          5
Makua             5
             ...   
William     3839236
Michael     4312975
Robert      4725713
John        4845414
James       4957166
Name: Count, Length: 30274, dtype: int64

E ordenar…

#In: 
(gb['Count'].
 sum().
 sort_values()
)
Name
Zyshonne          5
Makenlee          5
Makenlie          5
Makinlee          5
Makua             5
             ...   
William     3839236
Michael     4312975
Robert      4725713
John        4845414
James       4957166
Name: Count, Length: 30274, dtype: int64

É comum, embora mais chato de ler, fazer tudo em uma única chamada. Isto é uma prática que vem do mundo SQL. A chamada abaixo seria o mesmo de:

SELECT Name, SUM(Count)
FROM baby_table
GROUPBY Name
ORDERBY SUM(Count)
#In: 
(df[['Name', 'Count']].
 groupby('Name').
 sum().
 sort_values(by='Count')
)
Count
Name
Zyshonne5
Makenlee5
Makenlie5
Makinlee5
Makua5
......
William3839236
Michael4312975
Robert4725713
John4845414
James4957166

30274 rows × 1 columns

#In: 
(df[['Name', 'Year', 'Count']].
 groupby(['Name', 'Year']).
 sum()
)
Count
NameYear
Aaban20136
20146
Aadan200812
20096
20145
.........
Zyriah20116
20125
20137
20146
Zyshonne19985

548154 rows × 1 columns

NBA Salaries e Indexação Booleana

Por fim, vamos explorar alguns dados da NBA para entender a indexação booleana. Vamos carregar os dados da mesma forma que carregamos os dados dos nomes de crianças.

#In: 
df = pd.read_csv('https://media.githubusercontent.com/media/icd-ufmg/material/master/aulas/03-Tabelas-e-Tipos-de-Dados/nba_salaries.csv')
df.head()
PLAYERPOSITIONTEAMSALARY
0Paul MillsapPFAtlanta Hawks18.671659
1Al HorfordCAtlanta Hawks12.000000
2Tiago SplitterCAtlanta Hawks9.756250
3Jeff TeaguePGAtlanta Hawks8.000000
4Kyle KorverSGAtlanta Hawks5.746479

Por fim, vamos indexar nosso DataFrame por booleanos. A linha abaixo pega um vetor de booleanos onde o nome do time é Houston Rockets.

#In: 
df['TEAM'] == 'Houston Rockets'
0      False
1      False
2      False
3      False
4      False
       ...  
412    False
413    False
414    False
415    False
416    False
Name: TEAM, Length: 417, dtype: bool

Podemos usar tal vetor para filtrar nosso DataFrame. A linha abaixo é o mesmo de um:

SELECT *
FROM table
WHERE TEAM = 'Houston Rockets'
#In: 
filtro = df['TEAM'] == 'Houston Rockets'
df[filtro]
PLAYERPOSITIONTEAMSALARY
131Dwight HowardCHouston Rockets22.359364
132James HardenSGHouston Rockets15.756438
133Ty LawsonPGHouston Rockets12.404495
134Corey BrewerSGHouston Rockets8.229375
135Trevor ArizaSFHouston Rockets8.193030
136Patrick BeverleyPGHouston Rockets6.486486
137K.J. McDanielsSGHouston Rockets3.189794
138Terrence JonesPFHouston Rockets2.489530
139Donatas MotiejunasPFHouston Rockets2.288205
140Sam DekkerSFHouston Rockets1.646400
141Clint CapelaPFHouston Rockets1.242720
142Montrezl HarrellPFHouston Rockets1.000000

Assim como pegar os salários maior do que um certo valor!

#In: 
df[df['SALARY'] > 20]
PLAYERPOSITIONTEAMSALARY
29Joe JohnsonSFBrooklyn Nets24.894863
60Derrick RosePGChicago Bulls20.093064
72LeBron JamesSFCleveland Cavaliers22.970500
131Dwight HowardCHouston Rockets22.359364
156Chris PaulPGLos Angeles Clippers21.468695
169Kobe BryantSFLos Angeles Lakers25.000000
201Chris BoshPFMiami Heat22.192730
255Carmelo AnthonySFNew York Knicks22.875000
268Kevin DurantSFOklahoma City Thunder20.158622

Exercícios

Abaixo temos algumas chamadas em pandas. Tente explicar cada uma delas.

#In: 
(df[['POSITION', 'SALARY']].
 groupby('POSITION').
 mean()
)
SALARY
POSITION
C6.082913
PF4.951344
PG5.165487
SF5.532675
SG3.988195
#In: 
(df[['TEAM', 'SALARY']].
 groupby('TEAM').
 mean().
 sort_values('SALARY')
)
SALARY
TEAM
Phoenix Suns2.971813
Utah Jazz3.095993
Portland Trail Blazers3.246206
Philadelphia 76ers3.267796
Boston Celtics3.352367
Milwaukee Bucks4.019873
Detroit Pistons4.221176
Toronto Raptors4.392507
Brooklyn Nets4.408229
Denver Nuggets4.459243
Memphis Grizzlies4.466497
Charlotte Hornets4.672355
Indiana Pacers4.822694
Atlanta Hawks4.969507
New Orleans Pelicans5.032163
Minnesota Timberwolves5.065186
Los Angeles Clippers5.082624
Washington Wizards5.296912
New York Knicks5.338846
Orlando Magic5.544567
Dallas Mavericks5.978414
Oklahoma City Thunder6.052010
Sacramento Kings6.216808
Los Angeles Lakers6.237086
San Antonio Spurs6.511698
Chicago Bulls6.568407
Golden State Warriors6.720367
Miami Heat6.794056
Houston Rockets7.107153
Cleveland Cavaliers10.231241