Guia rápido de Pandas usando exploração de dados

Explorando uma base de dados para aprender o básico do Python Pandas

O Pandas é uma biblioteca Python para exploração, análise e manipulação de dados. Ela possui muitas ferramentas que nos auxiliam a trabalhar com bancos de dados como o MySQL, dados baseados em arquivos de texto como csv, json, html ou arquivos do Excel.

Open Source, poderoso e com uma curva de aprendizado baixa, é uma ótima ferramenta para iniciantes na linguagem Python e uma alternativa muito mais robusta para pessoas que usam o Excel como ferramenta de análise.

Sobre a Análise Exploratória de Dados

A Análise Exploratória de Dados (AED) é uma etapa fundamental no processo de análise de dados em ciência de dados e estatística. Ela envolve a exploração e o exame inicial dos dados para entender suas características, padrões, tendências e anomalias antes de aplicar técnicas mais avançadas de modelagem ou inferência estatística. A principal finalidade da AED é resumir, visualizar e compreender os dados, o que pode fornecer insights valiosos para direcionar as etapas subsequentes da análise de dados.

Neste artigo vamos utilizar um pouco da AED para aprender o básico de Pandas. De quebra teremos um conhecimento da ferramenta capaz de ajudar a iniciar análises de uma série de problemas do mundo real.

O que é necessário para começar

Para começar a utilizar o Pandas você não precisa instalar nenhum software, apenas acesse uma ferramenta online como Google Colab. É possível também utilizar o Jupyter Notebook instalado em sua máquina ou mesmo baixar um projeto que fiz e disponibilizei em meu GitHub que simplifica o processo de rodar o Jupyter Notebook em sua máquina utilizado o Docker.

Este post está longe de esgotar o assunto pois a ideia é apenas mostrar os conceitos básicos do Pandas como uma espécie de guia de consulta. Para isto vamos utilizar a base de dados Estimativa de População 2021 do IBGE para treinar e fixar os conceitos.

Fonte original dos dados: https://www.ibge.gov.br/estatisticas/downloads-estatisticas.html

Estimativas_de_Populacao > Estimativas_2021 > estimativa_dou_2021.xls

Porém para este guia preparei os dados de forma a facilitar nosso trabalho. Eles podem ser baixados aqui:

Arquivo no formato csv
estimativa_dou_2021.csv
Arquivo no formato xls
estimativa_dou_2021.xls

Tópicos abordados

Carregando a biblioteca Pandas

pd é o apelido que a comunidade dá ao pandas.

        
  import pandas as pd
        
    

No Google Colab ou Jupyter Notebook o Pandas já vem instalado, sendo assim não é necessário nenhum esforço extra além do comando acima :).

Importando dados de fontes externas

Carregando arquivos CSV

Deixei o arquivo estimativa_dou_2021.csv pré formatado de forma a carregar de maneira mais fácil.

Aqui a única observação é indicar o tipo de separador das colunas, no caso sep=";" e forçar a exibição dos dados como string para não perdermos nenhuma informação já que por padrão o Pandas tenta interpretar o formato dos dados.

            
  df = pd.read_csv("estimativa_dou_2021.csv", sep=";", dtype=str)
  df.head()
            
    

Por padrão .head() retorna cinco registros.

UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
0 RO 11 00015 Alta Floresta D'Oeste 22.516
1 RO 11 00023 Ariquemes 111.148
2 RO 11 00031 Cabixi 5.067
3 RO 11 00049 Cacoal 86.416
4 RO 11 00056 Cerejeiras 16.088

O Data Frame

            
  type(df)

  pandas.core.frame.DataFrame
            
    

O Pandas nos retorna um DataFrame que é um formado tabular de dados, semelhante ao que seria uma tabela no Excel.

É possivel criar um Data Frame manualmente também. Segue um exemplo abaixo

         
  data = {'nome': ['Ana', 'João', 'Beatriz'], 'idade': [23, 18, 86]}
  df = pd.DataFrame(data, columns=['nome','idade'])
        
    
