Manipulação de dados - III¶
Agregação e agrupamento¶
Agregando informações de linhas ou colunas¶
Para agregar informações (p.ex. somar, tomar médias etc.) de linhas ou colunas podemos utilizar alguns métodos específicos já existentes em DataFrames e Series, tais como sum, mean, cumsum e aggregate (ou equivalentemente agg):
import pandas as pd
import numpy as np
dados_covid_PB = pd.read_csv('https://superset.plataformatarget.com.br/superset/explore_json/?form_data=%7B%22slice_id%22%3A1550%7D&csv=true', 
                             sep=',', index_col=0)
dados_covid_PB.agg(lambda vetor: np.sum(vetor))[['casosNovos','obitosNovos']].astype('int')
casosNovos     440037
obitosNovos      9294
dtype: int64
Podemos conferir esta agregação resultante com o número de casos acumulados e óbitos acumulados
dados_covid_PB.head()
| casosAcumulados | casosNovos | descartados | recuperados | obitosAcumulados | obitosNovos | Letalidade | |
|---|---|---|---|---|---|---|---|
| data | |||||||
| 2021-09-26 | 441155 | 134 | 484336 | 333751 | 9294 | 2.0 | 0.0211 | 
| 2021-09-25 | 441021 | 165 | 484331 | 333441 | 9292 | 2.0 | 0.0211 | 
| 2021-09-24 | 440856 | 225 | 484301 | 332845 | 9290 | 3.0 | 0.0211 | 
| 2021-09-23 | 440631 | 203 | 484276 | 332540 | 9287 | 3.0 | 0.0211 | 
| 2021-09-22 | 440428 | 297 | 484265 | 331958 | 9284 | 6.0 | 0.0211 | 
Isto também pode ser obtido utilizando o método sum de DataFrames e Series:
dados_covid_PB[['casosNovos','obitosNovos']].sum()
casosNovos     440037.0
obitosNovos      9294.0
dtype: float64
Podemos recriar a coluna 'obitosAcumulados' com o método cumsum (soma cumulativa):
dados_covid_PB.obitosNovos.sort_index().cumsum()
data
2020-03-16       0.0
2020-03-17       0.0
2020-03-18       0.0
2020-03-19       0.0
2020-03-20       0.0
               ...  
2021-09-22    9284.0
2021-09-23    9287.0
2021-09-24    9290.0
2021-09-25    9292.0
2021-09-26    9294.0
Name: obitosNovos, Length: 559, dtype: float64
Selecionando entradas distintas¶
Para selecionar entradas distintas utilizamos o método drop_duplicate. Aqui, para exemplificar, vamos utilizar o banco de dados oficial sobre COVID no Brasil:
# pode levar um tempo para ler...
covid_BR = pd.read_excel('../database/HIST_PAINEL_COVIDBR_18jul2020.xlsx')
covid_BR.tail(3)
| Unnamed: 0 | regiao | estado | municipio | coduf | codmun | codRegiaoSaude | nomeRegiaoSaude | data | semanaEpi | populacaoTCU2019 | casosAcumulado | casosNovos | obitosAcumulado | obitosNovos | Recuperadosnovos | emAcompanhamentoNovos | interior/metropolitana | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 629803 | 629803 | Centro-Oeste | DF | Brasília | 53 | 530010.0 | 53001.0 | DISTRITO FEDERAL | 2020-07-16 | 29 | 3015268 | 77621 | 2242 | 1037 | 36 | NaN | NaN | 1.0 | 
| 629804 | 629804 | Centro-Oeste | DF | Brasília | 53 | 530010.0 | 53001.0 | DISTRITO FEDERAL | 2020-07-17 | 29 | 3015268 | 79400 | 1779 | 1060 | 23 | NaN | NaN | 1.0 | 
| 629805 | 629805 | Centro-Oeste | DF | Brasília | 53 | 530010.0 | 53001.0 | DISTRITO FEDERAL | 2020-07-18 | 29 | 3015268 | 81163 | 1763 | 1075 | 15 | NaN | NaN | 1.0 | 
# resumo da tabela
covid_BR.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 629806 entries, 0 to 629805
Data columns (total 18 columns):
 #   Column                  Non-Null Count   Dtype  
