Manipulação de dados - II

DataFrames

Como dissemos anterioremente, o DataFrame é a segunda estrutura basilar do pandas. Um DataFrame:

  • é uma tabela, ou seja, é bidimensional;

  • tem cada coluna formada como uma Series do pandas;

  • pode ter Series contendo tipos de dado diferentes.

import numpy as np
import pandas as pd

Criação de um DataFrame

O método padrão para criarmos um DataFrame é através de uma função com mesmo nome.

df_exemplo = pd.DataFrame(dados_de_interesse, index = indice_de_interesse, 
                          columns = colunas_de_interesse)

Ao criar um DataFrame, podemos informar

  • index: rótulos para as linhas (atributos index das Series).

  • columns: rótulos para as colunas (atributos name das Series).

No template, dados_de_interesse pode ser

  • um dicionário de:

    • arrays unidimensionais do numpy;

    • listas;

    • dicionários;

    • Series do pandas.

  • um array bidimensional do numpy;

  • uma Series do Pandas;

  • outro DataFrame.

DataFrame a partir de dicionários de Series

Neste método de criação, as Series do dicionário não precisam possuir o mesmo número de elementos. O index do DataFrame será dado pela união dos index de todas as Series contidas no dicionário.

Exemplo:

serie_Idade = pd.Series({'Ana':20, 'João': 19, 'Maria': 21, 'Pedro': 22}, name="Idade")
serie_Peso = pd.Series({'Ana':55, 'João': 80, 'Maria': 62, 'Pedro': 67, 'Túlio': 73}, name="Peso")
serie_Altura = pd.Series({'Ana':162, 'João': 178, 'Maria': 162, 'Pedro': 165, 'Túlio': 171}, name="Altura")
dicionario_series_exemplo = {'Idade': serie_Idade, 'Peso': serie_Peso, 'Altura': serie_Altura}
df_dict_series = pd.DataFrame(dicionario_series_exemplo)
df_dict_series
Idade Peso Altura
Ana 20.0 55 162
João 19.0 80 178
Maria 21.0 62 162
Pedro 22.0 67 165
Túlio NaN 73 171

Compare este resultado com a criação de uma planilha pelos métodos usuais. Veja que há muita flexibilidade para criarmos ou modificarmos uma tabela.

Vejamos exemplos sobre como acessar intervalos de dados na tabela.

pd.DataFrame(dicionario_series_exemplo, index=['Ana','Maria'])
Idade Peso Altura
Ana 20 55 162
Maria 21 62 162
pd.DataFrame(dicionario_series_exemplo, index=['Ana','Maria'], columns=['Peso','Altura'])
Peso Altura
Ana 55 162
Maria 62 162

Neste exemplo, adicionamos a coluna IMC, ainda sem valores calculados.

pd.DataFrame(dicionario_series_exemplo, index=['Ana','Maria','Paula'], 
             columns=['Peso','Altura','IMC'])
Peso Altura IMC
Ana 55.0 162.0 NaN
Maria 62.0 162.0 NaN
Paula NaN NaN NaN
df_exemplo_IMC = pd.DataFrame(dicionario_series_exemplo, 
             columns=['Peso','Altura','IMC'])

Agora, mostramos como os valores do IMC podem ser calculados diretamente por computação vetorizada sobre as Series.

df_exemplo_IMC['IMC']=round(df_exemplo_IMC['Peso']/(df_exemplo_IMC['Altura']/100)**2,2)
df_exemplo_IMC
Peso Altura IMC
Ana 55 162 20.96
João 80 178 25.25
Maria 62 162 23.62
Pedro 67 165 24.61
Túlio 73 171 24.96

DataFrame a partir de dicionários de listas ou arrays do numpy

Neste método de criação, os arrays ou as listas devem possuir o mesmo comprimento. Se o index não for informado, o index será dado de forma similar ao do objeto tipo Series.

Exemplo com dicionário de listas:

dicionario_lista_exemplo = {'Idade': [20,19,21,22,20],
                            'Peso': [55,80,62,67,73],
                            'Altura': [162,178,162,165,171]}
pd.DataFrame(dicionario_lista_exemplo)
Idade Peso Altura
0 20 55 162
1 19 80 178
2 21 62 162
3 22 67 165
4 20 73 171

Mais exemplos:

pd.DataFrame(dicionario_lista_exemplo, index=['Ana','João','Maria','Pedro','Túlio'])
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171

Exemplos com dicionário de arrays do numpy:

dicionario_array_exemplo = {'Idade': np.array([20,19,21,22,20]),
                            'Peso': np.array([55,80,62,67,73]),
                            'Altura': np.array([162,178,162,165,171])}
pd.DataFrame(dicionario_array_exemplo)
Idade Peso Altura
0 20 55 162
1 19 80 178
2 21 62 162
3 22 67 165
4 20 73 171

Mais exemplos:

pd.DataFrame(dicionario_array_exemplo, index=['Ana','João','Maria','Pedro','Túlio'])
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171

DataFrame a partir de uma Series do pandas

Neste caso, o DataFrame terá o mesmo index que a Series do pandas e apenas uma coluna.

series_exemplo = pd.Series({'Ana':20, 'João': 19, 'Maria': 21, 'Pedro': 22, 'Túlio': 20})
pd.DataFrame(series_exemplo)
0
Ana 20
João 19
Maria 21
Pedro 22
Túlio 20

Caso a Series possua um atributo name especificado, este será o nome da coluna do DataFrame.

series_exemplo_Idade = pd.Series({'Ana':20, 'João': 19, 'Maria': 21, 'Pedro': 22, 'Túlio': 20}, name="Idade")
pd.DataFrame(series_exemplo_Idade)
Idade
Ana 20
João 19
Maria 21
Pedro 22
Túlio 20

DataFrame a partir de lista de Series do pandas

Neste caso, a entrada dos dados da lista no DataFrame será feita por linha.

pd.DataFrame([serie_Peso, serie_Altura, serie_Idade])
Ana João Maria Pedro Túlio
Peso 55.0 80.0 62.0 67.0 73.0
Altura 162.0 178.0 162.0 165.0 171.0
Idade 20.0 19.0 21.0 22.0 NaN

Podemos corrigir a orientação usando o método transpose.