nome idade
0 Ana 23
1 João 18
2 Beatriz 86

Referência: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html

Outras formas de abrir arquivos de dados:

          
  // Por padrão tenta abrir um csv com separação por vírgulas
  pd.read_csv('filename')
  
  // Abre com encode iso-8859-1
  pd.read_csv('filename', encoding='iso-8859-1')
  
  // Carrega apenas algumas linhas do .csv. Ex: 10 linhas
  pd.read_csv('filename', nrows=10)
  
  // Carrega dados com nomes de colunas personalizadas
  pd.read_csv('filename', names=['Column #1','Column #2'], engine='python')
  
  // Carrega dados de algumas colunas (menor utilização de memória)
  pd.read_csv('filename', usecols=[0,1,2...])
  pd.read_csv('filename', usecols=['Column #1','Column #2'])
    
  // Carrega dados de arquivos .tsv
  pd.read_table('filename')
  
  // Carrega json
  pd.read_json('json source')
  
  // Carrega dados de um documento HTML
  pd.read_html('html source')
  
  // Carrega dados de uma conexão SQL
  pd.read_sql(query, connection_configs)
        
    

Visualizando as características gerais do DataFrame

É importante uma pré visualização de como está formatado nosso DataFrame para que consigamos avaliar se será preciso corrigir, limpar ou modificar algo. Existem dois métodos que podem fazer isso rapidamente, o .info() e o .describe(). Vamos utiliza-los para olhar dentro de nosso DataFrame.

        
  df.info()
        
    
        
  
  RangeIndex: 5570 entries, 0 to 5569
  Data columns (total 5 columns):
   #   Column                Non-Null Count  Dtype 
  ---  ------                --------------  ----- 
   0   UF                    5570 non-null   object
   1   COD. UF               5570 non-null   object
   2   COD. MUNIC            5570 non-null   object
   3   NOME DO MUNICÍPIO     5570 non-null   object
   4    POPULAÇÃO ESTIMADA   5570 non-null   object
  dtypes: object(5)
  memory usage: 217.7+ KB
        
    
        
  df.describe()
        
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
count 5570 5570 5570 5570 5570
unique 27 27 4307 5297 5110
top MG 31 00708 Bom Jesus 6.232
freq 853 853 4 5 4

Olhando os retornos acima podemos notar alguns problemas neste DataFrame. Precisamos atuar neles para corrigi-los.

Renomeando campos

O campo 'POPULAÇÃO ESTIMADA' na verdade está como ' POPULAÇÃO ESTIMADA ' com espaços no início e final do nome. Vamos corrigir:

        
  df.rename(columns={' POPULAÇÃO ESTIMADA ': 'POPULAÇÃO ESTIMADA'}, inplace=True)
  df
        
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
0 RO 11 00015 Alta Floresta D'Oeste 22.516
1 RO 11 00023 Ariquemes 111.148
2 RO 11 00031 Cabixi 5.067
3 RO 11 00049 Cacoal 86.416
4 RO 11 00056 Cerejeiras 16.088
... ... ... ... ... ...
5565 GO 52 22005 Vianópolis 14.088
5566 GO 52 22054 Vicentinópolis 9.002
5567 GO 52 22203 Vila Boa 6.451
5568 GO 52 22302 Vila Propício 5.941
5569 DF 53 00108 Brasília 3.094.325

5570 rows × 5 columns

Modificando um campo do DataFrame

O campo 'POPULAÇÃO ESTIMADA' está formatado com ponto de milhar e está em formado de string ou objeto. Este campo não é um objeto mas sim uma variável quantitativa discreta.