---  ------                  --------------   -----  
 0   Unnamed: 0              629806 non-null  int64  
 1   regiao                  629806 non-null  object 
 2   estado                  629661 non-null  object 
 3   municipio               623352 non-null  object 
 4   coduf                   629806 non-null  int64  
 5   codmun                  625746 non-null  float64
 6   codRegiaoSaude          623352 non-null  float64
 7   nomeRegiaoSaude         623352 non-null  object 
 8   data                    629806 non-null  object 
 9   semanaEpi               629806 non-null  int64  
 10  populacaoTCU2019        627412 non-null  object 
 11  casosAcumulado          629806 non-null  int64  
 12  casosNovos              629806 non-null  int64  
 13  obitosAcumulado         629806 non-null  int64  
 14  obitosNovos             629806 non-null  int64  
 15  Recuperadosnovos        91 non-null      float64
 16  emAcompanhamentoNovos   91 non-null      float64
 17  interior/metropolitana  623352 non-null  float64
dtypes: float64(5), int64(7), object(6)
memory usage: 86.5+ MB
# todos os estados únicos
covid_BR.estado.drop_duplicates().array
<PandasArray>
[ nan, 'RO', 'AC', 'AM', 'RR', 'PA', 'AP', 'TO', 'MA', 'PI', 'CE', 'RN', 'PB',
 'PE', 'AL', 'SE', 'BA', 'MG', 'ES', 'RJ', 'SP', 'PR', 'SC', 'RS', 'MS', 'MT',
 'GO', 'DF']
Length: 28, dtype: object
# ordena alfabeticamente
covid_BR.estado.drop_duplicates().dropna().sort_values().array
<PandasArray>
['AC', 'AL', 'AM', 'AP', 'BA', 'CE', 'DF', 'ES', 'GO', 'MA', 'MG', 'MS', 'MT',
 'PA', 'PB', 'PE', 'PI', 'PR', 'RJ', 'RN', 'RO', 'RR', 'RS', 'SC', 'SE', 'SP',
 'TO']
Length: 27, dtype: object
Agrupando dados por valores em colunas e agregando os resultados¶
Vamos determinar uma coluna para agrupar. Consideraremos o DataFrame covid_BRe selecionaremos os estados PB, PE, RJ e SP para realizar análises agrupando os resultados por estados.
covid_BR.query('estado in ["PB", "PE", "RJ", "SP"]')
| Unnamed: 0 | regiao | estado | municipio | coduf | codmun | codRegiaoSaude | nomeRegiaoSaude | data | semanaEpi | populacaoTCU2019 | casosAcumulado | casosNovos | obitosAcumulado | obitosNovos | Recuperadosnovos | emAcompanhamentoNovos | interior/metropolitana | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1740 | 1740 | Nordeste | PB | NaN | 25 | NaN | NaN | NaN | 2020-02-25 | 9 | 4018127 | 0 | 0 | 0 | 0 | NaN | NaN | NaN | 
| 1741 | 1741 | Nordeste | PB | NaN | 25 | NaN | NaN | NaN | 2020-02-26 | 9 | 4018127 | 0 | 0 | 0 | 0 | NaN | NaN | NaN | 
| 1742 | 1742 | Nordeste | PB | NaN | 25 | NaN | NaN | NaN | 2020-02-27 | 9 | 4018127 | 0 | 0 | 0 | 0 | NaN | NaN | NaN | 
| 1743 | 1743 | Nordeste | PB | NaN | 25 | NaN | NaN | NaN | 2020-02-28 | 9 | 4018127 | 0 | 0 | 0 | 0 | NaN | NaN | NaN | 
| 1744 | 1744 | Nordeste | PB | NaN | 25 | NaN | NaN | NaN | 2020-02-29 | 9 | 4018127 | 0 | 0 | 0 | 0 | NaN | NaN | NaN | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 448655 | 448655 | Sudeste | SP | Estiva Gerbi | 35 | 355730.0 | 35141.0 | BAIXA MOGIANA | 2020-07-14 | 29 | 11304 | 62 | 6 | 3 | 1 | NaN | NaN | 0.0 | 
| 448656 | 448656 | Sudeste | SP | Estiva Gerbi | 35 | 355730.0 | 35141.0 | BAIXA MOGIANA | 2020-07-15 | 29 | 11304 | 65 | 3 | 3 | 0 | NaN | NaN | 0.0 | 
| 448657 | 448657 | Sudeste | SP | Estiva Gerbi | 35 | 355730.0 | 35141.0 | BAIXA MOGIANA | 2020-07-16 | 29 | 11304 | 70 | 5 | 3 | 0 | NaN | NaN | 0.0 | 
| 448658 | 448658 | Sudeste | SP | Estiva Gerbi | 35 | 355730.0 | 35141.0 | BAIXA MOGIANA | 2020-07-17 | 29 | 11304 | 75 | 5 | 4 | 1 | NaN | NaN | 0.0 | 
| 448659 | 448659 | Sudeste | SP | Estiva Gerbi | 35 | 355730.0 | 35141.0 | BAIXA MOGIANA | 2020-07-18 | 29 | 11304 | 75 | 0 | 4 | 0 | NaN | NaN | 0.0 | 
130768 rows × 18 columns
Inspecionando o conjunto de dados, observamos que os dados para estado são apresentados com o valor NaN para codmun e quando codmun possui um valor diferente de NaN, o resultado é apenas para o município do código em questão.
Como estamos interessados nos valores por estado, vamos selecionar apenas os dados com codmun contendo NaN.
covid_estados = covid_BR.query('estado in ["PB", "PE", "RJ", "SP"]')
covid_apenas_estados = covid_estados.loc[covid_estados['codmun'].isna()]
Vamos agora selecionar apenas as colunas de interesse. Para tanto, vejamos os nomes das colunas:
covid_apenas_estados.columns
Index(['Unnamed: 0', 'regiao', 'estado', 'municipio', 'coduf', 'codmun',
       'codRegiaoSaude', 'nomeRegiaoSaude', 'data', 'semanaEpi',
       'populacaoTCU2019', 'casosAcumulado', 'casosNovos', 'obitosAcumulado',
       'obitosNovos', 'Recuperadosnovos', 'emAcompanhamentoNovos',
       'interior/metropolitana'],
      dtype='object')