pd.DataFrame([serie_Peso, serie_Altura, serie_Idade]).transpose()
Peso Altura Idade
Ana 55.0 162.0 20.0
João 80.0 178.0 19.0
Maria 62.0 162.0 21.0
Pedro 67.0 165.0 22.0
Túlio 73.0 171.0 NaN

DataFrame a partir de arquivos

Para criar um DataFrame a partir de um arquivo, precisamos de funções do tipo pd.read_FORMATO, onde FORMATO indica o formato a ser importado sob o pressuposto de que a biblioteca pandas foi devidamente importada com pd.

Os formatos mais comuns são:

  • csv (comma-separated values),

  • xls ou xlsx (formatos do Microsoft Excel),

  • hdf5 (comumente utilizado em big data),

  • json (comumente utilizado em páginas da internet).

As funções para leitura correspondentes são:

  • pd.read_csv,

  • pd.read_excel,

  • pd.read_hdf,

  • pd.read_json,

respectivamente.

De todas elas, a função mais utilizada é read_csv. Ela possui vários argumentos. Vejamos os mais utilizados:

  • file_path_or_buffer: o endereço do arquivo a ser lido. Pode ser um endereço da internet.

  • sep: o separador entre as entradas de dados. O separador padrão é ,.

  • index_col: a coluna que deve ser usada para formar o index. O padrão é None. Porém pode ser alterado para outro. Um separador comumente encontrado é o \t (TAB).

  • names: nomes das colunas a serem usadas. O padrão é None.

  • header: número da linha que servirá como nome para as colunas. O padrão é infer (ou seja, tenta deduzir automaticamente). Se os nomes das colunas forem passados através do names, então header será automaticamente considerado como None.

Exemplo: considere o arquivo data/exemplo_data.csv contendo:

,coluna_1,coluna_2
2020-01-01,-0.4160923582996922,1.8103644347460834
2020-01-02,-0.1379696602473578,2.5785204825192785
2020-01-03,0.5758273450544708,0.06086648807755068
2020-01-04,-0.017367186564883633,1.2995865328684455
2020-01-05,1.3842792448510655,-0.3817320973859929
2020-01-06,0.5497056238566345,-1.308789022968975
2020-01-07,-0.2822962331437976,-1.6889791765925102
2020-01-08,-0.9897300598660013,-0.028120707936426497
2020-01-09,0.27558240737928663,-0.1776585993494299
2020-01-10,0.6851316082235455,0.5025348904591399

Para ler o arquivo acima basta fazer:

df_exemplo_0 = pd.read_csv('../database/exemplo_data.csv')
df_exemplo_0
Unnamed: 0 coluna_1 coluna_2
0 2020-01-01 -0.416092 1.810364
1 2020-01-02 -0.137970 2.578520
2 2020-01-03 0.575827 0.060866
3 2020-01-04 -0.017367 1.299587
4 2020-01-05 1.384279 -0.381732
5 2020-01-06 0.549706 -1.308789
6 2020-01-07 -0.282296 -1.688979
7 2020-01-08 -0.989730 -0.028121
8 2020-01-09 0.275582 -0.177659
9 2020-01-10 0.685132 0.502535

No exemplo anterior, as colunas receberam nomes corretamentes exceto pela primeira coluna que gostaríamos de considerar como index. Neste caso fazemos:

df_exemplo = pd.read_csv('../database/exemplo_data.csv', index_col=0)
df_exemplo
coluna_1 coluna_2
2020-01-01 -0.416092 1.810364
2020-01-02 -0.137970 2.578520
2020-01-03 0.575827 0.060866
2020-01-04 -0.017367 1.299587
2020-01-05 1.384279 -0.381732
2020-01-06 0.549706 -1.308789
2020-01-07 -0.282296 -1.688979
2020-01-08 -0.989730 -0.028121
2020-01-09 0.275582 -0.177659
2020-01-10 0.685132 0.502535

O método head do DataFrame

O método head, sem argumento, permite que visualizemos as 5 primeiras linhas do DataFrame.

df_exemplo.head()
coluna_1 coluna_2
2020-01-01 -0.416092 1.810364
2020-01-02 -0.137970 2.578520
2020-01-03 0.575827 0.060866
2020-01-04 -0.017367 1.299587
2020-01-05 1.384279 -0.381732

Se for passado um argumento com valor n, as n primeiras linhas são impressas.

df_exemplo.head(2)
coluna_1 coluna_2
2020-01-01 -0.416092 1.810364
2020-01-02 -0.137970 2.578520
df_exemplo.head(7)
coluna_1 coluna_2
2020-01-01 -0.416092 1.810364
2020-01-02 -0.137970 2.578520
2020-01-03 0.575827 0.060866
2020-01-04 -0.017367 1.299587
2020-01-05 1.384279 -0.381732
2020-01-06 0.549706 -1.308789
2020-01-07 -0.282296 -1.688979

O método tail do DataFrame

O método tail, sem argumento, retorna as últimas 5 linhas do DataFrame.

df_exemplo.tail()
coluna_1 coluna_2
2020-01-06 0.549706 -1.308789
2020-01-07 -0.282296 -1.688979
2020-01-08 -0.989730 -0.028121
2020-01-09 0.275582 -0.177659
2020-01-10 0.685132 0.502535

Se for passado um argumento com valor n, as n últimas linhas são impressas.

df_exemplo.tail(2)
coluna_1 coluna_2
2020-01-09 0.275582 -0.177659
2020-01-10 0.685132 0.502535
df_exemplo.tail(7)
coluna_1 coluna_2
2020-01-04 -0.017367 1.299587
2020-01-05 1.384279 -0.381732
2020-01-06 0.549706 -1.308789
2020-01-07 -0.282296 -1.688979
2020-01-08 -0.989730 -0.028121
2020-01-09 0.275582 -0.177659
2020-01-10 0.685132 0.502535

Atributos de Series e DataFrames

Atributos comumente usados para Series e DataFrames são:

  • shape: fornece as dimensões do objeto em questão (Series ou DataFrame) em formato consistente com o atributo shape de um array do numpy.

  • index: fornece o índice do objeto. No caso do DataFrame são os rótulos das linhas.

  • columns: fornece as colunas (apenas disponível para DataFrames)

Exemplo:

df_exemplo.shape
(10, 2)
serie_1 = pd.Series([1,2,3,4,5])
serie_1.shape
(5,)
df_exemplo.index
Index(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05',
       '2020-01-06', '2020-01-07', '2020-01-08', '2020-01-09', '2020-01-10'],
      dtype='object')
serie_1.index
RangeIndex(start=0, stop=5, step=1)
df_exemplo.columns
Index(['coluna_1', 'coluna_2'], dtype='object')

Se quisermos obter os dados contidos nos index ou nas Series podemos utilizar a propriedade .array.

serie_1.index.array
<PandasArray>
[0, 1, 2, 3, 4]
Length: 5, dtype: int64
df_exemplo.columns.array
<PandasArray>
['coluna_1', 'coluna_2']
Length: 2, dtype: object

Se o interesse for obter os dados como um array do numpy, devemos utilizar o método .to_numpy().

Exemplo:

serie_1.index.to_numpy()
array([0, 1, 2, 3, 4])
df_exemplo.columns.to_numpy()
array(['coluna_1', 'coluna_2'], dtype=object)

O método .to_numpy() também está disponível em DataFrames:

df_exemplo.to_numpy()
array([[-0.41609236,  1.81036443],
       [-0.13796966,  2.57852048],
       [ 0.57582735,  0.06086649],
       [-0.01736719,  1.29958653],
       [ 1.38427924, -0.3817321 ],
       [ 0.54970562, -1.30878902],
       [-0.28229623, -1.68897918],
       [-0.98973006, -0.02812071],
       [ 0.27558241, -0.1776586 ],
       [ 0.68513161,  0.50253489]])

A função do numpy asarray() é compatível com index, columns e DataFrames do pandas:

np.asarray(df_exemplo.index)
array(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
       '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
       '2020-01-09', '2020-01-10'], dtype=object)
np.asarray(df_exemplo.columns)
array(['coluna_1', 'coluna_2'], dtype=object)
np.asarray(df_exemplo)
array([[-0.41609236,  1.81036443],
       [-0.13796966,  2.57852048],
       [ 0.57582735,  0.06086649],
       [-0.01736719,  1.29958653],
       [ 1.38427924, -0.3817321 ],
       [ 0.54970562, -1.30878902],
       [-0.28229623, -1.68897918],
       [-0.98973006, -0.02812071],
       [ 0.27558241, -0.1776586 ],
       [ 0.68513161,  0.50253489]])

Informações sobre as colunas de um DataFrame

Para obtermos uma breve descrição sobre as colunas de um DataFrame utilizamos o método info.

Exemplo:

df_exemplo.info()
<class 'pandas.core.frame.DataFrame'>
Index: 10 entries, 2020-01-01 to 2020-01-10
Data columns (total 2 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   coluna_1  10 non-null     float64
 1   coluna_2  10 non-null     float64
dtypes: float64(2)
memory usage: 240.0+ bytes

Criando arquivos a partir de DataFrames

Para criar arquivos a partir de DataFrames, basta utilizar os métodos do tipo pd.to_FORMATO, onde FORMATO indica o formato a ser exportado e supondo que a biblioteca pandas foi importada com pd.

Com relação aos tipos de arquivo anteriores, os métodos para exportação correspondentes são:

  • .to_csv (‘endereço_do_arquivo’),

  • .to_excel (‘endereço_do_arquivo’),

  • .to_hdf (‘endereço_do_arquivo’),

  • .to_json(‘endereço_do_arquivo’),

onde endereço_do_arquivo é uma str que contém o endereço do arquivo a ser exportado.

Exemplo:

Para exportar para o arquivo exemplo_novo.csv, utilizaremos o método .to_csv ao DataFrame df_exemplo:

df_exemplo.to_csv('../database/exemplo_novo.csv')

Exemplo COVID-19 PB

Dados diários de COVID-19 do estado da Paraíba:

Fonte: https://superset.plataformatarget.com.br/superset/dashboard/microdados/

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.info()
<class 'pandas.core.frame.DataFrame'>
Index: 559 entries, 2021-09-26 to 2020-03-16
Data columns (total 7 columns):
 #   Column            Non-Null Count  Dtype  
---  ------            --------------  -----  
 0   casosAcumulados   559 non-null    int64  
 1   casosNovos        559 non-null    int64  
 2   descartados       559 non-null    int64  
 3   recuperados       559 non-null    int64  
 4   obitosAcumulados  559 non-null    int64  
 5   obitosNovos       558 non-null    float64
 6   Letalidade        559 non-null    float64
dtypes: float64(2), int64(5)
memory usage: 34.9+ KB
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
dados_covid_PB.tail()
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
data
2020-03-20 0 0 0 0 0 0.0 0.0
2020-03-19 0 0 0 0 0 0.0 0.0
2020-03-18 0 0 0 0 0 0.0 0.0
2020-03-17 0 0 0 0 0 0.0 0.0
2020-03-16 0 0 0 0 0 0.0 0.0
dados_covid_PB['estado'] = 'PB'
dados_covid_PB.head()
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade estado
data
2021-09-26 441155 134 484336 333751 9294 2.0 0.0211 PB
2021-09-25 441021 165 484331 333441 9292 2.0 0.0211 PB
2021-09-24 440856 225 484301 332845 9290 3.0 0.0211 PB
2021-09-23 440631 203 484276 332540 9287 3.0 0.0211 PB
2021-09-22 440428 297 484265 331958 9284 6.0 0.0211 PB
dados_covid_PB.to_csv('../database/dadoscovidpb.csv')

Índices dos valores máximos ou mínimos

Os métodos idxmin() e idxmax() retornam o index cuja entrada fornece o valor mínimo ou máximo da Series ou DataFrame. Se houver múltiplas ocorrências de mínimos ou máximos, o método retorna a primeira ocorrência.

Vamos recriar um DataFrame genérico.

serie_Idade = pd.Series({'Ana':20, 'João': 19, 'Maria': 21, 'Pedro': 22, 'Túlio': 20}, name="Idade")
serie_Peso = pd.Series({'Ana':55, 'João': 80, 'Maria': 62, 'Pedro': 67, 'Túlio': 73}, name="Peso")
serie_Altura = pd.Series({'Ana':162, 'João': 178, 'Maria': 162, 'Pedro': 165, 'Túlio': 171}, name="Altura")
dicionario_series_exemplo = {'Idade': serie_Idade, 'Peso': serie_Peso, 'Altura': serie_Altura}
df_dict_series = pd.DataFrame(dicionario_series_exemplo)
df_dict_series
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171

Assim, podemos localizar quem possui menores idade, peso e altura.

df_dict_series.idxmin()
Idade     João
Peso       Ana
Altura     Ana
dtype: object

De igual forma, localizamos quem possui maiores idade, peso e altura.

df_dict_series.idxmax()
Idade     Pedro
Peso       João
Altura     João
dtype: object

Exemplo: Aplicaremos as funções idxmin() e idxmax() aos dados do arquivo data/exemplo_data.csv para localizar entradas de interesse.

df_exemplo = pd.read_csv('../database/exemplo_data.csv', index_col=0); df_exemplo
coluna_1 coluna_2
2020-01-01 -0.416092 1.810364
2020-01-02 -0.137970 2.578520
2020-01-03 0.575827 0.060866
2020-01-04 -0.017367 1.299587
2020-01-05 1.384279 -0.381732
2020-01-06 0.549706 -1.308789
2020-01-07 -0.282296 -1.688979
2020-01-08 -0.989730 -0.028121
2020-01-09 0.275582 -0.177659
2020-01-10 0.685132 0.502535
df_exemplo = pd.DataFrame(df_exemplo, columns=['coluna_1','coluna_2','coluna_3'])

Inserimos uma terceira coluna com dados fictícios.

df_exemplo['coluna_3'] = pd.Series([1,2,3,4,5,6,7,8,np.nan,np.nan],index=df_exemplo.index)
df_exemplo
coluna_1 coluna_2 coluna_3
2020-01-01 -0.416092 1.810364 1.0
2020-01-02 -0.137970 2.578520 2.0
2020-01-03 0.575827 0.060866 3.0
2020-01-04 -0.017367 1.299587 4.0
2020-01-05 1.384279 -0.381732 5.0
2020-01-06 0.549706 -1.308789 6.0
2020-01-07 -0.282296 -1.688979 7.0
2020-01-08 -0.989730 -0.028121 8.0
2020-01-09 0.275582 -0.177659 NaN
2020-01-10 0.685132 0.502535 NaN

Os index correspondentes aos menores e maiores valores são datas, evidentemente.

df_exemplo.idxmin()
coluna_1    2020-01-08
coluna_2    2020-01-07
coluna_3    2020-01-01
dtype: object
df_exemplo.idxmax()
coluna_1    2020-01-05
coluna_2    2020-01-02
coluna_3    2020-01-08
dtype: object

Reindexação de DataFrames

No pandas, o método reindex

  • reordena o DataFrame de acordo com o conjunto de rótulos inserido como argumento;

  • insere valores faltantes caso um rótulo do novo index não tenha valor atribuído no conjunto de dados;

  • remove valores correspondentes a rótulos que não estão presentes no novo index.

Exemplos:

df_dict_series.reindex(index=['Victor', 'Túlio', 'Pedro', 'João'], columns=['Altura','Peso','IMC'])
Altura Peso IMC
Victor NaN NaN NaN
Túlio 171.0 73.0 NaN
Pedro 165.0 67.0 NaN
João 178.0 80.0 NaN

Remoção de linhas ou colunas de um DataFrame

Para remover linhas ou colunas de um DataFrame do pandas podemos utilizar o método drop. O argumento axis identifica o eixo de remoção: axis=0, que é o padrão, indica a remoção de uma ou mais linhas; axis=1 indica a remoção de uma ou mais colunas.

Nos exemplos que segue, note que novos DataFrames são obtidos a partir de df_dict_series sem que este seja sobrescrito.

df_dict_series.drop('Túlio') # axis=0 implícito 
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
df_dict_series.drop(['Ana','Maria'], axis=0)
Idade Peso Altura
João 19 80 178
Pedro 22 67 165
Túlio 20 73 171
df_dict_series.drop(['Idade'], axis=1)
Peso Altura
Ana 55 162
João 80 178
Maria 62 162
Pedro 67 165
Túlio 73 171

Renomeando index e columns

O método rename retorna uma cópia na qual o index (no caso de Series e DataFrames) e columns (no caso de DataFrames) foram renomeados. O método aceita como entrada um dicionário, uma Series do pandas ou uma função.

Exemplo:

serie_exemplo = pd.Series([1,2,3], index=['a','b','c'])
serie_exemplo
a    1
b    2
c    3
dtype: int64
serie_exemplo.rename({'a':'abacaxi', 'b':'banana', 'c': 'cebola'})
abacaxi    1
banana     2
cebola     3
dtype: int64

Exemplo:

df_dict_series
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171
df_dict_series.rename(index = {'Ana':'a', 'João':'j', 'Maria':'m', 'Pedro':'p','Túlio':'t'},
                     columns = {'Idade':'I', 'Peso':'P','Altura':'A'})
I P A
a 20 55 162
j 19 80 178
m 21 62 162
p 22 67 165
t 20 73 171

No próximo exemplo, usamos uma Series para renomear os rótulos.

indice_novo = pd.Series({'Ana':'a', 'João':'j', 'Maria':'m', 'Pedro':'p','Túlio':'t'})
df_dict_series.rename(index = indice_novo)
Idade Peso Altura
a 20 55 162
j 19 80 178
m 21 62 162
p 22 67 165
t 20 73 171

Neste exemplo, usamos a função str.upper (altera a str para “todas maiúsculas”) para renomear colunas.

df_dict_series.rename(columns=str.upper)
IDADE PESO ALTURA
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171

Ordenação de Series e DataFrames

É possível ordenar ambos pelos rótulos do index (para tanto é necessário que eles sejam ordenáveis) ou por valores nas colunas.

O método sort_index ordena a Series ou o DataFrame pelo index. O método sort_values ordena a Series ou o DataFrame pelos valores (escolhendo uma ou mais colunas no caso de DataFrames). No caso do DataFrame, o argumento by é necessário para indicar qual(is) coluna(s) será(ão) utilizada(s) como base para a ordenação.

Exemplos:

serie_desordenada = pd.Series({'Maria': 21, 'Pedro': 22, 'Túlio': 20, 'João': 19, 'Ana':20}); 
serie_desordenada
Maria    21
Pedro    22
Túlio    20
João     19
Ana      20
dtype: int64
serie_desordenada.sort_index() # ordenação alfabética
Ana      20
João     19
Maria    21
Pedro    22
Túlio    20
dtype: int64

Mais exemplos:

df_desordenado = df_dict_series.reindex(index=['Pedro','Maria','Ana','Túlio','João'])
df_desordenado
Idade Peso Altura
Pedro 22 67 165
Maria 21 62 162
Ana 20 55 162
Túlio 20 73 171
João 19 80 178
df_desordenado.sort_index()
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171

Mais exemplos:

serie_desordenada.sort_values()
João     19
Túlio    20
Ana      20
Maria    21
Pedro    22
dtype: int64
df_desordenado.sort_values(by=['Altura']) # ordena por 'Altura'
Idade Peso Altura
Maria 21 62 162
Ana 20 55 162
Pedro 22 67 165
Túlio 20 73 171
João 19 80 178

No caso de “empate”, podemos utilizar outra coluna para desempatar.

df_desordenado.sort_values(by=['Altura','Peso']) # usa a coluna 'Peso' para desempatar
Idade Peso Altura
Ana 20 55 162
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171
João 19 80 178

Os métodos sort_index e sort_values admitem o argumento opcional ascending, que permite inverter a ordenação caso tenha valor False.

df_desordenado.sort_index(ascending=False)
Idade Peso Altura
Túlio 20 73 171
Pedro 22 67 165
Maria 21 62 162
João 19 80 178
Ana 20 55 162
df_desordenado.sort_values(by=['Idade'], ascending=False)
Idade Peso Altura
Pedro 22 67 165
Maria 21 62 162
Ana 20 55 162
Túlio 20 73 171
João 19 80 178

Comparação de Series e DataFrames

Series e DataFrames possuem os seguintes métodos de comparação lógica:

  • eq (igual);

  • ne (diferente);

  • lt (menor do que);

  • gt (maior do que);

  • le (menor ou igual a);

  • ge (maior ou igual a)

que permitem a utilização dos operadores binários ==, !=, <, >, <= e >=, respectivamente. As comparações são realizadas em cada entrada da Series ou do DataFrame.

Observação: Para que esses métodos sejam aplicados, todos os objetos presentes nas colunas do DataFrame devem ser de mesma natureza. Por exemplo, se um DataFrame possui algumas colunas numéricas e outras com strings, ao realizar uma comparação do tipo > 1, um erro ocorrerá, pois o pandas tentará comparar objetos do tipo int com objetos do tipo str, assim gerando uma incompatibilidade.

Exemplos:

serie_exemplo
a    1
b    2
c    3
dtype: int64
serie_exemplo == 2
a    False
b     True
c    False
dtype: bool

De outra forma:

serie_exemplo.eq(2)
a    False
b     True
c    False
dtype: bool
serie_exemplo > 1
a    False
b     True
c     True
dtype: bool

Ou, na forma funcional:

serie_exemplo.gt(1)
a    False
b     True
c     True
dtype: bool
df_exemplo > 1
coluna_1 coluna_2 coluna_3
2020-01-01 False True False
2020-01-02 False True True
2020-01-03 False False True
2020-01-04 False True True
2020-01-05 True False True
2020-01-06 False False True
2020-01-07 False False True
2020-01-08 False False True
2020-01-09 False False False
2020-01-10 False False False

Importante: Ao comparar np.nan, o resultado tipicamente é falso:

np.nan == np.nan
False
np.nan > np.nan
False
np.nan >= np.nan
False

Só é verdadeiro para indicar que é diferente:

np.nan != np.nan
True

Neste sentido, podemos ter tabelas iguais sem que a comparação usual funcione:

# 'copy', como o nome sugere, gera uma cópia do DataFrame
df_exemplo_2 = df_exemplo.copy() 
(df_exemplo == df_exemplo_2)
coluna_1 coluna_2 coluna_3
2020-01-01 True True True
2020-01-02 True True True
2020-01-03 True True True
2020-01-04 True True True
2020-01-05 True True True
2020-01-06 True True True
2020-01-07 True True True
2020-01-08 True True True
2020-01-09 True True False
2020-01-10 True True False

O motivo de haver entradas como False ainda que df_exemplo_2 seja uma cópia exata de df_exemplo é a presença do np.nan. Neste caso, devemos utilizar o método equals para realizar a comparação.

df_exemplo.equals(df_exemplo_2)
True

Os métodos any, all e a propriedade empty

O método any é aplicado a entradas booleanas (verdadeiras ou falsas) e retorna verdadeiro se existir alguma entrada verdadeira, ou falso, se todas forem falsas. O método all é aplicado a entradas booleanas e retorna verdadeiro se todas as entradas forem verdadeiras, ou falso, se houver pelo menos uma entrada falsa. A propriedade empty retorna verdadeiro se a Series ou o DataFrame estiver vazio, ou falso caso contrário.

Exemplos:

serie_exemplo
a    1
b    2
c    3
dtype: int64
serie_exemplo_2 = serie_exemplo-2; 
serie_exemplo_2
a   -1
b    0
c    1
dtype: int64
(serie_exemplo_2 > 0).any()
True
(serie_exemplo > 1).all()
False

Este exemplo reproduz um valor False único.

(df_exemplo == df_exemplo_2).all().all()
False
serie_exemplo.empty
False

Mais exemplos:

(df_exemplo == df_exemplo_2).any()
coluna_1    True
coluna_2    True
coluna_3    True
dtype: bool
df_exemplo.empty
False
df_vazio = pd.DataFrame()
df_vazio.empty
True

Seleção de colunas de um DataFrame

Para selecionar colunas de um DataFrame, basta aplicar colchetes a uma lista contendo os nomes das colunas de interesse.

No exemplo abaixo, temos um DataFrame contendo as colunas 'Idade', 'Peso' e 'Altura'. Selecionaremos 'Peso' e 'Altura', apenas.

df_dict_series[['Peso','Altura']]
Peso Altura
Ana 55 162
João 80 178
Maria 62 162
Pedro 67 165
Túlio 73 171

Se quisermos selecionar apenas uma coluna, não há necessidade de inserir uma lista. Basta utilizar o nome da coluna:

df_dict_series['Peso']
Ana      55
João     80
Maria    62
Pedro    67
Túlio    73
Name: Peso, dtype: int64

Para remover colunas, podemos utilizar o método drop.

df_dict_series.drop(['Peso','Altura'], axis=1)
Idade
Ana 20
João 19
Maria 21
Pedro 22
Túlio 20

Criação de novas colunas a partir de colunas existentes

Um método eficiente para criar novas colunas a partir de colunas já existentes é eval. Neste método, podemos utilizar como argumento uma string contendo uma expressão matemática envolvendo nomes de colunas do DataFrame.

Como exemplo, vamos ver como calcular o IMC no DataFrame anterior:

df_dict_series.eval('Peso/(Altura/100)**2')
Ana      20.957171
João     25.249337
Maria    23.624447
Pedro    24.609734
Túlio    24.964946
dtype: float64

Se quisermos obter um DataFrame contendo o IMC como uma nova coluna, podemos utilizar o método assign (sem modificar o DataFrame original):

df_dict_series.assign(IMC=round(df_dict_series.eval('Peso/(Altura/100)**2'),2))
Idade Peso Altura IMC
Ana 20 55 162 20.96
João 19 80 178 25.25
Maria 21 62 162 23.62
Pedro 22 67 165 24.61
Túlio 20 73 171 24.96
df_dict_series # não modificado
Idade Peso Altura
Ana 20 55 162
João 19 80 178
Maria 21 62 162
Pedro 22 67 165
Túlio 20 73 171

Se quisermos modificar o DataFrame para incluir a coluna IMC fazemos:

df_dict_series['IMC']=round(df_dict_series.eval('Peso/(Altura/100)**2'),2)
df_dict_series # modificado "in-place"
Idade Peso Altura IMC
Ana 20 55 162 20.96
João 19 80 178 25.25
Maria 21 62 162 23.62
Pedro 22 67 165 24.61
Túlio 20 73 171 24.96

Seleção de linhas de um DataFrame

Podemos selecionar linhas de um DataFrame de diversas formas diferentes. Veremos agora algumas dessas formas.

Diferentemente da forma de selecionar colunas, para selecionar diretamente linhas de um DataFrame devemos utilizar o método loc (fornecendo o index, isto é, o rótulo da linha) ou o iloc (fornecendo a posição da linha):

Trabalharemos a seguir com um banco de dados atualizado sobre a COVID-19. Para tanto, importaremos o módulo datetime que nos auxiliará com datas.

import datetime
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)