É preciso modificar isso retirando o ponto de milhar e convertendo o campo de Objeto para Inteiro

        
  df['POPULAÇÃO ESTIMADA'] = df['POPULAÇÃO ESTIMADA'].str.replace('.','')
  df['POPULAÇÃO ESTIMADA'] = df['POPULAÇÃO ESTIMADA'].astype(int)
        
    
        
  df.info()
        
    
        
  
  RangeIndex: 5570 entries, 0 to 5569
  Data columns (total 5 columns):
   #   Column              Non-Null Count  Dtype 
  ---  ------              --------------  ----- 
   0   UF                  5570 non-null   object
   1   COD. UF             5570 non-null   object
   2   COD. MUNIC          5570 non-null   object
   3   NOME DO MUNICÍPIO   5570 non-null   object
   4   POPULAÇÃO ESTIMADA  5570 non-null   int64 
  dtypes: int64(1), object(4)
  memory usage: 217.7+ KB
        
    

Agora nosso DataFrame está pronto para exploração, porém vamos fazer o mesmo processo utilizando um arquivo excel.

Carregando arquivos Excel

A planilha "estimativa_dou_2021.xls" possui os mesmos dados do arquivo csv anterior porém com algumas linha a mais e também está em um formato antigo do Excel.

Para a correta interpretação do arquivo pelo Pandas precisamos utilizar a engine "xlrd".

Como a planilha possui duas abas se não indicamos qual aba queremos o pandas abre por padrão a primeira. Selecionamos a aba "Municípios" que é a correta para esta análise.

Como a planilha possui um cabeçalho que não nos interessa para esta análise pulamos a primeira linha com o parâmetro skiprows=[0].

Outro ponto de atenção é que por padrão o Pandas tenta interpretar o tipo de cada campo automaticamente o que pode gerar perda de infornação para a análise. Quando não se sabe ao certo como são os dados é interessante forçar a coversão de todos os campos para o formato de string.

        
  df = pd.read_excel("estimativa_dou_2021.xls", engine="xlrd", skiprows=[0], sheet_name="Municípios", dtype=str)
        
    

Vamos fazer uma análise prévia de como os dados estão, para isso utilizamos o .head() e o .tail() que por padrão listam respectivamente as primeiras e últimas cinco linhas.

Podemos também fornecer a quantidade de linhas desejadas como em .tail(30) que listará as 30 últimas linhas

Visualizando as características gerais do DataFrame criado a partir do Excel

        
  df.head()
        
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
0 RO 11 00015 Alta Floresta D'Oeste 22516
1 RO 11 00023 Ariquemes 111148
2 RO 11 00031 Cabixi 5067
3 RO 11 00049 Cacoal 86416
4 RO 11 00056 Cerejeiras 16088
        
  df.tail(30)
        
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
5563 GO 52 21858 Valparaíso de Goiás 175720
5564 GO 52 21908 Varjão 3848
5565 GO 52 22005 Vianópolis 14088
5566 GO 52 22054 Vicentinópolis 9002
5567 GO 52 22203 Vila Boa 6451
5568 GO 52 22302 Vila Propício 5941
5569 DF 53 00108 Brasília 3094325
5570 NaN NaN NaN NaN NaN
5571 Fonte: IBGE. Diretoria de Pesquisas - DPE - C... NaN NaN NaN NaN
5572 NaN NaN NaN NaN NaN
5573 Notas: NaN NaN NaN NaN
5574 (1) População judicial do município de Porto V... NaN NaN NaN NaN
5575 (2) População judicial do município de Benjami... NaN NaN NaN NaN
5576 (3) População judicial do município de Caapira... NaN NaN NaN NaN
5577 (4) População judicial do município de Guajará... NaN NaN NaN NaN
5578 (5) População judicial do município de Jutaí-A... NaN NaN NaN NaN
5579 (6) População judicial do município de Lábrea-... NaN NaN NaN NaN
5580 (7) População judicial do município de Manaqui... NaN NaN NaN NaN
5581 (8) População judicial do município de Parinti... NaN NaN NaN NaN
5582 (9) População judicial do município de Santa I... NaN NaN NaN NaN
5583 (10) População judicial do município de Tabati... NaN NaN NaN NaN
5584 (11) População judicial do município de Urucar... NaN NaN NaN NaN
5585 (12) População judicial do município de Urucur... NaN NaN NaN NaN
5586 (13) População judicial do município de Jacare... NaN NaN NaN NaN
5587 (14) População judicial do município de Paço d... NaN NaN NaN NaN
5588 (15) População judicial do município de Ferrei... NaN NaN NaN NaN
5589 (16) População judicial do município Coronel J... NaN NaN NaN NaN
5590 (17) População judicial do município Ibiassucê... NaN NaN NaN NaN
5591 (18) População judicial do município de Rodela... NaN NaN NaN NaN
5592 (19) População judicial do município de Vera C... NaN NaN NaN NaN
        
  df.describe()
        
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
count 5591 5570 5570 5570 5570
unique 48 27 4307 5297 5110
top MG 31 00708 Bom Jesus 6232
freq 853 853 4 5 4