covid_apenas_estados = covid_apenas_estados[['estado', 'data', 'casosNovos', 'obitosNovos']]
A data parece ser o index natural, já que o index atual não representa nada. Observe que teremos index repetidos, pois teremos as mesmas datas em estados diferentes.
covid_apenas_estados
| estado | data | casosNovos | obitosNovos | |
|---|---|---|---|---|
| 1740 | PB | 2020-02-25 | 0 | 0 | 
| 1741 | PB | 2020-02-26 | 0 | 0 | 
| 1742 | PB | 2020-02-27 | 0 | 0 | 
| 1743 | PB | 2020-02-28 | 0 | 0 | 
| 1744 | PB | 2020-02-29 | 0 | 0 | 
| ... | ... | ... | ... | ... | 
| 3040 | SP | 2020-07-14 | 12000 | 417 | 
| 3041 | SP | 2020-07-15 | 6569 | 316 | 
| 3042 | SP | 2020-07-16 | 8872 | 398 | 
| 3043 | SP | 2020-07-17 | 5367 | 339 | 
| 3044 | SP | 2020-07-18 | 4612 | 270 | 
580 rows × 4 columns
covid_apenas_estados = covid_apenas_estados.set_index('data')
covid_apenas_estados
| estado | casosNovos | obitosNovos | |
|---|---|---|---|
| data | |||
| 2020-02-25 | PB | 0 | 0 | 
| 2020-02-26 | PB | 0 | 0 | 
| 2020-02-27 | PB | 0 | 0 | 
| 2020-02-28 | PB | 0 | 0 | 
| 2020-02-29 | PB | 0 | 0 | 
| ... | ... | ... | ... | 
| 2020-07-14 | SP | 12000 | 417 | 
| 2020-07-15 | SP | 6569 | 316 | 
| 2020-07-16 | SP | 8872 | 398 | 
| 2020-07-17 | SP | 5367 | 339 | 
| 2020-07-18 | SP | 4612 | 270 | 
580 rows × 3 columns
Agrupando com o método groupby¶
Podemos escolher uma (ou mais colunas, incluindo o índice) para agrupar os dados. Ao agruparmos os dados, receberemos um objeto do tipo DataFrameGroupBy. Para vermos os resultados, devemos agregar os valores:
covid_estados_agrupado = covid_apenas_estados.groupby('estado')
covid_estados_agrupado.sum().rename({'casosNovos':'Casos Totais', 'obitosNovos':'Obitos Totais'},axis=1)
| Casos Totais | Obitos Totais | |
|---|---|---|
| estado | ||
| PB | 66971 | 1477 | 
| PE | 78509 | 5928 | 
| RJ | 135230 | 11919 | 
| SP | 412027 | 19647 | 
Podemos agrupar por mais de uma coluna. Vamos fazer dois grupos. grupo_1 formado por PB e PE e grupo_2 formado por RJ e SP. Em seguida, vamos agrupar por grupo e por data:
covid_estados_grupos = covid_apenas_estados.copy()
col_grupos = covid_estados_grupos.estado.map(lambda estado: 'grupo_1' if estado in ['PB','PE']
                                                  else 'grupo_2')