# busca o banco na data D-1, visto que a atualização
# ocorre em D
ontem = (datetime.date.today() - datetime.timedelta(days=1)).strftime('%Y-%m-%d') 
dados_covid_PB.head(1)
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
data
2021-09-26 441155 134 484336 333751 9294 2.0 0.0211

Podemos ver as informações de um único dia como argumento. Para tanto, excluímos a coluna 'Letalidade' (valor não inteiro) e convertemos o restante para valores inteiros:

dados_covid_PB.loc[ontem].drop('Letalidade').astype('int')
casosAcumulados     441155
casosNovos             134
descartados         484336
recuperados         333751
obitosAcumulados      9294
obitosNovos              2
Name: 2021-09-26, dtype: int64

Podemos selecionar um intervalo de datas como argumento (excluindo letalidade):

dados_covid_PB.index = pd.to_datetime(dados_covid_PB.index) # Convertendo o index de string para data
dados_covid_PB.loc[pd.date_range('2021-02-01',periods=5,freq="D")].drop('Letalidade',axis=1) 
                #função pd.date_range é muito útil para criar índices a partir de datas.
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos
2021-02-01 192598 1014 234215 149235 4068 12.0
2021-02-02 193465 867 234366 149242 4082 14.0
2021-02-03 194519 1054 234902 149248 4096 14.0
2021-02-04 195482 963 235319 149792 4110 14.0
2021-02-05 196542 1060 236216 150169 4123 13.0