info() e describe() são ferramentas importantes para verificar o estado bruto em que se encontram nossos dados, ver quantidades e se existem valores nulos.

Pela análise acima podemos observar que existem alguns campos com valores nulos (NaN), estes campos são campos de descrição que não precisamos manter, por isso vamos corrigir isso.

Limpando o DataFrame dos valores nulos

      
  df = df.dropna(subset=['POPULAÇÃO ESTIMADA'])
        
    

Poderíamos ter usado um df.dropna() que consideraria todos os campos com NaN mas por segurança indicamos o campo de referência 'POPULAÇÃO ESTIMADA', ou seja, todas as linhas que tenham este campo com NaN serão eliminadas

      
  df.tail()
        
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
5565 GO 52 22005 Vianópolis 14088
5566 GO 52 22054 Vicentinópolis 9002
5567 GO 52 22203 Vila Boa 6451
5568 GO 52 22302 Vila Propício 5941
5569 DF 53 00108 Brasília 3094325
      
  df.head()
      
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
0 RO 11 00015 Alta Floresta D'Oeste 22516
1 RO 11 00023 Ariquemes 111148
2 RO 11 00031 Cabixi 5067
3 RO 11 00049 Cacoal 86416
4 RO 11 00056 Cerejeiras 16088
      
  df.shape

  # (5570, 5)
      
    

O comando shape resume o número de linhas e colunas existentes no DataFrame. A limpeza foi concluída com sucesso.

Modificando um campo do DataFrame

Agora que temos apenas os dados de interesse podemos converter o campo 'POPULAÇÃO ESTIMADA', que é uma variável quantitativa discreta, para inteiro.

      
  df = df.astype({"POPULAÇÃO ESTIMADA":"int"})
      
    
      
  df.info()
      
    
      
  
  Index: 5570 entries, 0 to 5569
  Data columns (total 5 columns):
   #   Column              Non-Null Count  Dtype 
  ---  ------              --------------  ----- 
   0   UF                  5570 non-null   object
   1   COD. UF             5570 non-null   object
   2   COD. MUNIC          5570 non-null   object
   3   NOME DO MUNICÍPIO   5570 non-null   object
   4   POPULAÇÃO ESTIMADA  5570 non-null   int64 
  dtypes: int64(1), object(4)
  memory usage: 261.1+ KB
      
    

Sendo assim chegamos no mesmo estado do DataFrame carregado pelo arquivo csv. Podemos prosseguir com a análise exploratória dos dados.

Explorando os dados

Máximos, mínimos e médias

Com o DataFrame estruturado corretamente podemos iniciar a exploração dos dados, tanto de maneira geral quanto olhando detalhes que sejam interessantes.

      
  df[['UF','COD. UF']].describe()
      
    