covid_estados_grupos['grupo'] = col_grupos
covid_estados_grupos
| estado | casosNovos | obitosNovos | grupo | |
|---|---|---|---|---|
| data | ||||
| 2020-02-25 | PB | 0 | 0 | grupo_1 | 
| 2020-02-26 | PB | 0 | 0 | grupo_1 | 
| 2020-02-27 | PB | 0 | 0 | grupo_1 | 
| 2020-02-28 | PB | 0 | 0 | grupo_1 | 
| 2020-02-29 | PB | 0 | 0 | grupo_1 | 
| ... | ... | ... | ... | ... | 
| 2020-07-14 | SP | 12000 | 417 | grupo_2 | 
| 2020-07-15 | SP | 6569 | 316 | grupo_2 | 
| 2020-07-16 | SP | 8872 | 398 | grupo_2 | 
| 2020-07-17 | SP | 5367 | 339 | grupo_2 | 
| 2020-07-18 | SP | 4612 | 270 | grupo_2 | 
580 rows × 4 columns
Agora vamos agrupar e agregar:
covid_grupo_agrupado = covid_estados_grupos.groupby(['grupo','data'])
covid_grupo_agrupado.sum()
| casosNovos | obitosNovos | ||
|---|---|---|---|
| grupo | data | ||
| grupo_1 | 2020-02-25 | 0 | 0 | 
| 2020-02-26 | 0 | 0 | |
| 2020-02-27 | 0 | 0 | |
| 2020-02-28 | 0 | 0 | |
| 2020-02-29 | 0 | 0 | |
| ... | ... | ... | ... | 
| grupo_2 | 2020-07-14 | 12778 | 567 | 
| 2020-07-15 | 8196 | 449 | |
| 2020-07-16 | 8996 | 490 | |
| 2020-07-17 | 6024 | 409 | |
| 2020-07-18 | 4612 | 270 | 
290 rows × 2 columns
Mesclando DataFrames¶
Vamos agora ver algumas formas de juntar dois ou mais DataFrames com index ou colunas em comum para formar um novo DataFrame.
Mesclando DataFrames através de concatenações¶
Concatenar nada mais é do que “colar” dois ou mais DataFrames. Podemos concatenar por linhas ou por colunas.
A função que realiza a concatenação é concat. Os dois argumentos mais utilizados são a lista de DataFrames a serem concatenados e axis, onde axis = 0 indica concatenação por linha (um DataFrame “embaixo” do outro) e axis=1 indica concatenação por coluna (um DataFrame ao lado do outro).
Relembre do DataFrame df_dict_series:
df_dict_series = pd.read_csv('../database/df_dict_series.csv')
Vamos criar um novo, com novas pessoas:
serie_Idade_nova = pd.Series({'Augusto':13, 'André': 17, 'Alexandre': 45}, name="Idade")
serie_Peso_novo = pd.Series({'Augusto':95, 'André': 65, 'Alexandre': 83}, name="Peso")
serie_Altura_nova = pd.Series({'Augusto':192, 'André': 175, 'Alexandre': 177}, name="Altura")
serie_sobrenome = pd.Series({'Augusto':'Castro', 'André':'Castro', 'Alexandre':'Castro'}, name='Sobrenome')
dicionario_novo = {'Sobrenome':serie_sobrenome, 'Peso': serie_Peso_novo, 
                   'Idade': serie_Idade_nova, 'Altura': serie_Altura_nova}