Podemos colocar uma lista como argumento:

dados_covid_PB.loc[pd.to_datetime(['2021-01-01','2021-02-01'])]
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
2021-01-01 167062 578 219890 127388 3680 8.0 0.0220
2021-02-01 192598 1014 234215 149235 4068 12.0 0.0211

Vamos agora examinar os dados da posição 100 (novamente excluindo a coluna letalidade e convertendo para inteiro):

dados_covid_PB.iloc[100].drop('Letalidade').astype('int')
casosAcumulados     371133
casosNovos            2555
descartados         328941
recuperados         243203
obitosAcumulados      8316
obitosNovos             47
Name: 2021-06-18 00:00:00, dtype: int64

Podemos colocar um intervalo como argumento:

dados_covid_PB.iloc[50:55].drop('Letalidade', axis=1).astype('int') 
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos
data
2021-08-07 424983 406 456236 298889 9049 12
2021-08-06 424577 423 455493 298554 9037 14
2021-08-05 424154 570 454357 297945 9023 5
2021-08-04 423584 872 453146 297222 9018 7
2021-08-03 422712 37 451358 296180 9011 8

Seleção de colunas com loc e iloc

Podemos selecionar colunas utilizando os métodos loc e iloc utilizando um argumento adicional.

dados_covid_PB.loc[:,['casosNovos','obitosNovos']]
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

dados_covid_PB.iloc[:,4:6] # fatiamento na coluna
obitosAcumulados obitosNovos
data
2021-09-26 9294 2.0
2021-09-25 9292 2.0
2021-09-24 9290 3.0
2021-09-23 9287 3.0
2021-09-22 9284 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

Seleção de linhas e colunas específicas com loc e iloc

Usando o mesmo princípio de fatiamento aplicado a arrays do numpy, podemos selecionar linhas e colunas em um intervalo específico de forma a obter uma subtabela.

dados_covid_PB.iloc[95:100,4:6]
obitosAcumulados obitosNovos
data
2021-06-23 8453 20.0
2021-06-22 8433 22.0
2021-06-21 8411 30.0
2021-06-20 8381 33.0
2021-06-19 8348 32.0

Neste exemplo um pouco mais complexo, buscamos casos novos e óbitos novos em um período específico e ordenamos a tabela da data mais recente para a mais antiga.

dados_covid_PB.loc[pd.date_range('2020-04-06','2020-04-10'),['casosNovos','obitosNovos']].sort_index(ascending=False)
casosNovos obitosNovos
2020-04-10 6 0.0
2020-04-09 24 4.0
2020-04-08 14 3.0
2020-04-07 5 0.0
2020-04-06 1 0.0