UF COD. UF
count 5570 5570
unique 27 27
top MG 31
freq 853 853
      
  df['POPULAÇÃO ESTIMADA'].describe()
      
    
      
  count    5.570000e+03
  mean     3.829760e+04
  std      2.242882e+05
  min      7.710000e+02
  25%      5.454000e+03
  50%      1.173200e+04
  75%      2.576475e+04
  max      1.239637e+07
  Name: POPULAÇÃO ESTIMADA, dtype: float64
      
    

Minas Gerais aparece como o TOP das ocorrências de estados. Isto é compreensível já que os dados se referem a todos os municipios do Brasil e Minas Gerais é o estado com maior número de municipios (853).

A população média por município é de 38.297,6 habitantes porém temos um municipio (ou mais) com aprox. 12.396.370 habitantes e um (ou mais) com 771 habitantes. Que municípios serão estes?

Vamos descobrir isso olhando dentro do DataFrame pelo número de habitantes.

      
  municipio_menos_populoso = df['POPULAÇÃO ESTIMADA'].min()
  municipio_menos_populoso

  # 771

  df[df['POPULAÇÃO ESTIMADA'] == municipio_menos_populoso]
      
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
3026 MG 31 66600 Serra da Saudade 771

O município brasileiro com o menor número de habitantes é 'Serra da Saudade' que fica em Minas Gerais

      
  municipio_mais_populoso = df['POPULAÇÃO ESTIMADA'].max()

  df[df['POPULAÇÃO ESTIMADA'] == municipio_mais_populoso]
      
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
3829 SP 35 50308 São Paulo 12396372

Como já desconfiávamos o município com a maior população é São Paulo.

Já que estamos falando da cidade de São Paulo e do estado de Minas Gerais vamos olhar ambos com mais detalhes. Para isso vamos fazer um agrupamento geral.

Agrupando para contar e somar

Mas antes de seguir para São Paulo e Minas Gerais vamos fazer um apanhado geral dos municípios e população para cada estado, o que facilitará nosso trabalho futuro.

Brasil
      
  total_municipios_por_uf = df.groupby('UF')['COD. MUNIC'].count()
  total_municipios_por_uf
      
    
      
  UF
  AC     22
  AL    102
  AM     62
  AP     16
  BA    417
  CE    184
  DF      1
  ES     78
  GO    246
  MA    217
  MG    853
  MS     79
  MT    141
  PA    144
  PB    223
  PE    185
  PI    224
  PR    399
  RJ     92
  RN    167
  RO     52
  RR     15
  RS    497
  SC    295
  SE     75
  SP    645
  TO    139
  Name: COD. MUNIC, dtype: int64
      
    
      
  type(total_municipios_por_uf)

  # pandas.core.series.Series
      
    
      
  total_municipios_por_uf.count()

  # 27
      
    

O agrupamento acima por UF criou uma estrutura do pandas chamada Series. Cada coluna de um DataFrame é uma Series.

Referência: https://pandas.pydata.org/docs/reference/api/pandas.Series.html

A lista acima traz o total de municípios por unidade da federação que é composta por 26 estados e um Distrito Federal (27 UFs).

Podemos somar todos municípios e confirmar se o total bate com o número 5570.

      
  total_municipios_por_uf.sum()

  # 5570

  populacao_por_uf = df.groupby('UF')['POPULAÇÃO ESTIMADA'].sum()
  populacao_por_uf
      
    
      
  UF
  AC      906876
  AL     3365351
  AM     4269995
  AP      877613
  BA    14985284
  CE     9240580
  DF     3094325
  ES     4108508
  GO     7206589
  MA     7153262
  MG    21411923
  MS     2839188
  MT     3567234
  PA     8777124
  PB     4059905
  PE     9674793
  PI     3289290
  PR    11597484
  RJ    17463349
  RN     3560903
  RO     1815278
  RR      652713
  RS    11466630
  SC     7338473
  SE     2338474
  SP    46649132
  TO     1607363
  Name: POPULAÇÃO ESTIMADA, dtype: int64
      
    

