É comum disponibilizar dados tabulares em arquivos CSV ou XLSX. No entanto, nem sempre esses dados vêm no melhor formato estruturado para leitura e processamento por softwares.

O IBGE, por exemplo, disponibiliza vários dados em arquivos de planilhas (.xls, .xlsx, .ods) que, em muitos casos, não é amigável à leitura por scripts. Nesses casos é preciso escrever scripts para extrair esses dados para um formato usável em análise de dados.

Neste texto eu descrevo passo a passo como extrair dados das Projeções de População do IBGE de 2018.

Instalação dos pacotes necessários

Para instalar os pacotes necessários, se ainda não os tiver, basta executar o sequinte comando:

pip install pandas xlrd
  • pandas: manipulação de dataframes
  • xlrd: ler/salvar arquivos xls

Com tudo instalado, basta importar o pandas com:

import pandas as pd

Download dos arquivos

Primeiro é preciso baixar os arquivos Excel no servidor FTP do IBGE. Isso pode ser feito via navegador ou pelo Python mesmo.

Os arquivos podem ser encontrados nos endereços:

O arquivo que vou usar é projecoes_2018_indicadores.xls

Inspeção visual no Microsoft Excel / LibreOffice Calc

A primeira coisa que faço é abrir os arquivos no Excel / Calc para fazer uma inspeção visual em como os dados estão organizados na planilha.

Primeiro vejo como os dados estão organizados e se é possível extraí-los apenas com o Pandas. Olho coisas como:

  • onde começa e termina o cabeçalho da(s) tabela(s) (argumento headers);
  • se há linhas antes ou depois da tabela para ignorar (skiprows e skipfooter);
  • se há mais de uma planilha no arquivo;

No caso do arquivo projecoes_2018_indicadores.xls temos várias planilhas (uma para cada região), felizmente todas com a mesma estrutura: três linhas antes da tabela, duas linhas de cabeçalho e doze linhas de rodapé.

Primeiro é vou descrever o código para extrair dados de uma planilha e então aplicar um loop para fazer o mesmo com todas as planilhas do arquivo.

Assim, a chamada para a função read_excel do pandas fica assim:

df = pd.read_excel(
    "data/projecoes_2018_indicadores.xls",
    skiprows=3,
    skipfooter=12,
    header=(0, 1),
)
df.head()

Veja que é preciso tratar os nomes das colunas. Principalmente, é preciso corrigir os nomes das olunas do segundo nível (as colunas “Unnamed” 😣).

MultiIndex

A tabela do IBGE tem um cabeçalho com nomes das colunas com dois níveis hierárquicos formatado com células mescladas. No Pandas esse tipo de coluna é representado pelo objeto MultiIndex.

Vou então construir um novo MultiIndex com uma lista de tuplas com os nomes das colunas e atribuir ao DataFrame.

O bloco de código a seguir itera sobre as colunas do DataFrame:

  • substitui o caractere de nova linha ("\n") por um espaço (" “);
  • se o nome da coluna no segundo nível começar com “Unnamed:”, o nome dele é o mesmo do primeiro nível
  • coloca a tupla (“coluna_nivel_1”, “coluna_nivel_2”) numa lista (new_columns)
new_columns = []
for column in df.columns:
    column = [col.replace("\n", " ") for col in column]
    for i, col in enumerate(column):
        if col.startswith("Unnamed:"):
            column[i] = column[i-1]
    new_columns.append(tuple(column))

Agora que temos a lista das colunas com nomes corrigidos podemos construir o novo MultiIndex e atribuir ao DataFrame.

df.columns = pd.MultiIndex.from_tuples(new_columns)
df.head()

O código para ler os dados de uma planilha está feito. Vou colocá-lo em uma função para usar no loop para ler todas as planilhas do arquivo.

def ler_planilha(filepath, sheet_name):
    df = pd.read_excel(
        filepath,
        sheet_name=sheet_name,
        skiprows=3,
        skipfooter=12,
        header=(0, 1),
    )
    new_columns = []
    for col0, col1 in df.columns:
        col0 = col0.replace("\n", " ")
        col1 = col1.replace("\n", " ")
        if col1.startswith("Unnamed:"):
            new_columns.append((col0, col0))
        else:
            new_columns.append((col0, col1))
    df.columns = pd.MultiIndex.from_tuples(new_columns)
    df.loc[:, ("REGIAO", "REGIAO")] = sheet_name
    return df

Agora é preciso ler os dados de todas as planilhas do arquivo.

Para isso pode-se colocar o código num loop iterando sobre todas as planilhas. Para obter os nomes das planilhas a classe ExcelFile do pandas é bem útil.

with pd.ExcelFile("data/projecoes_2018_indicadores.xls") as xls:
    sheet_names = xls.sheet_names
print(sheet_names)
['Brasil', 'Norte', 'RO', 'AC', 'AM', 'RR', 'PA', 'AP', 'TO', 'Nordeste', 'MA', 'PI', 'CE', 'RN', 'PB', 'PE', 'AL', 'SE', 'BA', 'Sudeste', 'MG', 'ES', 'RJ', 'SP', 'Sul', 'PR', 'SC', 'RS', 'Centro-Oeste', 'MS', 'MT', 'GO', 'DF']

Cada planilha contém dados de uma região do Brasil. Para identificar a região nos dados cria-se uma coluna com valores igual ao nome da planilha.

data = pd.DataFrame()
for sheet_name in sheet_names:
    df = ler_planilha("data/projecoes_2018_indicadores.xls", sheet_name)
    data = pd.concat((data, df), ignore_index=True)

Enfim salvamos o arquivo num formato mais conveniente (como parquet).

data.to_parquet("projecoes_2018_indicadores.parquet")

Apesar da grande quantidade de dados públicos na Internet, nem sempre eles estão prontos para serem processados por modelos estatísticos e algoritmos de machine learning. É preciso fazer um pré-processamento para deixá-los utilizáveis. A técnica descrita neste texto é apenas um exemplo de como resolver um problema que um engenheiro / cientista de dados no seu dia a dia.