Suponha que o peso de Ana foi medido corretamente, mas registrado de maneira errônea no DataFrame df_dict_series como 55.

df_dict_series
Idade Peso Altura IMC
Ana 20 55 162 20.96
João 19 80 178 25.25
Maria 21 62 162 23.62
Pedro 22 67 165 24.61
Túlio 20 73 171 24.96

Supondo que, na realidade, o valor é 65, alteramos a entrada específica com um simples loc. Em seguida, atualizamos a tabela.

df_dict_series.loc['Ana','Peso'] = 65

df_dict_series = df_dict_series.assign(IMC=round(df_dict_series.eval('Peso/(Altura/100)**2'),2)) # O IMC mudou
df_dict_series
Idade Peso Altura IMC
Ana 20 65 162 24.77
João 19 80 178 25.25
Maria 21 62 162 23.62
Pedro 22 67 165 24.61
Túlio 20 73 171 24.96

Seleção de linhas através de critérios lógicos ou funções

Vamos selecionar quais os dias em que houve mais de 40 mortes registradas:

dados_covid_PB.loc[dados_covid_PB['obitosNovos']>40]
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
data
2021-06-18 371133 2555 328941 243203 8316 47.0 0.0224
2021-06-11 354715 2451 322301 235778 8058 55.0 0.0227
2021-06-10 352264 3911 231258 235329 8003 46.0 0.0227
2021-04-27 289319 1037 290111 204340 6722 46.0 0.0232
2021-04-19 280967 904 286168 194644 6487 43.0 0.0231
2021-04-14 275301 1218 282121 193451 6316 42.0 0.0229
2021-04-12 272811 1486 279801 193188 6234 58.0 0.0229
2021-04-07 267008 1551 274623 189753 6050 49.0 0.0227
2021-04-06 265457 817 273026 186879 6001 52.0 0.0226
2021-04-05 264640 1059 272719 186670 5949 43.0 0.0225
2021-04-03 262500 789 272207 186334 5866 46.0 0.0223
2021-04-01 260484 1311 271069 186084 5791 47.0 0.0222
2021-03-31 259173 1553 270560 183668 5744 73.0 0.0222
2021-03-30 257620 1150 269399 183369 5671 70.0 0.0220
2021-03-29 256470 968 268985 183028 5601 49.0 0.0218
2021-03-28 255502 1203 268866 182873 5552 43.0 0.0217
2021-03-27 254299 1410 268309 182680 5509 57.0 0.0217
2021-03-26 252889 1611 266785 182404 5452 48.0 0.0216
2021-03-25 251278 1672 265533 180125 5404 50.0 0.0215
2021-03-24 249606 1154 264150 177812 5354 41.0 0.0214
2021-03-23 248452 1140 264146 177591 5313 41.0 0.0214
2021-03-20 245564 1300 264128 174980 5212 45.0 0.0212
2021-03-19 244264 1269 264122 174769 5167 44.0 0.0212
2021-03-18 242995 1403 258188 172789 5123 43.0 0.0211
2021-03-17 241592 1194 256574 172492 5080 44.0 0.0210
2021-03-16 240398 804 255491 172218 5036 44.0 0.0209
2021-03-15 239594 1025 255162 171911 4992 59.0 0.0208
2021-03-10 232771 1365 251742 170510 4797 50.0 0.0206
2021-03-04 225672 1385 245919 164712 4612 54.0 0.0204
2020-07-21 68844 1164 78605 25028 1558 41.0 0.0226
2020-07-15 63939 1477 74399 23695 1383 41.0 0.0216
2020-07-02 49536 1361 48272 16349 1044 42.0 0.0211
2020-06-30 46957 1900 43070 14930 977 46.0 0.0208

Selecionando os dias com mais de 25 óbitos e mais de 1500 casos novos:

dados_covid_PB.loc[(dados_covid_PB.obitosNovos > 25) & (dados_covid_PB.casosNovos>1500)]
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
data
2021-07-02 398440 1536 332530 262757 8654 26.0 0.0217
2021-06-24 385018 2391 332313 250519 8479 26.0 0.0220
2021-06-21 378064 2114 330969 249135 8411 30.0 0.0222
2021-06-20 375950 2178 330721 248667 8381 33.0 0.0223
2021-06-19 373772 2639 329903 248304 8348 32.0 0.0223
2021-06-18 371133 2555 328941 243203 8316 47.0 0.0224
2021-06-17 368578 2457 327929 242820 8269 32.0 0.0224
2021-06-16 366121 2328 326517 242184 8237 40.0 0.0225
2021-06-15 363793 2358 325032 241749 8197 39.0 0.0225
2021-06-14 361435 2575 324438 241293 8158 30.0 0.0226
2021-06-13 358860 2034 324327 236555 8128 33.0 0.0226
2021-06-12 356826 2111 323444 236186 8095 37.0 0.0227
2021-06-11 354715 2451 322301 235778 8058 55.0 0.0227
2021-06-10 352264 3911 231258 235329 8003 46.0 0.0227
2021-06-06 344174 1982 319055 230002 7849 29.0 0.0228
2021-06-05 342192 1992 318096 229790 7820 29.0 0.0229
2021-06-04 340200 2421 317390 229489 7791 26.0 0.0229
2021-06-03 337779 2660 316011 229062 7765 30.0 0.0230
2021-06-02 335119 2403 314538 225278 7735 32.0 0.0231
2021-06-01 332716 1751 314520 224912 7703 31.0 0.0232
2021-05-29 328771 2429 312011 224255 7617 28.0 0.0232
2021-05-28 326342 1917 311013 223896 7589 33.0 0.0233
2021-05-27 324425 1887 310639 223537 7556 36.0 0.0233
2021-05-26 322538 2262 309492 221134 7520 36.0 0.0233
2021-05-25 320276 2015 308275 220621 7484 36.0 0.0234
2021-04-07 267008 1551 274623 189753 6050 49.0 0.0227
2021-03-31 259173 1553 270560 183668 5744 73.0 0.0222
2021-03-26 252889 1611 266785 182404 5452 48.0 0.0216
2021-03-25 251278 1672 265533 180125 5404 50.0 0.0215
2021-03-13 237313 1694 254238 171130 4896 31.0 0.0206
2020-08-04 85760 1549 106500 38554 1901 31.0 0.0222
2020-07-31 82794 1686 96753 35971 1811 26.0 0.0219
2020-07-23 73104 2132 84047 28566 1618 37.0 0.0221
2020-07-10 59118 1504 69567 21481 1229 33.0 0.0208
2020-07-08 56344 1542 67549 19999 1171 26.0 0.0208
2020-07-07 54802 1651 64933 19373 1145 27.0 0.0209
2020-06-30 46957 1900 43070 14930 977 46.0 0.0208
2020-06-09 22452 1501 20650 4671 534 27.0 0.0238