A população brasileira pode ser obtida de duas formas, ou somando os totais por estado ou somando todos os municípios direto do DataFrame principal.

      
  populacao_brasil = populacao_por_uf.sum()
  populacao_brasil

  # 213317639
      
    
      
  df['POPULAÇÃO ESTIMADA'].sum()

  # 213317639
      
    

Ambos os números batem em 213.317.639

Ordenando Series e DataFrames

Vamos ordenar as unidades da federação e municípios pela quantidade decrescente de habitantes.

Veja que nos exemplos abaixo a ordenação é feita tanto a partir de uma Series quanto de um DataFrame e que cada tipo de estrutura tem uma sintaxe específica.

Ordenação de uma Series
      
  populacao_por_uf.sort_values(ascending=False)
      
    
      
  UF
  SP    46649132
  MG    21411923
  RJ    17463349
  BA    14985284
  PR    11597484
  RS    11466630
  PE     9674793
  CE     9240580
  PA     8777124
  SC     7338473
  GO     7206589
  MA     7153262
  AM     4269995
  ES     4108508
  PB     4059905
  MT     3567234
  RN     3560903
  AL     3365351
  PI     3289290
  DF     3094325
  MS     2839188
  SE     2338474
  RO     1815278
  TO     1607363
  AC      906876
  AP      877613
  RR      652713
  Name: POPULAÇÃO ESTIMADA, dtype: int64
      
    
Ordenação de um DataFrame
      
  df.sort_values(by="POPULAÇÃO ESTIMADA", ascending=False)
      
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
3829 SP 35 50308 São Paulo 12396372
3242 RJ 33 04557 Rio de Janeiro 6775561
5569 DF 53 00108 Brasília 3094325
2162 BA 29 27408 Salvador 2900319
949 CE 23 04400 Fortaleza 2703391
... ... ... ... ... ...
5077 RS 43 22350 União da Serra 1084
4749 RS 43 06924 Engenho Velho 932
5192 MT 51 01209 Araguainha 909
3348 SP 35 07209 Borá 839
3026 MG 31 66600 Serra da Saudade 771

5570 rows × 5 columns

Minas Gerais

Primeiro vamos confirmar a quantidade de municipios no estado de Minas Gerais e depois vamos ver a população total do estado.

Obter o total para Minas Gerais é fácil, basta selecionar pelo índice da Series. Os índices desta Series são as siglas dos estados.

      
  total_municipios_minas_gerais = total_municipios_por_uf.loc['MG']
  total_municipios_minas_gerais

  # 853
      
    

A quantidade de municípios de MG bate com o max de .describe(), confirmando que Minas Gerais é o estado com o maior número de municípios.

      
  populacao_mg = populacao_por_uf.loc['MG']
  populacao_mg

  # 21411923
      
    

A população do estado de Minas Gerais é de 21.411.923 habitantes

São Paulo

Agora vamos olhar para o Estado de São Paulo e contar a quantidade de municípios do estado e sua população total.

      
  total_municipios_sp = total_municipios_por_uf.loc['SP']
  total_municipios_sp

  # 645
      
    
      
  populacao_sp = populacao_por_uf.loc['SP']
  populacao_sp
    
  # 46649132
      
    

São 645 municípios com uma população total de 46.649.132 habitantes.

Gráficos

Gráfico de barras

Podemos fazer um gráfico simplificado da população por estado utilizando diretamente o Pandas. Existem bibliotetas Python melhores para trabalhar com gráficos como o Seaborn ou Matplotlib porém para tarefas mais simples de exploração o Pandas nos dá uma grande ajuda.

Referência: https://pandas.pydata.org/docs/reference/api/pandas.Series.plot.html

      
  populacao_por_uf.plot(kind="bar", title="População por estado", ylabel="População")
      
    