df_novo = pd.DataFrame(dicionario_novo)
df_novo = df_novo.assign(IMC=round(df_novo.eval('Peso/(Altura/100)**2'),2))
df_novo
| Sobrenome | Peso | Idade | Altura | IMC | |
|---|---|---|---|---|---|
| Augusto | Castro | 95 | 13 | 192 | 25.77 | 
| André | Castro | 65 | 17 | 175 | 21.22 | 
| Alexandre | Castro | 83 | 45 | 177 | 26.49 | 
Agora vamos concatená-los:
pd.concat([df_dict_series,df_novo]) 
| Unnamed: 0 | Idade | Peso | Altura | IMC | Sobrenome | |
|---|---|---|---|---|---|---|
| 0 | Ana | 20 | 65 | 162 | 24.77 | Silva | 
| 1 | João | 19 | 80 | 178 | 25.25 | PraDo | 
| 2 | Maria | 21 | 62 | 162 | 23.62 | Sales | 
| 3 | Pedro | 22 | 67 | 165 | 24.61 | MachadO | 
| 4 | Túlio | 20 | 73 | 171 | 24.96 | Coutinho | 
| Augusto | NaN | 13 | 95 | 192 | 25.77 | Castro | 
| André | NaN | 17 | 65 | 175 | 21.22 | Castro | 
| Alexandre | NaN | 45 | 83 | 177 | 26.49 | Castro | 
Concatenando por coluna¶
Para exemplificar vamos considerar os dados de COVID da Paraíba, selecionando casos novos e óbitos novos, e vamos obter dos dados do Brasil apenas os casos e óbitos diários do país, e vamos concatená-los por coluna.
covid_PB_casos_obitos = dados_covid_PB[['casosNovos','obitosNovos']]
Vamos tratar os dados do Brasil:
covid_BR_casos_obitos = covid_BR.query('regiao=="Brasil"')
covid_BR_casos_obitos = covid_BR_casos_obitos.set_index('data')
covid_BR_casos_obitos = covid_BR_casos_obitos[['casosNovos','obitosNovos']].rename({
    'casosNovos':'casosBR', 'obitosNovos':'obitosBR'
}, axis=1)
covid_PB_casos_obitos
| casosNovos | obitosNovos | |
|---|---|---|
| data | ||
| 2021-09-26 | 134 | 2.0 | 
| 2021-09-25 | 165 | 2.0 | 
| 2021-09-24 | 225 | 3.0 | 
| 2021-09-23 | 203 | 3.0 | 
| 2021-09-22 | 297 | 6.0 | 
| ... | ... | ... | 
| 2020-03-20 | 0 | 0.0 | 
| 2020-03-19 | 0 | 0.0 | 
| 2020-03-18 | 0 | 0.0 | 
| 2020-03-17 | 0 | 0.0 | 
| 2020-03-16 | 0 | 0.0 | 
559 rows × 2 columns
covid_BR_casos_obitos
| casosBR | obitosBR | |
|---|---|---|
| data | ||
| 2020-02-25 | 0 | 0 | 
| 2020-02-26 | 1 | 0 | 
| 2020-02-27 | 0 | 0 | 
| 2020-02-28 | 0 | 0 | 
| 2020-02-29 | 1 | 0 | 
| ... | ... | ... | 
| 2020-07-14 | 41857 | 1300 | 
| 2020-07-15 | 39924 | 1233 | 
| 2020-07-16 | 45403 | 1322 | 
| 2020-07-17 | 34177 | 1163 | 
| 2020-07-18 | 28532 | 921 | 
145 rows × 2 columns
Vamos agora concatená-los por coluna:
pd.concat([covid_PB_casos_obitos, covid_BR_casos_obitos], axis=1)
| casosNovos | obitosNovos | casosBR | obitosBR | |
|---|---|---|---|---|
| data | ||||
| 2021-09-26 | 134.0 | 2.0 | NaN | NaN | 
| 2021-09-25 | 165.0 | 2.0 | NaN | NaN | 
| 2021-09-24 | 225.0 | 3.0 | NaN | NaN | 
| 2021-09-23 | 203.0 | 3.0 | NaN | NaN | 
| 2021-09-22 | 297.0 | 6.0 | NaN | NaN | 
| ... | ... | ... | ... | ... | 
| 2020-03-11 | NaN | NaN | 18.0 | 0.0 | 
| 2020-03-12 | NaN | NaN | 25.0 | 0.0 | 
| 2020-03-13 | NaN | NaN | 21.0 | 0.0 | 
| 2020-03-14 | NaN | NaN | 23.0 | 0.0 | 
| 2020-03-15 | NaN | NaN | 79.0 | 0.0 | 
579 rows × 4 columns
Para um polimento final, vamos substituir os valores NaN que ocorreram antes do dia 13 de julho por 0. Para tanto, a forma ideal é utilizando o método map:
dados_PB_BR = pd.concat([covid_PB_casos_obitos, covid_BR_casos_obitos], axis=1)
dados_PB_BR['casosNovos'] = dados_PB_BR.casosNovos.map(lambda caso: 0 if np.isnan(caso) else caso).astype('int')
dados_PB_BR['obitosNovos'] = dados_PB_BR.obitosNovos.map(lambda obito: 0 if np.isnan(obito) else obito).astype('int')
dados_PB_BR
| casosNovos | obitosNovos | casosBR | obitosBR | |
|---|---|---|---|---|
| data | ||||
| 2021-09-26 | 134 | 2 | NaN | NaN | 
| 2021-09-25 | 165 | 2 | NaN | NaN | 
| 2021-09-24 | 225 | 3 | NaN | NaN | 
| 2021-09-23 | 203 | 3 | NaN | NaN | 
| 2021-09-22 | 297 | 6 | NaN | NaN | 
| ... | ... | ... | ... | ... | 
| 2020-03-11 | 0 | 0 | 18.0 | 0.0 | 
| 2020-03-12 | 0 | 0 | 25.0 | 0.0 | 
| 2020-03-13 | 0 | 0 | 21.0 | 0.0 | 
| 2020-03-14 | 0 | 0 | 23.0 | 0.0 | 
| 2020-03-15 | 0 | 0 | 79.0 | 0.0 | 
579 rows × 4 columns
Mesclando DataFrames através de joins¶
Para realizar joins iremos utilizar a função merge do pandas. joins tomam duas tabelas, uma tabela à esquerda e uma à direita e retornam uma terceira tabela contendo a união das colunas das duas tabelas.
Existem 4 tipos de joins:
left join: Apenas irão aparecer os index (da linha) que existem na tabela à esquerda;
right join: Apenas irão aparecer os index (da linha) que existem na tabela à direita;
inner join: Apenas irão aparecer os index que existem nas duas tabelas;
full join ou outer join: irão aparecer todos os index das duas tabelas.
Para exemplificar vamos considerar dois DataFrames (aqui teremos menos linhas, com nomes e dados fictícios). O primeiro DataFrame consistirá de nomes de alunos, CPF e matrícula da UFPB (nome_cpf_mat). O segundo DataFrame consistirá de nome, CPF e e-mail (nome_cpf_email). Nosso objetivo é criar um novo DataFrame contendo Nome, CPF, matrícula e e-mail.
Temos ainda as seguintes situações:
No DataFrame nome_cpf_mat existem alunos que não estão presentes no nome_cpf_email, pois não enviaram esta informação.
No DataFrame nome_cpf_email existem alunos que não estão presentes no nome_cpf_mat pois estes não são alunos da UFPB.
nome_cpf_mat = pd.read_csv('../database/nome_cpf_mat.csv')
nome_cpf_email = pd.read_csv('../database/nome_cpf_email.csv')
Vamos agora examinar os DataFrames. Como são bem simples, basta realizar prints deles.
nome_cpf_mat
| Nome | CPF | Matricula | |
|---|---|---|---|
| 0 | João Paulo | 326.475.190-99 | 8848484 | 
| 1 | Ana Silva | 073.101.240-22 | 8451212 | 
| 2 | Antonio Carlos | 830.060.930-03 | 5151213 | 
| 3 | Debora Santos | 472.006.460-40 | 51848484 | 
| 4 | Rodrigo Gomes | 566.712.550-16 | 1415816 | 
| 5 | Edson Jardim | 308.226.400-07 | 9592303 | 
nome_cpf_email
| Nome | CPF | ||
|---|---|---|---|
| 0 | João Paulo | 326.475.190-99 | joao@inventado.com.br | 
| 1 | Ana Silva | 073.101.240-22 | ana@inventado.com.br | 
| 2 | Antonio Carlos | 830.060.930-03 | antonio@inventado.com.br | 
| 3 | Saulo Santos | 370.981.810-99 | saulo@inventado.com.br | 
| 4 | Paulo Cardoso | 250.078.710-95 | paulo@inventado.com.br | 
| 5 | Edson Jardim | 308.226.400-07 | edson@inventado.com.br | 
| 6 | Ana Silva | 344.246.630-00 | anasilva@inventado.com.br | 
Tipicamente é bom possuir index únicos. Neste sentido, vamos definir o CPF como index:
nome_cpf_mat = nome_cpf_mat.set_index('CPF')
nome_cpf_email = nome_cpf_email.set_index('CPF')
Vamos agora realizar um left join com o DataFrame nome_cpf_mat ficando à esquerda (neste caso, apenas alunos com matrícula irão aparecer):
pd.merge(nome_cpf_mat, nome_cpf_email, how = 'left', on = ['Nome','CPF'])
| Nome | Matricula | ||
|---|---|---|---|
| CPF | |||
| 326.475.190-99 | João Paulo | 8848484 | joao@inventado.com.br | 
| 073.101.240-22 | Ana Silva | 8451212 | ana@inventado.com.br | 
| 830.060.930-03 | Antonio Carlos | 5151213 | antonio@inventado.com.br | 
| 472.006.460-40 | Debora Santos | 51848484 | NaN | 
| 566.712.550-16 | Rodrigo Gomes | 1415816 | NaN | 
| 308.226.400-07 | Edson Jardim | 9592303 | edson@inventado.com.br | 
Na opção how dizemos qual o tipo de join que queremos realizar.
Na opção on dizemos quais as colunas que existem em comum nos DataFrames.
Veja o que aconteceria se informássemos apenas que o CPF está presente nos dois DataFrames:
pd.merge(nome_cpf_mat, nome_cpf_email, how = 'left', on = 'CPF')
| Nome_x | Matricula | Nome_y | ||
|---|---|---|---|---|
| CPF | ||||
| 326.475.190-99 | João Paulo | 8848484 | João Paulo | joao@inventado.com.br | 
| 073.101.240-22 | Ana Silva | 8451212 | Ana Silva | ana@inventado.com.br | 
| 830.060.930-03 | Antonio Carlos | 5151213 | Antonio Carlos | antonio@inventado.com.br | 
| 472.006.460-40 | Debora Santos | 51848484 | NaN | NaN | 
| 566.712.550-16 | Rodrigo Gomes | 1415816 | NaN | NaN | 
| 308.226.400-07 | Edson Jardim | 9592303 | Edson Jardim | edson@inventado.com.br | 
Observe que os nomes dos alunos que estão na segunda tabela ficam indeterminados na coluna Nome_y.
Vamos agora realizar um right join com o DataFrame nome_cpf_mat ficando à esquerda (neste caso, apenas alunos com e-mail irão aparecer):
pd.merge(nome_cpf_mat, nome_cpf_email, how = 'right', on = ['Nome','CPF'])
| Nome | Matricula | ||
|---|---|---|---|
| CPF | |||
| 326.475.190-99 | João Paulo | 8848484.0 | joao@inventado.com.br | 
| 073.101.240-22 | Ana Silva | 8451212.0 | ana@inventado.com.br | 
| 830.060.930-03 | Antonio Carlos | 5151213.0 | antonio@inventado.com.br | 
| 370.981.810-99 | Saulo Santos | NaN | saulo@inventado.com.br | 
| 250.078.710-95 | Paulo Cardoso | NaN | paulo@inventado.com.br | 
| 308.226.400-07 | Edson Jardim | 9592303.0 | edson@inventado.com.br | 
| 344.246.630-00 | Ana Silva | NaN | anasilva@inventado.com.br | 
Vamos agora realizar um inner join com o DataFrame nome_cpf_mat ficando à esquerda (neste caso, apenas alunos com matrícula e com e-mail irão aparecer):
pd.merge(nome_cpf_mat, nome_cpf_email, how = 'inner', on = ['Nome','CPF'])
| Nome | Matricula | ||
|---|---|---|---|
| CPF | |||
| 326.475.190-99 | João Paulo | 8848484 | joao@inventado.com.br | 
| 073.101.240-22 | Ana Silva | 8451212 | ana@inventado.com.br | 
| 830.060.930-03 | Antonio Carlos | 5151213 | antonio@inventado.com.br | 
| 308.226.400-07 | Edson Jardim | 9592303 | edson@inventado.com.br | 
Por fim, vamos agora realizar um outer ou full join com o DataFrame nome_cpf_mat ficando à esquerda (neste caso, todos os alunos irão aparecer):
pd.merge(nome_cpf_mat, nome_cpf_email, how = 'outer', on = ['Nome','CPF'])
| Nome | Matricula | ||
|---|---|---|---|
| CPF | |||
| 326.475.190-99 | João Paulo | 8848484.0 | joao@inventado.com.br | 
| 073.101.240-22 | Ana Silva | 8451212.0 | ana@inventado.com.br | 
| 830.060.930-03 | Antonio Carlos | 5151213.0 | antonio@inventado.com.br | 
| 472.006.460-40 | Debora Santos | 51848484.0 | NaN | 
| 566.712.550-16 | Rodrigo Gomes | 1415816.0 | NaN | 
| 308.226.400-07 | Edson Jardim | 9592303.0 | edson@inventado.com.br | 
| 370.981.810-99 | Saulo Santos | NaN | saulo@inventado.com.br | 
| 250.078.710-95 | Paulo Cardoso | NaN | paulo@inventado.com.br | 
| 344.246.630-00 | Ana Silva | NaN | anasilva@inventado.com.br | 
Os métodos apply, map e applymap¶
A ideia é relativamente simples. Os três métodos são vetorizados e aplicam uma função ou uma substituição via dicionário de tal forma que:
apply é realizado via linha ou coluna em um DataFrame;
map é aplicado a cada elemento de uma Series;
applymap é aplicado a cada elemento de um DataFrame.
Já vimos diversos exemplos de uso de map. Vejamos exemplos de applymap e apply.
Neste exemplo vamos retomar a concatenação entre os dados da Paraíba e do Brasil, porém iremos substituir todos os valores de
NaNpor zero, usando o métodpapplymap.
dados_PB_BR = pd.concat([covid_PB_casos_obitos, covid_BR_casos_obitos], axis=1)
dados_PB_BR.applymap(lambda valor: 0 if np.isnan(valor) else valor)
| casosNovos | obitosNovos | casosBR | obitosBR | |
|---|---|---|---|---|
| data | ||||
| 2021-09-26 | 134.0 | 2.0 | 0.0 | 0.0 | 
| 2021-09-25 | 165.0 | 2.0 | 0.0 | 0.0 | 
| 2021-09-24 | 225.0 | 3.0 | 0.0 | 0.0 | 
| 2021-09-23 | 203.0 | 3.0 | 0.0 | 0.0 | 
| 2021-09-22 | 297.0 | 6.0 | 0.0 | 0.0 | 
| ... | ... | ... | ... | ... | 
| 2020-03-11 | 0.0 | 0.0 | 18.0 | 0.0 | 
| 2020-03-12 | 0.0 | 0.0 | 25.0 | 0.0 | 
| 2020-03-13 | 0.0 | 0.0 | 21.0 | 0.0 | 
| 2020-03-14 | 0.0 | 0.0 | 23.0 | 0.0 | 
| 2020-03-15 | 0.0 | 0.0 | 79.0 | 0.0 | 
579 rows × 4 columns
Vamos utilizar apply para realizar a soma de casos e óbitos através de mais de uma forma
dados_PB_BR.apply(lambda x: np.sum(x)).astype('int')
casosNovos      440037
obitosNovos       9294
casosBR        2074860
obitosBR         78772
dtype: int64
Se quisermos realizar a operação por linhas, basta utilizar o argumento axis=1:
dados_PB_BR.apply(lambda x: (x>0).all(), axis=1)
data
2021-09-26    False
2021-09-25    False
2021-09-24    False
2021-09-23    False
2021-09-22    False
              ...  
2020-03-11    False
2020-03-12    False
2020-03-13    False
2020-03-14    False
2020-03-15    False
Length: 579, dtype: bool