Obs.: Note que podemos utilizar o nome da coluna como um atributo.

Vamos inserir uma coluna sobrenome no df_dict_series:

df_dict_series['Sobrenome'] = ['Silva', 'PraDo', 'Sales', 'MachadO', 'Coutinho']
df_dict_series
Idade Peso Altura IMC Sobrenome
Ana 20 65 162 24.77 Silva
João 19 80 178 25.25 PraDo
Maria 21 62 162 23.62 Sales
Pedro 22 67 165 24.61 MachadO
Túlio 20 73 171 24.96 Coutinho

Vamos encontrar as linhas cujo sobrenome termina em “do”. Para tanto, note que a função abaixo retorna True se o final é “do” e False caso contrário.

def verifica_final_do(palavra):
    return palavra.lower()[-2:] == 'do'

Obs.: Note que convertemos tudo para minúsculo.

Agora vamos utilizar essa função para alcançar nosso objetivo:

# 'map' aplica a função lambda a cada elemento da *Series*
df_dict_series['Sobrenome'].map(lambda palavra: palavra.lower()[-2:]=='do') 
Ana      False
João      True
Maria    False
Pedro     True
Túlio    False
Name: Sobrenome, dtype: bool
# procurando no df inteiro
df_dict_series.loc[df_dict_series['Sobrenome'].map(lambda palavra: palavra.lower()[-2:]=='do')]
Idade Peso Altura IMC Sobrenome
João 19 80 178 25.25 PraDo
Pedro 22 67 165 24.61 MachadO

Vamos selecionar as linhas do mês 2 (fevereiro) usando index.month:

dados_covid_PB.loc[dados_covid_PB.index.month==2].head()
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
data
2021-02-28 221115 1392 245686 158304 4496 25.0 0.0203
2021-02-27 219723 1416 245121 158132 4471 20.0 0.0203
2021-02-26 218307 1186 244356 157849 4451 18.0 0.0204
2021-02-25 217121 1594 243890 157586 4433 14.0 0.0204
2021-02-24 215527 1320 243253 157329 4419 15.0 0.0205

Seleção de linhas com o método query

Similarmente ao método eval, ao utilizarmos query, podemos criar expressões lógicas a partir de nomes das colunas do DataFrame.

Assim, podemos reescrever o código

dados_covid_PB.loc[(dados_covid_PB.obitosNovos>25) & 
                   (dados_covid_PB.casosNovos>1500)]

como

dados_covid_PB.query('obitosNovos>25 and casosNovos>1500') # note que 'and' é usado em vez de '&'
casosAcumulados casosNovos descartados recuperados obitosAcumulados obitosNovos Letalidade
data
2021-07-02 398440 1536 332530 262757 8654 26.0 0.0217
2021-06-24 385018 2391 332313 250519 8479 26.0 0.0220
2021-06-21 378064 2114 330969 249135 8411 30.0 0.0222
2021-06-20 375950 2178 330721 248667 8381 33.0 0.0223
2021-06-19 373772 2639 329903 248304 8348 32.0 0.0223
2021-06-18 371133 2555 328941 243203 8316 47.0 0.0224
2021-06-17 368578 2457 327929 242820 8269 32.0 0.0224
2021-06-16 366121 2328 326517 242184 8237 40.0 0.0225
2021-06-15 363793 2358 325032 241749 8197 39.0 0.0225
2021-06-14 361435 2575 324438 241293 8158 30.0 0.0226
2021-06-13 358860 2034 324327 236555 8128 33.0 0.0226
2021-06-12 356826 2111 323444 236186 8095 37.0 0.0227
2021-06-11 354715 2451 322301 235778 8058 55.0 0.0227
2021-06-10 352264 3911 231258 235329 8003 46.0 0.0227
2021-06-06 344174 1982 319055 230002 7849 29.0 0.0228
2021-06-05 342192 1992 318096 229790 7820 29.0 0.0229
2021-06-04 340200 2421 317390 229489 7791 26.0 0.0229
2021-06-03 337779 2660 316011 229062 7765 30.0 0.0230
2021-06-02 335119 2403 314538 225278 7735 32.0 0.0231
2021-06-01 332716 1751 314520 224912 7703 31.0 0.0232
2021-05-29 328771 2429 312011 224255 7617 28.0 0.0232
2021-05-28 326342 1917 311013 223896 7589 33.0 0.0233
2021-05-27 324425 1887 310639 223537 7556 36.0 0.0233
2021-05-26 322538 2262 309492 221134 7520 36.0 0.0233
2021-05-25 320276 2015 308275 220621 7484 36.0 0.0234
2021-04-07 267008 1551 274623 189753 6050 49.0 0.0227
2021-03-31 259173 1553 270560 183668 5744 73.0 0.0222
2021-03-26 252889 1611 266785 182404 5452 48.0 0.0216
2021-03-25 251278 1672 265533 180125 5404 50.0 0.0215
2021-03-13 237313 1694 254238 171130 4896 31.0 0.0206
2020-08-04 85760 1549 106500 38554 1901 31.0 0.0222
2020-07-31 82794 1686 96753 35971 1811 26.0 0.0219
2020-07-23 73104 2132 84047 28566 1618 37.0 0.0221
2020-07-10 59118 1504 69567 21481 1229 33.0 0.0208
2020-07-08 56344 1542 67549 19999 1171 26.0 0.0208
2020-07-07 54802 1651 64933 19373 1145 27.0 0.0209
2020-06-30 46957 1900 43070 14930 977 46.0 0.0208
2020-06-09 22452 1501 20650 4671 534 27.0 0.0238