<Axes: title={'center': 'População por estado'}, xlabel='UF', ylabel='População'>

Gráfico de Barras

Boxplot e os outliers

Podemos também verificar se existem e como estão distribuidos outliers nos dados utilizando o boxplot.

Vamos olhar, por exemplo, a população por município.

Referência: https://pandas.pydata.org/docs/reference/api/pandas.Series.plot.box.html

      
  df['POPULAÇÃO ESTIMADA'].plot(kind="box", grid=True, logy=True)
      
    
Boxplot

Aqui a primeira observação a ser feita é que devemos plotar utilizando uma escala logaritmica para uma melhor visualização dos dados.

A mediana (linha verde) está um pouco a cima dos 10.000 habitantes o que corresponde ao valor de 11.732 obtido pelo .description() (50% ou segundo quartil)

As bolinhas escuras representam nossos outliers, ou seja, os municípios cujas populações se diferenciam significativamente dos demais valores de nossa base de dados. A bolinha superior mais afastada representa o município de São Paulo.

O gráfico acima é construído através dos valores calculados abaixo sendo que a linha azul, perto dos 100 mil, é o chamado limite superior.

      
  Q1 = df['POPULAÇÃO ESTIMADA'].quantile(0.25, interpolation="nearest")
  Q3 = df['POPULAÇÃO ESTIMADA'].quantile(0.75, interpolation="nearest")
  IQR = Q3 - Q1
  limite_inferior = Q1 - (1.5 * IQR)
  limite_superior = Q3 + (1.5 * IQR)
  limite_superior

  # 56243.0
      
    

Histograma

Vamos utilizar este limite superior, ou seja, 56243 habitantes, para construir um histograma dos dados que se encontram dentro do boxplot.

A ideia do histograma neste caso é contar a quantidade de municípios que está dentro de um intervalo de habitantes (ex: quantos municípios possuem entre 10.000 e 20.000 habitantes).

      
  df[df['POPULAÇÃO ESTIMADA'] <= limite_superior]['POPULAÇÃO ESTIMADA'].plot(kind="hist", title="Histograma de municípios", ylabel="Contagem de municípios", xlabel="Habitantes")
      
    

<Axes: title={'center': 'Histograma de municípios'}, xlabel='Habitantes', ylabel='Contagem de municípios'>

Histograma

O histograma acima pode ser classificado como 'distorcido à direita' e indica que conforme vamos procurando municípios com mais habitantes eles vão se tornando mais raros.

Criando e selecionando pelo índice

Vamos selecionar uma linha qualquer do DataFrame utilizando o número do index, que no caso de nosso DataFrame por padrão é uma sequência numérica. Vamos escolher o índice 3549

      
  df.loc[3549]
      
    
      
  UF                          SP
  COD. UF                     35
  COD. MUNIC               24907
  NOME DO MUNICÍPIO     Jambeiro
  POPULAÇÃO ESTIMADA        6828
  Name: 3549, dtype: object
      
    

Um índice melhor para nosso DataFrame seria, ao invés de uma sequencia de números, utilizar um padrão que crie um índice único para cada registro. Vamos fazer isso utilizando os campos 'UF' e 'COD. MUNIC'.

Primeiro vamos criar uma nova coluna chamada COD. GERAL com esta composição de 'UF' e 'COD. MUNIC'

      
  df['COD. GERAL'] = df['UF'] + df['COD. MUNIC']
  df
      
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA COD. GERAL
0 RO 11 00015 Alta Floresta D'Oeste 22516 RO00015
1 RO 11 00023 Ariquemes 111148 RO00023
2 RO 11 00031 Cabixi 5067 RO00031
3 RO 11 00049 Cacoal 86416 RO00049
4 RO 11 00056 Cerejeiras 16088 RO00056
... ... ... ... ... ... ...
5565 GO 52 22005 Vianópolis 14088 GO22005
5566 GO 52 22054 Vicentinópolis 9002 GO22054
5567 GO 52 22203 Vila Boa 6451 GO22203
5568 GO 52 22302 Vila Propício 5941 GO22302
5569 DF 53 00108 Brasília 3094325 DF00108

5570 rows × 6 columns

Agora é transformar a nova coluna no índice do DataFrame

      
  df = df.set_index('COD. GERAL')
  df  
      
    
UF COD. UF COD. MUNIC NOME DO MUNICÍPIO POPULAÇÃO ESTIMADA
COD. GERAL
RO00015 RO 11 00015 Alta Floresta D'Oeste 22516
RO00023 RO 11 00023 Ariquemes 111148
RO00031 RO 11 00031 Cabixi 5067
RO00049 RO 11 00049 Cacoal 86416
RO00056 RO 11 00056 Cerejeiras 16088
... ... ... ... ... ...
GO22005 GO 52 22005 Vianópolis 14088
GO22054 GO 52 22054 Vicentinópolis 9002
GO22203 GO 52 22203 Vila Boa 6451
GO22302 GO 52 22302 Vila Propício 5941
DF00108 DF 53 00108 Brasília 3094325

5570 rows × 5 columns

Podemos selecionar uma linha pelo novo índice, por exemplo a cidade do Rio de Janeiro

      
  df.loc['RJ04557']
      
    
      
  UF                                RJ
  COD. UF                           33
  COD. MUNIC                     04557
  NOME DO MUNICÍPIO     Rio de Janeiro
  POPULAÇÃO ESTIMADA           6775561
  Name: RJ04557, dtype: object
      
    

Combinando DataFrames

Vamos juntar dois DataFrames em um único. Para isso vamos utilizar as duas Series construídas para agrupar quantidade de minicípios e habitantes por UF.

Vamos converter as Series 'total_municipios_por_uf' e 'populacao_por_uf' em um DataFrame.

      
  df_populacao_por_uf = populacao_por_uf.to_frame()
  df_municipios_por_uf = total_municipios_por_uf.to_frame()
      
    

Vamos juntar os dois DataFrames utilizando o índice 'UF' como chave.

      
  df_uf = pd.merge(df_populacao_por_uf, df_municipios_por_uf, how='inner', on='UF')
  df_uf.head(2)
      
    
POPULAÇÃO ESTIMADA COD. MUNIC
UF
AC 906876 22
AL 3365351 102

O nome da segunda coluna não está correto, vamos muda-lo para 'QTD MUNICIPIOS'.

      
  df_uf = df_uf.rename(columns={'COD. MUNIC':'QTD MUNICIPIOS'})
      
    
POPULAÇÃO ESTIMADA QTD MUNICIPIOS
UF
AC 906876 22
AL 3365351 102
AM 4269995 62
AP 877613 16
BA 14985284 417
CE 9240580 184
DF 3094325 1
ES 4108508 78
GO 7206589 246
MA 7153262 217
MG 21411923 853
MS 2839188 79
MT 3567234 141
PA 8777124 144
PB 4059905 223
PE 9674793 185
PI 3289290 224
PR 11597484 399
RJ 17463349 92
RN 3560903 167
RO 1815278 52
RR 652713 15
RS 11466630 497
SC 7338473 295
SE 2338474 75
SP 46649132 645
TO 1607363 139

Exportando dados

Por último vamos salvar o DataFrame como um arquivo .csv

      
  df_uf.to_csv('habitantes_e_municipios_por_uf.csv', sep=';', header='True')
      
    

Estas são algumas das operações básicas para a exploração de dados que podem ser feitas utilizando a biblioteca Pandas.

Para uma visão mais ampla das capacidades da biblioteca recomendo a documentação oficial: https://pandas.pydata.org/docs/user_guide/index.html#user-guide

Dúvidas ou comentários?

Entre em contato comigo. Veja como me encontrar.