Procedimento para checagem e atualização da base geoespacial das escolas (2022 e 2025)

Author

CEM-USP (Thiago C. Jacovine)

Published

April 29, 2026

Modified

May 15, 2026

Visão geral

O presente documento disponibiliza o procedimento para a definição, a manutenção e a atualização dos dados geoespaciais das escolas brasileiras presentes na plataforma GeoReDUS. O objetivo é obter uma base geoespacial única das escolas ao longo do tempo. Para isso, propõe-se um procedimento de compatibilização espaço-temporal dos dados.

A proposta, como pode ser vista neste documento e no sumário localizado no canto superior direito da página, está estruturada em “grandes etapas”. São elas: i) preparação do ambiente local para armazenamento dos dados originais (microdados do censo escolar e catálogo de escolas; ii) acesso, importação e definição das operações relacionadas à limpeza e à organização da base compatibilizada dos microdados escolares; iii) breve exploração e análise dos dados; iv) geocodificação das escolas que não apresentam coordenadas geográficas e v) exportação dos resultados gerados[^1].

[^1] Caso você esteja usando o Positron como IDE, a estrutura do documento pode ser acompanhada por meio do campo OUTLINE, no canto inferior esquerdo da IDE.

Preparação e configurações iniciais

O primeiro passo para a geração dos dados geoespaciais das escolas consiste na preparação e estruturação do R e do ambiente local onde os dados serão armazenados. Dessa forma, o procedimento poderá ser reproduzido por qualquer pessoa em qualquer local, obtendo-se os mesmos resultados.

Carregando os pacotes necessários

De modo a facilitar algumas operações, e tomando como guia os princípios FAIR e do Tidyverse, alguns pacotes serão habilitados. Note: graças ao uso do Renv, as mesmas versões dos pacotes utilizadas no momento de geração dos dados serão replicadas em seu ambiente local.

# Defina quais serão as versões dos pacotes utilizadas (mesmas versões do presente documento)
renv::restore()

# Defina os pacotes que serão utilizados
pckgs <- c("archive", "arrow", "fs", "geocodebr", "gt", "httr2", "here", "janitor", "knitr", "readxl", "quarto", "scales", "sf", "tidyverse", "zip")

# Ative-os
lapply(pckgs, library, character.only = TRUE)

# Remova o objeto que armazenou o nome dos pacotes
rm(pckgs)

Definindo algumas variáveis para fins de reprodutibilidade/atualizações

Para facilitar possíveis alterações, atualizações, usos recorrentes e/ou novas consultas, algumas variáveis já serão definidas neste momento. Por ora, elas compreendem o total dos censos escolares analisados (censo_esc_tot) e os seus respectivos anos (censo_esc_anos).

# Defina o número de bases analisadas (neste momento, quatro: 2022, 2023, 2024 e 2025)
censo_esc_anos <- c(2022, 2023, 2024, 2025)
censo_esc_tot <- length(censo_esc_anos)

Obtenção, transformação e organização dos dados

A partir deste momento, serão realizadas algumas operações voltadas à obtenção, ao tratamento e à organização dos dados que serão utilizados para gerar a base geoespacial das escolas brasileiras ao longo do tempo.

Criando a estrutura de armazenamento do ambiente local

Para armazenar os dados, três pastas serão criadas:

  • 01_logs: local destinado ao armazenamento dos registros de operações e modificações realizadas;

  • 02_originais: local destinado ao armazenamento dos dados originais, e,

  • 03_processados: local destinado ao armazenamento dos dados gerados por meio do atual procedimento.

# Crie os caminhos das pastas que armazenarão os dados
pastas <- c(
    here("dados", str_c("01", "_logs")),
    here("dados", str_c("02", "_originais")),
    here("dados", str_c("03", "_processados"))
)

# Crie as pastas, caso não existam
walk(pastas, ~ if(!dir_exists(.x)) dir_create(.x, recurse = TRUE))

# Armazene o caminho de algumas pastas em objetos para facilitar as chamadas ao longo do código
pasta_logs <- pastas[1]
pasta_dados_originais <- pastas[2]
pasta_dados_processados <- pastas[3]      

Criando o procedimento para a obtenção, o tratamento e a organização dos dados

A obtenção, o tratamento e a organização dos microdados dos censos escolares ao longo do tempo pode ser realizada de diferentes formas. No presente caso, optou-se por criar uma função que reúne as etapas necessárias para essas ações.

Por meio dela, os dados originais serão:

  • Acessados via internet, baixados para o ambiente o local (computador) e importados para o R;
  • Realizadas operações de tratamento (exclusão e geração de variáveis; transformação de classes, (re)organização dos dados, etc.)
  • Geração de uma base única compatibilizada entre os anos analisados - base, essa, que servirá de insumo para a etapa de geocodificação, mais adiante.
# Definição da função para processar os dados de cada ano
processar_censo_ano <- function(ano, max_tentativas = 3) {
    # Preparação dos registros das ações e alterações (logs)  
    ## Especifique o caminho onde o arquivo de log será armazenado
    arquivo_log <- file.path(pasta_logs, str_glue("processamento_{ano}_{Sys.Date()}.log"))
   
    ## Crie uma função para gerar as mensagens de log
    log_msg <- function(msg, tipo = "INFO") {
        timestamp <- format(Sys.time(), "%Y-%m-%d %H:%M:%S")
        mensagem <- str_glue("[{timestamp}] [{tipo}] Ano {ano}: {msg}")
        write_lines(mensagem, arquivo_log, append = TRUE)
        message(mensagem)
    }
   
    # Acesso aos dados
    ## Gere uma mensagem indicando o início do processamento
    log_msg("Início do processamento")

    ## Defina o endereço para baixar o dado
    base_url <- "https://download.inep.gov.br"
   
    ## Defina o nome do arquivo a ser baixado
    arq_orig <- str_c("microdados_censo_escolar_", ano, if_else(ano == 2025, "_", ""), ".zip") # O if_else é usado para contemplar a grafia diferente dos microdados de 2025 (um traço antes do ".zip")
   
    ## Baixe os dados
    for (tentativa in 1:max_tentativas) {
        # Gere uma mensagem sobre o início do processo
        log_msg(str_glue("Tentativa de download/importação {tentativa}/{max_tentativas}"))
       
        resultado <- tryCatch({
        # Baixe o dado da fonte e salve-o localmente, caso ele ainda não exista
        if (!file.exists(file.path(pasta_dados_originais, arq_orig))) {
            request(base_url) |>
            req_url_path_append("dados_abertos") |>
            req_url_path_append(arq_orig) |>
            req_perform(path = file.path(pasta_dados_originais, arq_orig))
        }
   
    ## Renomeie a pasta original do dado de 2025, assumindo o mesmo padrão dos anos anteriores
    if (str_detect(arq_orig, "_\\.zip$")) {
        novo_nome <- str_replace(arq_orig, "_\\.zip$", ".zip")
        caminho_novo <- path(pasta_dados_originais, novo_nome)
        fs::file_move(file.path(pasta_dados_originais, arq_orig), caminho_novo)
    }

    ## Descompacte os dados
    ### Defina o caminho do arquivo compactado (.zip)
    arq_zip <- dir_ls(pasta_dados_originais, type = "file", regexp = glue::glue("microdados_censo_escolar_{ano}\\.zip$"))
   
    ### Extraia os dados dos arquivos compactados e salve-os na pasta de dados originais
    zip::unzip(
        zipfile = arq_zip,
        exdir = pasta_dados_originais,
        overwrite = TRUE)

    ## Importe os dados para o ambiente do R    
    ### Localize os microdados (dados descompactados)
    #### Trate o caso de 2022, que apresenta especificidades
    if (ano == 2022) {
        # Liste o nome do diretòrio desconsiderando os caracteres especiais
        pasta_2022 <- dir_ls(
            path = pasta_dados_originais,
            type = "directory",
            regexp = str_glue("Censo.*Escolar.*{ano}"),
            ignore.case = TRUE
        )
        # Altere o nome da pasta para o ano de 2022
        if (length(pasta_2022) == 1) {
            pasta_destino <- file.path(pasta_dados_originais, str_c("microdados_censo_escolar_", ano))
            
            if (!dir_exists(pasta_destino)) {
                file_move(pasta_2022, pasta_destino)
            }
        }
    }

    if (ano != 2025) {
    micro_base <- dir_ls(
        path = file.path(pasta_dados_originais, str_c("microdados_censo_escolar_", ano)),
        recurse = TRUE,
        type = "file",
        # Garante que, excluído o caso de 2025, apenas os microdados serão registrados
        regexp = str_glue("microdados_ed_basica_{ano}\\.csv$")
        )
    } else {
    micro_base <- dir_ls(
        path = file.path(pasta_dados_originais, str_c("microdados_censo_escolar_", ano)),
        recurse = TRUE,
        type = "file",
        glob = "*.csv"
        ) |>
        str_subset(
            pattern = "Curso_Tecnico_2025",
            negate = TRUE)
    }
   
    ### Crie uma mensagem indicando a ausência do arquivo, caso ele não seja encontrado
    if (length(micro_base) == 0) stop("Arquivo CSV de microdados não encontrado")
   
    ### Leia os dados brutos (microdados)
    if (ano != 2025) {
        micro_orig <- read_delim(
            micro_base,
            delim = ";",
            locale = locale(
                decimal_mark = ",",
                grouping_mark = ".",
                encoding = "latin1"),
            col_types = cols(.default = col_character())) |>
            clean_names() |>
            arrange(co_entidade)
        } else {
        micro_orig <- micro_base |>
            # Leia os dados de cada arquivo
            map(
                ~ read_csv2(.x,
                show_col_types = FALSE,
                locale = locale(encoding = "latin1"), # ISO-8859-1
                col_types = cols(.default = col_character()))
            ) |>
            # Junte todos os arquivos em uma base única  
            reduce(full_join, by = c("CO_ENTIDADE", "NU_ANO_CENSO")
            ) |>
            # Padronize a nomenclatura das variáveis
            janitor::clean_names() |>
            # Organize a base a partir do código das escolas
            arrange(co_entidade)
        }

    ### Crie uma mensagem indicando o número de linhas e colunas do dado bruto carregado (microdado)
    log_msg(str_glue("Dados brutos carregados: {nrow(micro_orig)} linhas, {ncol(micro_orig)} colunas"))
   
    # Transformação e organização dos dados
        microdados_esc_ativ <- micro_orig |>
            # Selecione as variáveis de interesse
            select(nu_ano_censo, sg_uf, no_municipio, co_municipio, co_cep, ds_endereco, nu_endereco, no_bairro, no_entidade, co_entidade, tp_dependencia, tp_situacao_funcionamento, qt_mat_bas
            ) |>
           
            # Filtre apenas as escolas ativas (em funcionamento e com ao menos 1 matrícula)
            filter(
                tp_situacao_funcionamento == 1 &
                if_any(starts_with("qt_mat"), ~ . > 0)) |>
            select(!tp_situacao_funcionamento) |>

            # Mude a classe de algumas variáveis
            mutate(
                # Substitua os valores 88888 por NA nas variáveis numéricas
                across(where(is.numeric), ~ na_if(., 88888)),

                # Recodifique a variável de tipo de dependência administrativa
                tp_dependencia = recode(tp_dependencia,
                                    "1" = "Pública - Federal",
                                    "2" = "Pública - Estadual",
                                    "3" = "Pública - Municipal",
                                    "4" = "Privada")
            ) |>

            # Renomeie as variáveis para o padrão utilizado na plataforma GeoReDUS
            rename(
                ano_cn_escolar = nu_ano_censo,
                nm_mun         = no_municipio,
                cod_mun        = co_municipio,
                cep            = co_cep,
                endereco       = ds_endereco,
                num_endereco   = nu_endereco,
                nm_bairro      = no_bairro,
                nm_escola      = no_entidade,
                cod_escola     = co_entidade,
                tp_adm         = tp_dependencia
                )
       
        ## Crie uma mensagem indicando o número de linhas e colunas do dado final gerado (microdados das escolas ativas)
        log_msg(str_glue("Base final gerada: {nrow(microdados_esc_ativ)} escolas ativas, {ncol(microdados_esc_ativ)} variáveis"))

        ## Crie uma mensagem explicitando os possíveis erros
        return(list(status = "sucesso", dados = microdados_esc_ativ))
        }, error = function(e) {
        log_msg(str_glue("Erro: {e$message}"), "ERRO")
       
        if (tentativa < max_tentativas) {
            espera <- 2^tentativa
            log_msg(str_glue("Aguardando {espera}s antes da próxima tentativa"), "NOVA TENTATIVA")
            Sys.sleep(espera)
        }
        return(list(status = "erro", mensagem = e$message))
        })
       
        if (resultado$status == "sucesso") return(resultado$dados)
    }
   
    ## Crie uma mensagem sobre eventuais falhas definitivas
    log_msg("Falha após todas as tentativas", "FALHA")
    return(NULL)
}

Implementando a função para o acesso e tratamento dos dados

Criada a função, basta aplicá-la ao conjunto de dados de interesse. O resultado esperado, neste caso, é a geração dos microdados das escolas ativas para cada um dos anos analisados.

NoteLembrete

Escolas ativas são aquelas que, de acordo com os dados do censo escolar, estão em funcionamento e apresentam ao menos uma matrícula ativa.

# Implementação da leitura, tratamento e organização dos dados para cada censo
## Mensagem indicando o início do processamento dos dados de todos os anos
    message(strrep("=", 50))
    message("🚀 Processamento dos Censos Escolares")
    message(strrep("=", 50))

## Aplique a função de processamento para cada ano e armazene os resultados em uma lista
resultados <- censo_esc_anos |>
    set_names(str_c("microdados_esc_ativ_", censo_esc_anos)) |>
    map(processar_censo_ano)

## Salve os casos em que o processamento foi bem-sucedido e os casos em que houve falha
result_posit <- compact(resultados)

## Salve os casos em que houve falha
sel_falha <- map_lgl(resultados, is.null)
result_negat <- resultados[sel_falha]

## Crie uma base única com os dados dos censos
base_unic_cens_edu_orig <- result_posit |>
    map("dados") |>
    keep(is.data.frame) |>
    list_rbind()

## Gere um resumo sobre todo o procedimento ("Relatório final")
    message("\n", strrep("=", 50))
    message("📊 RESUMO:")
    message(str_glue("✅ Sucesso: {length(result_posit)} anos"))

if (length(result_posit) > 0) {
    iwalk(result_posit, ~ message(str_glue("   ├─ {.y}: {nrow(.x)} escolas, {ncol(.x)} variáveis")))
}
   
if (length(result_negat) > 0) {
    message(str_glue("❌ Falha: {length(result_negat)} anos"))
    iwalk(result_negat, ~ message(str_glue("   └─ {.y} (verifique os logs)")))
}
    message(strrep("=", 50))

Explorando os dados dos Censos Escolares (2022, 2023, 2024, 2025)

Mapeando as escolas ao longo dos anos

A partir da base única criada (base_unic_cens_edu_orig), torna-se possível identificar a presença de cada escola ao longo do tempo. Tomando como exemplo o caso hipotético de uma escola presente em três anos distintos, o seu registro na base (associado as suas características) ocuparia três linhas, uma para cada ano.

Para facilitar a visualização desse quadro e sintetizar essas informações, três variáveis serão geradas:

  • no_censo_pres: quantifica o número de vezes que a escola aparece durante o período analisado (por ex., o número 3 indica que a escola está presente em três levantamentos);
  • ano_censos_pres: registra o ano dos censos em que a escola está presente (usando o mesmo exemplo anterior, o registro seria igual a “2023, 2024 e 2025”), e,
  • tipo_censos_pres: expressa, por meio de classes, o número de vezes que a escola aparece na base.
# Mapeie os casos exclusivos e os compartilhados, mantendo todos os registros originais em uma mesma base
base_unica_map_com_rep <- base_unic_cens_edu_orig |>
    # Agrupe os dados em função dos código das escolas
    group_by(cod_escola) |>
    mutate(
        # Conte o número de escolas por código único (lembre-se que dados de anos distintos foram integrados, possibilitando a repetição do cód. únic.)
        no_censos_pres = n(),
       
        # Registre o(s) ano(s) de origem associados ao cômputo dos cód. únic.
        ano_censos_pres = str_c(sort(unique(ano_cn_escolar)), collapse = ", "),
       
        # Crie uma variável para nomear as classes relacionadas ao cômputo feito
        tipo_censos_pres = case_when(
            no_censos_pres == 1 ~ "1_base",
            no_censos_pres == 2 ~ "2_bases",
            no_censos_pres == 3 ~ "3_bases",
            no_censos_pres == 4 ~ "4_bases")
  ) |>
    # Desfaça os grupos criados
    ungroup()

glimpse(base_unica_map_com_rep)
Rows: 714,874
Columns: 15
$ ano_cn_escolar   <chr> "2022", "2022", "2022", "2022", "2022", "2022", "2022…
$ sg_uf            <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO",…
$ nm_mun           <chr> "Porto Velho", "Porto Velho", "Porto Velho", "Porto V…
$ cod_mun          <chr> "1100205", "1100205", "1100205", "1100205", "1100205"…
$ cep              <chr> "76824556", "76808108", "76801123", "76804214", "7682…
$ endereco         <chr> "AVENIDA AMAZONAS", "RUA CAETANO", "AVENIDA CARLOS GO…
$ num_endereco     <chr> "6492", "3256", "1135", "1483", "1056", "605", "4767"…
$ nm_bairro        <chr> "TIRADENTES", "CALADINHO", "CENTRO", "SANTA BARBARA",…
$ nm_escola        <chr> "EEEE ABNAEL MACHADO DE LIMA - CENE", "EMEIEF PEQUENO…
$ cod_escola       <chr> "11000023", "11000040", "11000058", "11000082", "1100…
$ tp_adm           <chr> "Pública - Estadual", "Pública - Municipal", "Privada…
$ qt_mat_bas       <chr> "72", "244", "1289", "80", "750", "175", "976", "300"…
$ no_censos_pres   <int> 4, 4, 4, 3, 4, 1, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4,…
$ ano_censos_pres  <chr> "2022, 2023, 2024, 2025", "2022, 2023, 2024, 2025", "…
$ tipo_censos_pres <chr> "4_bases", "4_bases", "4_bases", "3_bases", "4_bases"…

A seguir, busca-se evidenciar quais são as escolas presentes em mais de um censo educacional. Para isso, o cômputo considera todos os anos do censo analisados (essa definição foi feita no objeto censo_esc_anos).

Dados do Censo Escolar referentes ao ano de 2022
Presença em mais de um censo escolar Anos Total de escolas
2_bases 2022, 2023 2585
2_bases 2022, 2024 193
2_bases 2022, 2025 111
3_bases 2022, 2023, 2024 4013
3_bases 2022, 2023, 2025 355
3_bases 2022, 2024, 2025 490
4_bases 2022, 2023, 2024, 2025 167499


Dados do Censo Escolar referentes ao ano de 2023
Presença em mais de um censo escolar Anos Total de escolas
2_bases 2022, 2023 2585
2_bases 2023, 2024 320
2_bases 2023, 2025 65
3_bases 2022, 2023, 2024 4013
3_bases 2022, 2023, 2025 355
3_bases 2023, 2024, 2025 3367
4_bases 2022, 2023, 2024, 2025 167499


Dados do Censo Escolar referentes ao ano de 2024
Presença em mais de um censo escolar Anos Total de escolas
2_bases 2022, 2024 193
2_bases 2023, 2024 320
2_bases 2024, 2025 3108
3_bases 2022, 2023, 2024 4013
3_bases 2022, 2024, 2025 490
3_bases 2023, 2024, 2025 3367
4_bases 2022, 2023, 2024, 2025 167499


Dados do Censo Escolar referentes ao ano de 2025
Presença em mais de um censo escolar Anos Total de escolas
2_bases 2022, 2025 111
2_bases 2023, 2025 65
2_bases 2024, 2025 3108
3_bases 2022, 2023, 2025 355
3_bases 2022, 2024, 2025 490
3_bases 2023, 2024, 2025 3367
4_bases 2022, 2023, 2024, 2025 167499


Considerando os dados expostos, que tratam das escolas presentes em mais de um censo escolar, duas constatações podem ser feitas:

  1. A depender do ano de referência da base, os números variam para os casos em que uma escola está presente em dois censos ou três anos;
  2. Independentemente do ano de referência, o número de escolas presentes em todos os levantamentos é o mesmo (167499).

Criando uma base única sem repetição de escolas

Considerando o objetivo final do presente procedimento (disponibilizar o dado geoespacial mais qualificado e atualizado possível das escolas), passa-se à criação da primeira base sintética referente ao período abrangido. Diferentemente do que ocorre com a base geral produzida anteriormente (base_unica_map_com_rep), neste caso o conjunto de escolas presentes em todos os anos analisados não contará com repetições.

Nesse sentido, é importante destacar a necessidade de se assumir um ano de referência para a geração dessa base. Afinal, a base única anterior abrange múltiplos anos e os dados da nova base proposta devem estar, em última instância, atrelados a um ano específico.

Do ponto de vista teórico, a fonte ideal seria a base mais atual. Isso porque, com o tempo as instituições produtoras de dados podem corrigir eventuais falhas, omissões e/ou prestar novos esclarecimentos sobre as possibilidade e as limitações de seus dados. Contudo, a análise empírica entre os anos dos censos escolares mostram que o dado sobre o logradouro (variável endereco) das escolas de 2025 muitas vezes encontra-se sem a denominação de seu tipo (“rua”, “avenida”, etc.). Esse fato, que é um fator limitante, atrelado à busca pelo dado mais atualizado, levou à escolha de 2024 como o ano de referência mais adequado para esta etapa.

Definida a referência temporal, a seguir cria-se a base com todas as escolas presentes durante o período analisado, incluindo-se os casos presentes em apenas um ano.

# Crie uma base sem as repetições dos registros originais por anos (REF.: 2024).
base_unica_map <- base_unica_map_com_rep |>
  mutate(ano_cn_escolar = factor(ano_cn_escolar, levels = c(2025, 2022, 2023, 2024))) |> # Para ordernar em função dos anos mais recentes, substitua o parâmetro "levels = c(...)" por "ordered = TRUE"
  arrange(cod_escola, desc(no_censos_pres), desc(ano_cn_escolar)) |>
  distinct(cod_escola, .keep_all = T)

glimpse(base_unica_map)
Rows: 189,545
Columns: 15
$ ano_cn_escolar   <fct> 2024, 2024, 2024, 2024, 2024, 2022, 2024, 2024, 2024,…
$ sg_uf            <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO",…
$ nm_mun           <chr> "Porto Velho", "Porto Velho", "Porto Velho", "Porto V…
$ cod_mun          <chr> "1100205", "1100205", "1100205", "1100205", "1100205"…
$ cep              <chr> "76824556", "76808108", "76801123", "76804214", "7682…
$ endereco         <chr> "AVENIDA AMAZONAS", "RUA CAETANO", "AVENIDA CARLOS GO…
$ num_endereco     <chr> "6492", "3256", "1135", "1483", "1056", "605", "4767"…
$ nm_bairro        <chr> "TIRADENTES", "CALADINHO", "CENTRO", "SANTA BARBARA",…
$ nm_escola        <chr> "EEEE ABNAEL MACHADO DE LIMA - CENE", "EMEIEF PEQUENO…
$ cod_escola       <chr> "11000023", "11000040", "11000058", "11000082", "1100…
$ tp_adm           <chr> "Pública - Estadual", "Pública - Municipal", "Privada…
$ qt_mat_bas       <chr> "71", "207", "1135", "58", "556", "175", "1046", "285…
$ no_censos_pres   <int> 4, 4, 4, 3, 4, 1, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4, 4,…
$ ano_censos_pres  <chr> "2022, 2023, 2024, 2025", "2022, 2023, 2024, 2025", "…
$ tipo_censos_pres <chr> "4_bases", "4_bases", "4_bases", "3_bases", "4_bases"…

A partir do exposto, é possível notar que a nova base conta com 189545 escolas.

De forma a visualizar melhor os dados, a seguir são apresentados um gráfico e duas tabelas ilustrando a presença das escolas ao longo do tempo. Enquanto a primeira tabela indica a origem (ano) dos dados que foram selecionados para compor a base, a segunda evidencia a presença/permanência das escolas ao longo do tempo.

# Verifique a procedência dos dados (ano)
base_unica_map_cnt_ano_orig <- base_unica_map |>
  count(ano_cn_escolar, sort = T, name = "tot_escolas") |>
  mutate(prop = scales::percent(tot_escolas/sum(tot_escolas), accuracy = 0.1))

# Compare a presença das escolas ao longo dos anos - ano mais atual (2024), após análise empírica
base_unica_map_cnt_anos <- base_unica_map |>
  mutate(tipo_censos_pres = factor(tipo_censos_pres)) |>
  # group_by(sg_uf) |> # Ative para ver o comportamento por estados. Caso queira realizar a leitura por município, acrescente a variável "nm_mun" 
  count(tipo_censos_pres , ano_censos_pres, name = "tot_escolas") |>
  mutate(prop = scales::percent(tot_escolas/sum(tot_escolas), accuracy = 0.1)) |> 
  arrange(desc(tipo_censos_pres), ano_censos_pres)

# Plote as duas tabelas
## Origem do dado
base_unica_map_cnt_ano_orig |>
    janitor::adorn_totals() |> 
    knitr::kable(col.names = c("Ano de origem do censo escolar", "Total de escolas", "Proporção"), caption = "Origem dos dados escolares (ano)", align = 'ccc')
Origem dos dados escolares (ano)
Ano de origem do censo escolar Total de escolas Proporção
2024 179286 94.6%
2025 3771 2.0%
2023 3277 1.7%
2022 3211 1.7%
Total 189545 -
## Presença ao longo dos anos
base_unica_map_cnt_anos |>
    janitor::adorn_totals() |> 
    knitr::kable(col.names = c("Presença das escolas", "Anos", "Total de escolas", "Proporção (%)"), caption = "Presença das escolas ao longo dos censos escolares (contagem por ano)", align = "llcc")
Presença das escolas ao longo dos censos escolares (contagem por ano)
Presença das escolas Anos Total de escolas Proporção (%)
4_bases 2022, 2023, 2024, 2025 167499 88.4%
3_bases 2022, 2023, 2024 4013 2.1%
3_bases 2022, 2023, 2025 355 0.2%
3_bases 2022, 2024, 2025 490 0.3%
3_bases 2023, 2024, 2025 3367 1.8%
2_bases 2022, 2023 2585 1.4%
2_bases 2022, 2024 193 0.1%
2_bases 2022, 2025 111 0.1%
2_bases 2023, 2024 320 0.2%
2_bases 2023, 2025 65 0.0%
2_bases 2024, 2025 3108 1.6%
1_base 2022 3100 1.6%
1_base 2023 272 0.1%
1_base 2024 296 0.2%
1_base 2025 3771 2.0%
Total - 189545 -

Como esperado, a maioria dos dados que compõem a base são de 2024, ano de referência adotado anteriormente. Por sua vez, a segunda tabela reforça alguns dados conhecidos, como a permanência de grande parte das escolas ao longo do período analisado (base_unica_map_cnt_anos[1, "prop"] |> pull()), e revela os que estão presentes em apenas em um ano do período. Esse mesmo quadro é exposto no gráfico a seguir.

base_unica_map_cnt_ano_orig |> 
    mutate(
        label_val_abs_rel = str_c(tot_escolas, "\n(", prop, ")"),
        label_pos = tot_escolas + max(tot_escolas) * 0.025) |> 
    ggplot(aes(x = fct_infreq(ano_cn_escolar), y = tot_escolas)) +
      geom_col(fill = "#4C6CB3") +
      geom_text(aes(y = label_pos, label = label_val_abs_rel),
                  hjust = -0.05, 
                  size = 4, 
                  fontface = "bold") +
      labs(
        title = "Mapeamento das escolas nos censos escolares",
        subtitle = ("Base de origem do dado (Brasil)"),
        x = NULL,
        y = NULL
        ) +
      coord_flip() +
      theme_classic() +
      theme(
        plot.title = element_text(size = 20),
        plot.subtitle = element_text(size = 15),
        axis.line.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 12.5)
        )

# Gere um gráfico para representar a presença das escolas ao longo dos anos (Brasil)
base_unica_map_cnt_anos|> 
  mutate(
    ano_censos_pres = fct_rev(fct_infreq(ano_censos_pres)),
    label_val_abs_rel = str_c(tot_escolas, "\n(", prop, ")"),
    label_pos = tot_escolas + max(tot_escolas) * 0.025) |> 
      ggplot(aes(x = fct_reorder(ano_censos_pres, tot_escolas), y = tot_escolas)) + 
        geom_col(fill = "#4C6CB3") +
        geom_text(aes(y = label_pos, label = label_val_abs_rel),
                  hjust = -0.05,
                  size = 3.5, 
                  fontface = "bold") +
        labs(
          title = "Mapeamento das escolas nos censos escolares",
          subtitle = c("Contagem da presença de cada unidade ao longo dos anos (Brasil)"),
          x = NULL) +
        coord_flip() +
        theme_classic() +
        theme(
          plot.title = element_text(size = 20),
          plot.title.position = "plot",
          plot.subtitle = element_text(size = 15),
          axis.line.x = element_blank(),
          axis.ticks.x = element_blank(),
          axis.text.x = element_blank(),
          axis.title.x = element_blank(),
          axis.text.y = element_text(size = 12.5)
        )

A partir das tabelas, verifica-se que após a seleção de 2024 como ano referência, 94.6% (179286) dos dados das escolas são provenientes dessa base. Por sua vez, ao analisarmos a presença das escolas ao longo do tempo, nota-se que 88.4% (167499) estão presentes ao longo do período analisado, indicando uma estabilidade para o Brasil, como um todo.

Os dados por estado, por sua vez, podem ser vistos a seguir.

# Crie uma tabela para representar a presença das escolas ao longo dos anos por ESTADOS
base_unica_map_cnt_anos_uf <- base_unica_map |>
  mutate(
    # tipo_censos_pres = factor(tipo_censos_pres , labels = c("Comum (3 bases)", "Compartilhado (2 bases)", "Exclusivo (1 base)")),
    ano_censos_pres =     
        fct_relevel(ano_censos_pres, "2022, 2023, 2024, 2025", "2022, 2023, 2024", "2022, 2023, 2025", "2022, 2024, 2025", "2023, 2024, 2025", "2022, 2023", "2022, 2024", "2022, 2025", "2023, 2024", "2023, 2025", "2024, 2025", "2022", "2023",  "2024", "2025"  )) |>
  group_by(sg_uf, .drop = FALSE) |> # Caso queira realizar a leitura por município, acrescente a variável "nm_mun" 
  count(ano_censos_pres, name = "tot_escolas") |>
  mutate(prop = scales::percent(tot_escolas/sum(tot_escolas), accuracy = 0.1))
    
base_unica_map_cnt_anos_uf |> 
  janitor::adorn_totals() |>  
  kable(col.names = c("Estado", "Ano do censo", "Total de escolas", "Proporção (%)"), align = 'clcc') # Caso o município tenha sido incluído no objeto anterior, ele tb deverá ser adicionado no parâmetro "col.names", entre as etiquetas "Estado" e "Ano do censo".
Estado Ano do censo Total de escolas Proporção (%)
AC 2022, 2023, 2024, 2025 1428 89.0%
AC 2022, 2023, 2024 32 2.0%
AC 2022, 2023, 2025 8 0.5%
AC 2022, 2024, 2025 4 0.2%
AC 2023, 2024, 2025 25 1.6%
AC 2022, 2023 19 1.2%
AC 2022, 2024 0 0.0%
AC 2022, 2025 4 0.2%
AC 2023, 2024 2 0.1%
AC 2023, 2025 2 0.1%
AC 2024, 2025 22 1.4%
AC 2022 28 1.7%
AC 2023 0 0.0%
AC 2024 3 0.2%
AC 2025 28 1.7%
AL 2022, 2023, 2024, 2025 2590 82.7%
AL 2022, 2023, 2024 101 3.2%
AL 2022, 2023, 2025 8 0.3%
AL 2022, 2024, 2025 17 0.5%
AL 2023, 2024, 2025 89 2.8%
AL 2022, 2023 59 1.9%
AL 2022, 2024 6 0.2%
AL 2022, 2025 3 0.1%
AL 2023, 2024 10 0.3%
AL 2023, 2025 1 0.0%
AL 2024, 2025 77 2.5%
AL 2022 81 2.6%
AL 2023 7 0.2%
AL 2024 17 0.5%
AL 2025 66 2.1%
AM 2022, 2023, 2024, 2025 5164 89.7%
AM 2022, 2023, 2024 74 1.3%
AM 2022, 2023, 2025 12 0.2%
AM 2022, 2024, 2025 19 0.3%
AM 2023, 2024, 2025 118 2.0%
AM 2022, 2023 55 1.0%
AM 2022, 2024 2 0.0%
AM 2022, 2025 4 0.1%
AM 2023, 2024 5 0.1%
AM 2023, 2025 2 0.0%
AM 2024, 2025 125 2.2%
AM 2022 72 1.3%
AM 2023 1 0.0%
AM 2024 12 0.2%
AM 2025 92 1.6%
AP 2022, 2023, 2024, 2025 820 90.4%
AP 2022, 2023, 2024 15 1.7%
AP 2022, 2023, 2025 0 0.0%
AP 2022, 2024, 2025 2 0.2%
AP 2023, 2024, 2025 19 2.1%
AP 2022, 2023 14 1.5%
AP 2022, 2024 0 0.0%
AP 2022, 2025 0 0.0%
AP 2023, 2024 0 0.0%
AP 2023, 2025 0 0.0%
AP 2024, 2025 9 1.0%
AP 2022 11 1.2%
AP 2023 2 0.2%
AP 2024 1 0.1%
AP 2025 14 1.5%
BA 2022, 2023, 2024, 2025 14540 84.0%
BA 2022, 2023, 2024 597 3.5%
BA 2022, 2023, 2025 37 0.2%
BA 2022, 2024, 2025 75 0.4%
BA 2023, 2024, 2025 266 1.5%
BA 2022, 2023 263 1.5%
BA 2022, 2024 38 0.2%
BA 2022, 2025 19 0.1%
BA 2023, 2024 60 0.3%
BA 2023, 2025 8 0.0%
BA 2024, 2025 240 1.4%
BA 2022 376 2.2%
BA 2023 60 0.3%
BA 2024 54 0.3%
BA 2025 669 3.9%
CE 2022, 2023, 2024, 2025 6989 86.9%
CE 2022, 2023, 2024 160 2.0%
CE 2022, 2023, 2025 9 0.1%
CE 2022, 2024, 2025 22 0.3%
CE 2023, 2024, 2025 261 3.2%
CE 2022, 2023 91 1.1%
CE 2022, 2024 10 0.1%
CE 2022, 2025 4 0.0%
CE 2023, 2024 14 0.2%
CE 2023, 2025 7 0.1%
CE 2024, 2025 158 2.0%
CE 2022 114 1.4%
CE 2023 22 0.3%
CE 2024 8 0.1%
CE 2025 178 2.2%
DF 2022, 2023, 2024, 2025 1157 83.1%
DF 2022, 2023, 2024 34 2.4%
DF 2022, 2023, 2025 10 0.7%
DF 2022, 2024, 2025 7 0.5%
DF 2023, 2024, 2025 27 1.9%
DF 2022, 2023 26 1.9%
DF 2022, 2024 4 0.3%
DF 2022, 2025 2 0.1%
DF 2023, 2024 6 0.4%
DF 2023, 2025 0 0.0%
DF 2024, 2025 44 3.2%
DF 2022 22 1.6%
DF 2023 4 0.3%
DF 2024 5 0.4%
DF 2025 44 3.2%
ES 2022, 2023, 2024, 2025 2883 92.0%
ES 2022, 2023, 2024 49 1.6%
ES 2022, 2023, 2025 1 0.0%
ES 2022, 2024, 2025 3 0.1%
ES 2023, 2024, 2025 29 0.9%
ES 2022, 2023 55 1.8%
ES 2022, 2024 0 0.0%
ES 2022, 2025 0 0.0%
ES 2023, 2024 1 0.0%
ES 2023, 2025 0 0.0%
ES 2024, 2025 39 1.2%
ES 2022 41 1.3%
ES 2023 1 0.0%
ES 2024 2 0.1%
ES 2025 31 1.0%
GO 2022, 2023, 2024, 2025 4358 87.5%
GO 2022, 2023, 2024 106 2.1%
GO 2022, 2023, 2025 11 0.2%
GO 2022, 2024, 2025 19 0.4%
GO 2023, 2024, 2025 93 1.9%
GO 2022, 2023 58 1.2%
GO 2022, 2024 13 0.3%
GO 2022, 2025 2 0.0%
GO 2023, 2024 12 0.2%
GO 2023, 2025 1 0.0%
GO 2024, 2025 108 2.2%
GO 2022 48 1.0%
GO 2023 10 0.2%
GO 2024 9 0.2%
GO 2025 130 2.6%
MA 2022, 2023, 2024, 2025 10682 89.9%
MA 2022, 2023, 2024 283 2.4%
MA 2022, 2023, 2025 30 0.3%
MA 2022, 2024, 2025 20 0.2%
MA 2023, 2024, 2025 130 1.1%
MA 2022, 2023 199 1.7%
MA 2022, 2024 4 0.0%
MA 2022, 2025 8 0.1%
MA 2023, 2024 13 0.1%
MA 2023, 2025 3 0.0%
MA 2024, 2025 125 1.1%
MA 2022 229 1.9%
MA 2023 17 0.1%
MA 2024 14 0.1%
MA 2025 125 1.1%
MG 2022, 2023, 2024, 2025 14806 88.5%
MG 2022, 2023, 2024 318 1.9%
MG 2022, 2023, 2025 14 0.1%
MG 2022, 2024, 2025 32 0.2%
MG 2023, 2024, 2025 302 1.8%
MG 2022, 2023 198 1.2%
MG 2022, 2024 5 0.0%
MG 2022, 2025 8 0.0%
MG 2023, 2024 29 0.2%
MG 2023, 2025 3 0.0%
MG 2024, 2025 260 1.6%
MG 2022 282 1.7%
MG 2023 15 0.1%
MG 2024 27 0.2%
MG 2025 424 2.5%
MS 2022, 2023, 2024, 2025 1726 92.0%
MS 2022, 2023, 2024 15 0.8%
MS 2022, 2023, 2025 0 0.0%
MS 2022, 2024, 2025 2 0.1%
MS 2023, 2024, 2025 29 1.5%
MS 2022, 2023 18 1.0%
MS 2022, 2024 0 0.0%
MS 2022, 2025 0 0.0%
MS 2023, 2024 1 0.1%
MS 2023, 2025 0 0.0%
MS 2024, 2025 33 1.8%
MS 2022 12 0.6%
MS 2023 0 0.0%
MS 2024 1 0.1%
MS 2025 39 2.1%
MT 2022, 2023, 2024, 2025 2467 84.0%
MT 2022, 2023, 2024 69 2.4%
MT 2022, 2023, 2025 7 0.2%
MT 2022, 2024, 2025 10 0.3%
MT 2023, 2024, 2025 77 2.6%
MT 2022, 2023 83 2.8%
MT 2022, 2024 2 0.1%
MT 2022, 2025 2 0.1%
MT 2023, 2024 12 0.4%
MT 2023, 2025 1 0.0%
MT 2024, 2025 57 1.9%
MT 2022 60 2.0%
MT 2023 3 0.1%
MT 2024 6 0.2%
MT 2025 80 2.7%
PA 2022, 2023, 2024, 2025 9873 88.6%
PA 2022, 2023, 2024 238 2.1%
PA 2022, 2023, 2025 36 0.3%
PA 2022, 2024, 2025 24 0.2%
PA 2023, 2024, 2025 232 2.1%
PA 2022, 2023 171 1.5%
PA 2022, 2024 7 0.1%
PA 2022, 2025 8 0.1%
PA 2023, 2024 28 0.3%
PA 2023, 2025 3 0.0%
PA 2024, 2025 115 1.0%
PA 2022 213 1.9%
PA 2023 9 0.1%
PA 2024 11 0.1%
PA 2025 180 1.6%
PB 2022, 2023, 2024, 2025 4358 87.6%
PB 2022, 2023, 2024 111 2.2%
PB 2022, 2023, 2025 14 0.3%
PB 2022, 2024, 2025 13 0.3%
PB 2023, 2024, 2025 85 1.7%
PB 2022, 2023 81 1.6%
PB 2022, 2024 6 0.1%
PB 2022, 2025 3 0.1%
PB 2023, 2024 6 0.1%
PB 2023, 2025 0 0.0%
PB 2024, 2025 53 1.1%
PB 2022 137 2.8%
PB 2023 5 0.1%
PB 2024 3 0.1%
PB 2025 98 2.0%
PE 2022, 2023, 2024, 2025 7559 89.3%
PE 2022, 2023, 2024 163 1.9%
PE 2022, 2023, 2025 1 0.0%
PE 2022, 2024, 2025 6 0.1%
PE 2023, 2024, 2025 115 1.4%
PE 2022, 2023 150 1.8%
PE 2022, 2024 0 0.0%
PE 2022, 2025 3 0.0%
PE 2023, 2024 4 0.0%
PE 2023, 2025 0 0.0%
PE 2024, 2025 142 1.7%
PE 2022 176 2.1%
PE 2023 3 0.0%
PE 2024 4 0.0%
PE 2025 142 1.7%
PI 2022, 2023, 2024, 2025 3803 86.6%
PI 2022, 2023, 2024 223 5.1%
PI 2022, 2023, 2025 8 0.2%
PI 2022, 2024, 2025 4 0.1%
PI 2023, 2024, 2025 48 1.1%
PI 2022, 2023 64 1.5%
PI 2022, 2024 4 0.1%
PI 2022, 2025 5 0.1%
PI 2023, 2024 4 0.1%
PI 2023, 2025 1 0.0%
PI 2024, 2025 54 1.2%
PI 2022 113 2.6%
PI 2023 3 0.1%
PI 2024 3 0.1%
PI 2025 53 1.2%
PR 2022, 2023, 2024, 2025 9186 93.8%
PR 2022, 2023, 2024 98 1.0%
PR 2022, 2023, 2025 7 0.1%
PR 2022, 2024, 2025 8 0.1%
PR 2023, 2024, 2025 104 1.1%
PR 2022, 2023 81 0.8%
PR 2022, 2024 1 0.0%
PR 2022, 2025 3 0.0%
PR 2023, 2024 6 0.1%
PR 2023, 2025 2 0.0%
PR 2024, 2025 116 1.2%
PR 2022 69 0.7%
PR 2023 1 0.0%
PR 2024 6 0.1%
PR 2025 102 1.0%
RJ 2022, 2023, 2024, 2025 10446 83.5%
RJ 2022, 2023, 2024 357 2.9%
RJ 2022, 2023, 2025 59 0.5%
RJ 2022, 2024, 2025 103 0.8%
RJ 2023, 2024, 2025 296 2.4%
RJ 2022, 2023 181 1.4%
RJ 2022, 2024 58 0.5%
RJ 2022, 2025 7 0.1%
RJ 2023, 2024 46 0.4%
RJ 2023, 2025 12 0.1%
RJ 2024, 2025 318 2.5%
RJ 2022 227 1.8%
RJ 2023 42 0.3%
RJ 2024 40 0.3%
RJ 2025 316 2.5%
RN 2022, 2023, 2024, 2025 3202 89.7%
RN 2022, 2023, 2024 81 2.3%
RN 2022, 2023, 2025 11 0.3%
RN 2022, 2024, 2025 9 0.3%
RN 2023, 2024, 2025 46 1.3%
RN 2022, 2023 36 1.0%
RN 2022, 2024 0 0.0%
RN 2022, 2025 5 0.1%
RN 2023, 2024 8 0.2%
RN 2023, 2025 2 0.1%
RN 2024, 2025 56 1.6%
RN 2022 54 1.5%
RN 2023 9 0.3%
RN 2024 12 0.3%
RN 2025 37 1.0%
RO 2022, 2023, 2024, 2025 1138 90.2%
RO 2022, 2023, 2024 36 2.9%
RO 2022, 2023, 2025 1 0.1%
RO 2022, 2024, 2025 0 0.0%
RO 2023, 2024, 2025 13 1.0%
RO 2022, 2023 15 1.2%
RO 2022, 2024 0 0.0%
RO 2022, 2025 0 0.0%
RO 2023, 2024 2 0.2%
RO 2023, 2025 0 0.0%
RO 2024, 2025 22 1.7%
RO 2022 21 1.7%
RO 2023 1 0.1%
RO 2024 0 0.0%
RO 2025 12 1.0%
RR 2022, 2023, 2024, 2025 854 92.5%
RR 2022, 2023, 2024 9 1.0%
RR 2022, 2023, 2025 0 0.0%
RR 2022, 2024, 2025 1 0.1%
RR 2023, 2024, 2025 18 2.0%
RR 2022, 2023 4 0.4%
RR 2022, 2024 0 0.0%
RR 2022, 2025 0 0.0%
RR 2023, 2024 0 0.0%
RR 2023, 2025 0 0.0%
RR 2024, 2025 22 2.4%
RR 2022 2 0.2%
RR 2023 0 0.0%
RR 2024 0 0.0%
RR 2025 13 1.4%
RS 2022, 2023, 2024, 2025 9342 90.0%
RS 2022, 2023, 2024 200 1.9%
RS 2022, 2023, 2025 18 0.2%
RS 2022, 2024, 2025 20 0.2%
RS 2023, 2024, 2025 180 1.7%
RS 2022, 2023 124 1.2%
RS 2022, 2024 10 0.1%
RS 2022, 2025 4 0.0%
RS 2023, 2024 12 0.1%
RS 2023, 2025 5 0.0%
RS 2024, 2025 140 1.3%
RS 2022 134 1.3%
RS 2023 15 0.1%
RS 2024 16 0.2%
RS 2025 165 1.6%
SC 2022, 2023, 2024, 2025 6095 90.0%
SC 2022, 2023, 2024 73 1.1%
SC 2022, 2023, 2025 6 0.1%
SC 2022, 2024, 2025 10 0.1%
SC 2023, 2024, 2025 144 2.1%
SC 2022, 2023 63 0.9%
SC 2022, 2024 4 0.1%
SC 2022, 2025 4 0.1%
SC 2023, 2024 3 0.0%
SC 2023, 2025 0 0.0%
SC 2024, 2025 130 1.9%
SC 2022 85 1.3%
SC 2023 6 0.1%
SC 2024 3 0.0%
SC 2025 149 2.2%
SE 2022, 2023, 2024, 2025 1908 88.0%
SE 2022, 2023, 2024 63 2.9%
SE 2022, 2023, 2025 0 0.0%
SE 2022, 2024, 2025 0 0.0%
SE 2023, 2024, 2025 25 1.2%
SE 2022, 2023 39 1.8%
SE 2022, 2024 2 0.1%
SE 2022, 2025 2 0.1%
SE 2023, 2024 2 0.1%
SE 2023, 2025 0 0.0%
SE 2024, 2025 34 1.6%
SE 2022 55 2.5%
SE 2023 3 0.1%
SE 2024 5 0.2%
SE 2025 30 1.4%
SP 2022, 2023, 2024, 2025 28624 89.9%
SP 2022, 2023, 2024 473 1.5%
SP 2022, 2023, 2025 47 0.1%
SP 2022, 2024, 2025 60 0.2%
SP 2023, 2024, 2025 574 1.8%
SP 2022, 2023 416 1.3%
SP 2022, 2024 17 0.1%
SP 2022, 2025 11 0.0%
SP 2023, 2024 34 0.1%
SP 2023, 2025 12 0.0%
SP 2024, 2025 585 1.8%
SP 2022 408 1.3%
SP 2023 33 0.1%
SP 2024 34 0.1%
SP 2025 526 1.7%
TO 2022, 2023, 2024, 2025 1501 90.3%
TO 2022, 2023, 2024 35 2.1%
TO 2022, 2023, 2025 0 0.0%
TO 2022, 2024, 2025 0 0.0%
TO 2023, 2024, 2025 22 1.3%
TO 2022, 2023 22 1.3%
TO 2022, 2024 0 0.0%
TO 2022, 2025 0 0.0%
TO 2023, 2024 0 0.0%
TO 2023, 2025 0 0.0%
TO 2024, 2025 24 1.4%
TO 2022 30 1.8%
TO 2023 0 0.0%
TO 2024 0 0.0%
TO 2025 28 1.7%
Total - 189545 -
# Gere um gráfico para representar a presença das escolas ao longo dos anos por ESTADOS
base_unica_map_cnt_anos_uf |>
  mutate(
    lab_val_abs_rel = str_c(tot_escolas, " (", prop,")")
  ) |> 
  ggplot(aes(x = fct_relevel(
    ano_censos_pres, 
    c(
      str_c("2023", "2024", "2025", sep = ", "), 
      str_c("2023", "2024", sep = ", "), 
      str_c("2023", "2025", sep = ", "),
      str_c("2024", "2025", sep = ", "),
      "2023", "2024", "2025")), y = tot_escolas)) + 
    geom_col(fill = "#4C6CB3") +
    geom_text(aes(label = lab_val_abs_rel), 
              hjust = -0.1,
              size = 2.25, 
              fontface = "bold") +
    labs(
      title = "Mapeamento das escolas nos censos escolares",
      subtitle = glue::glue("Contagem da presença de cada unidade escolar ao longo dos anos por unidade federativa ({paste(censo_esc_anos, collapse = ', ')})"),
      x = NULL) +
    coord_flip() +
    theme_classic() +
    theme(axis.line.x = element_blank(),
          axis.ticks.x = element_blank(),
          axis.text.x = element_blank(),
          axis.title.x = element_blank(),
          axis.text.y = element_text(size = 7),
          ) +
    facet_wrap(vars(sg_uf)) +
    scale_y_continuous(expand = expansion(mult = c(0.00, 0.2)))

Finalizada essa breve incursão exploratória, bem como a geração da base que será utilizada para a próxima etapa, a seguir passar-se-á à geocodificação.

Geocodificação

Acessando os dados do Catálogo de Escolas

Até o momento, os dados que permitem uma maior precisão para a localização das escolas referem-se às variáveis de logradouro e seus respectivos números. Contudo, nem sempre esses dados serão suficientes ou adequados, uma vez que para algumas escolas ou eles não existem ou indicam a localização de forma mais genérica (Estrada X, Terra Índigena, Área rural, etc.).

Para lidar com essa situação, uma nova base será explorada, o Catálogo de Escolas.

Baixe o dado original (“Catálogo de Escolas”) com a localização das escolas

De forma complementar aos dados presentes nos microdados do Censo Escolar, outra fonte que será utilizada para o processo de geocodificação, como recém mencionado, é o Catálogo de Escolas. Com os dados podendo ser acessados pelo site do Inep Data, essa base permite acessar um par de coordenadas geográficas associado a cada uma das escolas.

ImportantAtenção!

Essa etapa não é feita de forma automática

Para baixar os dados, acesse a url do Catálogo de Escolas. Na página, NÃO selecione nenhuma variável e clique em “Aplicar”.

O site gerará um relatório detalhado, apresentando o seguinte texto (19/02/26):
” Foram selecionadas 212.386 escolas. São apresentadas 25 escolas por página do relatório.
Quando selecionada a opção exportar, o resultado detalhado com todas as entidades retornadas na busca constarão do arquivo eletrônico.”

Em seguida, pressione o botão “Exportar” para baixar o arquivo em csv:
Análise - Tabela da lista das escolas - Detalhado.csv

Salve-o com o nome “catalogo_escolas” na pasta de dados originais criada no começo desse projeto.

Importe os dados originais do Catálogo de Escolas

A base do Catálogo de Escolas é formada por um conjunto de variáveis. Nem todas, porém, fornecem insumos para a geocodificação. Tendo isso em vista, o processo de importação a seguir seleciona apenas as variáveis que atendem a esse propósito.

# Importe os dados do catálogo de escolas
catalogo_escolas <- read_csv(file.path(pasta_dados_originais,
  "catalogo_escolas.csv"),
  locale = locale(
  #   decimal_mark = ",",
  #   grouping_mark = ".",
    encoding = "UTF-8"),
  col_select = all_of(c("Escola", "Código INEP", "Latitude", "Longitude")),
  col_types = cols(
    .default = col_character())) |>
  clean_names()

A partir da importação, é possível notar que o Catálogo de Escolas possui 212386 escolas cadastradas.

Renomeie, recodifique e selecione as variáveis de interesse (colunas)

Para facilitar a identificação e antecipar fontes eventuais de erros, a seguir as variáveis serão renomeadas e eventuais espaços na descrição das coordenadas geográficas eliminados.

# Renomeie as variáveis e elimine os eventuais espaços do campo das coordenadas geográficas
catalogo_escolas_geo <- catalogo_escolas |>
  rename(
    # Renomeie as variáveis
    cod_escola = codigo_inep,
    lat_inep = latitude,
    long_inep = longitude
  ) |>
  mutate(
    # Remova os eventuais espaços extras das coord. geo.
    lat_inep = trimws(lat_inep),
    long_inep = trimws(long_inep)
  ) |>
  select(cod_escola, lat_inep, long_inep)

glimpse(catalogo_escolas_geo)
Rows: 212,386
Columns: 3
$ cod_escola <chr> "11000023", "11000040", "11000058", "11000082", "11000104",…
$ lat_inep   <chr> "-8.758459", "-8.79373016", "-8.7607343", "-8.765205", "-8.…
$ long_inep  <chr> "-63.8540109", "-63.88391863", "-63.9019859", "-63.8961767"…

Integrando as coordenadas geográficas (Catálogo de Escolas) à base única gerada anteriormente (microdados do Censo Escolar)

Com o acesso às coordenadas geográficas presentes no Catálogo de Escolas devidamente formatadas, a seguir será realizada a junção dessa base com a dos microdados gerada anteriormente (base_unica_map). Note, também, que uma nova coluna é criada (fonte_coord_geo). O objetivo é registrar a fonte original do dado.

# Crie uma base única a partir dos microdados e Catálogo de Escolas
escolas_geo <- base_unica_map |>
  left_join(catalogo_escolas_geo, join_by("cod_escola")) |>
  mutate(fonte_coord_geo = case_when(
      !is.na(lat_inep) & !is.na(long_inep) ~ "catalogo_inep",
      TRUE ~ NA))

# Verifique a fonte dos dados presentes na base
escolas_geo |>
    count(fonte_coord_geo, name = "tot_escolas") |>
    knitr::kable(col.names = c("Fonte do dado", "Total de escolas"), align = 'lc')
Fonte do dado Total de escolas
catalogo_inep 150374
NA 39171

Realizada a integração entre as bases (“microdados” e “catalogo_escolas”), verifica-se que boa parte das escolas possuem coordenadas geográficas (79.33). Ainda restam, contudo, 20.67% das escolas sem esse dado.

Prepare a base para a geocodificação (escolas sem coordenadas geográficas)

Para lidar com a ausência de dados mais precisos sobre a dimensão espacial de algumas escolas, as coordenadas faltantes serão obtidas por meio do geocodebr, pacote dispobilizado pelo IPEA.

Dois objetos serão, então, criados: escolas_com_coord_geo e escolas_sem_coord_geo. Enquanto o primeiro registra os casos que já possuem coordenadas geográficas, o segundo armazenará as escolas que não possuem esses dados.

ImportantAtenção!

As coordenadas geradas via geocodebr são estimativas obtidas a partir das informações textuais de endereço. Nesse sentido, é importante frisar que a precisão espacial obtida está diretamente relacionada ao nível de detalhamento e qualidade dessa informação (logradouro, número, CEP, etc.). A depender do caso, ela pode variar da localização aproximada do imóvel ao centróide de áreas mais amplas, como as abrangidas pelo CEP ou município. Portanto, as coordenadas geográficas assim estimadas devem ser utilizadas com cautela, especialmente em análises espaciais de grande detalhamento.

# Selecione as escolas com coordenadas geográficas
escolas_com_coord_geo <- escolas_geo |>
  filter(!is.na(lat_inep) & !is.na(long_inep))

# Selecione as escolas sem coordenadas geográficas
escolas_sem_coord_geo <- escolas_geo |>
  filter(is.na(lat_inep) | is.na(long_inep)) |>
  select(!c(lat_inep, long_inep))

Geocodifique com o Geocodebr

Identificado o conjunto de escolas sem coordenadas geográficas, a seguir o procedimento de geocodificação será realizado. É importante lembrar, porém, que a base gerada até o momento contém dados de diferentes anos. Tal escolha, longe de ser fortuita, está relacionada à busca pela melhor localização possível das escolas.

Tendo esse objetivo em vista, propõe-se um procedimento de compatibilização entre os anos. A ideia consiste, basicamente, em geocodificar os endereços de todos os anos, compará-los e selecionar aqueles que apresentam os melhores resultados.

Nesse sentido, inicialmente criam-se objetos com i) os códigos das escolas sem coordenadas geográficas e ii) as variáveis que auxiliarão o algoritmo de geocodificação.

# Selecione as variáveis que serão utilizadas na geocodificação 
sel_var_geocod <- c("ano_cn_escolar", "cod_escola", "sg_uf", "nm_mun", "endereco", "num_endereco", "cep", "nm_bairro", "ano_censos_pres")

# Obtenha o código das escolas que não possuem coordenadas geográficas
sel_esc_sem_coordgeo <- escolas_sem_coord_geo |>
  pull(var = cod_escola)

# Veja o número de escolas selecionadas
length(sel_esc_sem_coordgeo)
[1] 39171

O próximo passo diz respeito à geração, de fato, das coordenadas geográficas para o conjunto de escolas que ainda não possui esses dados. Baseando-se no endereço registrado na base, um procedimento geral é proposto para implementar a geocodificação por ano (usa-se um for loop para isso).

O primeiro passo diz respeito à geração de uma lista vazia (resultados_geocod). Funcionando como insumo para as próximas etapas, o objetivo dessa lista é armazenar os resultados que serão produzidos pela geocodificação para cada um dos anos.

Em seguida, passa-se à estruturação da base. Mais especificamente, serão selecionadas as escolas e as variáveis de interesse (salvos no objeto base_esc_geocod_orig).

Com a base estruturada, o algoritimo de geocodificação pode ser implementado. Para isso, inicialmente serão definidos os parâmetros requeridos pelo algoritmo (campos). Vencido esse passo, executa-se a função geocode() do pacote Geocodebr. Note: de forma a explicitar uma exigência do algoritmo, o código a seguir inicia assegurando que todas as variáveis estão codificadas como character.

Finalizada a geocodificação, um novo conjunto de variáveis é gerado e acrescentado à base de entrada utilizada (escolas_geocod). De forma resumida, essas novas variáveis podem ser subdivididas em dois grupos: i) informações descritivas sobre a localização e ii) qualidade dos dados obtidos. Para o procedimento proposto, apenas algumas dessas variáveis serão retidas.

Por fim, o procedimento renomeia algumas variáveis (indicando o seu ano de origem) e salva os resultados na lista (inicialmente) vazia.

# Lista vazia para armazenar os resultados de cada ano
resultados_geocod <- list()

for(ano in censo_esc_anos) {
  # Crie a base anual a ser geocodificada
  base_esc_geocod_orig <- base_unica_map_com_rep |>
    filter(cod_escola %in% sel_esc_sem_coordgeo & ano_cn_escolar == ano) |>
    select(all_of(sel_var_geocod))

  # Defina os campos que serão utilizados para a geocodificação
  campos <- definir_campos(
    estado = "sg_uf",
    municipio = "nm_mun",
    logradouro = "endereco",
    numero = "num_endereco",
    cep = "cep",
    localidade = "nm_bairro")

  # Transforme a classe das variáveis (exigência do algoritmo)
  base_esc_geocod <- base_esc_geocod_orig |>
    mutate(across(everything(), as.character))

  # Realize a geocodificação
  escolas_geocod <- geocode(
    enderecos = base_esc_geocod,
    campos_endereco = campos,
    resultado_completo = TRUE,
    resultado_sf = FALSE,
    verboso = TRUE,
    cache = TRUE)

  # Selecione apenas as variáveis de interesse
  escolas_geocod <- escolas_geocod |>
    select(sg_uf, nm_mun, cod_escola, lat, lon, precisao, desvio_metros, tipo_resultado, ano_censos_pres)

  # Renomeie as colunas (exceto as variáveis que permanecerão as mesmas), acrescentando o ano
  ## Crie objetos auxiliares para identificar quais variáveis serão alteradas
  var_perm <- c("sg_uf", "nm_mun", "cod_escola")
  outras_var <- setdiff(names(escolas_geocod), var_perm)
  novos_nomes_var <- str_c(outras_var, "_", ano)
 
  ## Atribua os novos nomes as variáveis
  escolas_geocod <- escolas_geocod |> 
    rename_with(
      ~ novos_nomes_var[which(outras_var == .x)], 
      .cols = all_of(outras_var))

  # Guarde o resultado em uma lista
  resultados_geocod[[str_c("esc_geocod_", as.character(ano))]] <- escolas_geocod  
}
ℹ Padronizando endereços de entrada
ℹ Utilizando dados do CNEFE armazenados localmente
ℹ Geolocalizando endereços
 Casos processados: 0/29,162 ■                                  0% - dn01 
 Casos processados: 3,416/29,162 ■■■■■                             12% - da01 
 Casos processados: 5,895/29,162 ■■■■■■■                           20% - pn01 
 Casos processados: 6,304/29,162 ■■■■■■■                           22% - pa01 
 Casos processados: 6,799/29,162 ■■■■■■■■                          23% - dn02 
 Casos processados: 7,830/29,162 ■■■■■■■■■                         27% - da02 
 Casos processados: 8,640/29,162 ■■■■■■■■■■                        30% - pn02 
 Casos processados: 8,753/29,162 ■■■■■■■■■■                        30% - pa02 
 Casos processados: 8,897/29,162 ■■■■■■■■■■                        31% - dn03 
 Casos processados: 9,152/29,162 ■■■■■■■■■■                        31% - da03 
 Casos processados: 9,349/29,162 ■■■■■■■■■■■                       32% - pn03 
 Casos processados: 9,400/29,162 ■■■■■■■■■■■                       32% - pa03 
 Casos processados: 9,444/29,162 ■■■■■■■■■■■                       32% - dn04 
 Casos processados: 9,565/29,162 ■■■■■■■■■■■                       33% - da04 
 Casos processados: 9,731/29,162 ■■■■■■■■■■■                       33% - dl01 
 Casos processados: 11,338/29,162 ■■■■■■■■■■■■■                     39% - pl01 
 Casos processados: 11,791/29,162 ■■■■■■■■■■■■■                     40% - dl02 
 Casos processados: 14,479/29,162 ■■■■■■■■■■■■■■■■                  50% - pl02 
 Casos processados: 15,421/29,162 ■■■■■■■■■■■■■■■■■                 53% - dl03 
 Casos processados: 15,549/29,162 ■■■■■■■■■■■■■■■■■                 53% - pl03 
 Casos processados: 15,587/29,162 ■■■■■■■■■■■■■■■■■                 53% - dl04 
 Casos processados: 15,797/29,162 ■■■■■■■■■■■■■■■■■                 54% - dc01 
 Casos processados: 19,510/29,162 ■■■■■■■■■■■■■■■■■■■■■             67% - dc02 
 Casos processados: 28,730/29,162 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■   99% - db01 
 Casos processados: 29,032/29,162 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - dm01 
 Casos processados: 29,162/29,162 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - Fim! 

ℹ Preparando resultados
Foram encontrados e resolvidos 2071 casos de empate.
Warning message:
In enderecobr::padronizar_enderecos(enderecos = enderecos, campos_do_endereco = enderecobr::correspondencia_campos(logradouro = campos_endereco[["logradouro"]],  :
  Alguns números não puderam ser convertidos para integer, introduzindo NAs no
resultado.
ℹ Padronizando endereços de entrada
ℹ Utilizando dados do CNEFE armazenados localmente
ℹ Geolocalizando endereços
 Casos processados: 0/30,386 ■                                  0% - dn01 
 Casos processados: 3,797/30,386 ■■■■■                             12% - da01 
 Casos processados: 6,592/30,386 ■■■■■■■■                          22% - pn01 
 Casos processados: 7,017/30,386 ■■■■■■■■                          23% - pa01 
 Casos processados: 7,546/30,386 ■■■■■■■■                          25% - dn02 
 Casos processados: 8,706/30,386 ■■■■■■■■■■                        29% - da02 
 Casos processados: 9,598/30,386 ■■■■■■■■■■                        32% - pn02 
 Casos processados: 9,719/30,386 ■■■■■■■■■■■                       32% - pa02 
 Casos processados: 9,875/30,386 ■■■■■■■■■■■                       32% - dn03 
 Casos processados: 10,140/30,386 ■■■■■■■■■■■                       33% - da03 
 Casos processados: 10,351/30,386 ■■■■■■■■■■■                       34% - pn03 
 Casos processados: 10,401/30,386 ■■■■■■■■■■■                       34% - pa03 
 Casos processados: 10,458/30,386 ■■■■■■■■■■■                       34% - dn04 
 Casos processados: 10,586/30,386 ■■■■■■■■■■■                       35% - da04 
 Casos processados: 10,747/30,386 ■■■■■■■■■■■■                      35% - dl01 
 Casos processados: 12,437/30,386 ■■■■■■■■■■■■■                     41% - pl01 
 Casos processados: 12,898/30,386 ■■■■■■■■■■■■■■                    42% - dl02 
 Casos processados: 15,575/30,386 ■■■■■■■■■■■■■■■■                  51% - pl02 
 Casos processados: 16,525/30,386 ■■■■■■■■■■■■■■■■■                 54% - dl03 
 Casos processados: 16,649/30,386 ■■■■■■■■■■■■■■■■■                 55% - pl03 
 Casos processados: 16,684/30,386 ■■■■■■■■■■■■■■■■■                 55% - dl04 
 Casos processados: 16,908/30,386 ■■■■■■■■■■■■■■■■■■                56% - dc01 
 Casos processados: 20,709/30,386 ■■■■■■■■■■■■■■■■■■■■■             68% - dc02 
 Casos processados: 29,918/30,386 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■   98% - db01 
 Casos processados: 30,259/30,386 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - dm01 
 Casos processados: 30,386/30,386 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - Fim! 

ℹ Preparando resultados
Foram encontrados e resolvidos 2119 casos de empate.
Warning message:
In enderecobr::padronizar_enderecos(enderecos = enderecos, campos_do_endereco = enderecobr::correspondencia_campos(logradouro = campos_endereco[["logradouro"]],  :
  Alguns números não puderam ser convertidos para integer, introduzindo NAs no
resultado.
ℹ Padronizando endereços de entrada
ℹ Utilizando dados do CNEFE armazenados localmente
ℹ Geolocalizando endereços
 Casos processados: 0/32,105 ■                                  0% - dn01 
 Casos processados: 3,777/32,105 ■■■■■                             12% - da01 
 Casos processados: 6,648/32,105 ■■■■■■■                           21% - pn01 
 Casos processados: 7,127/32,105 ■■■■■■■■                          22% - pa01 
 Casos processados: 7,674/32,105 ■■■■■■■■                          24% - dn02 
 Casos processados: 8,780/32,105 ■■■■■■■■■                         27% - da02 
 Casos processados: 9,711/32,105 ■■■■■■■■■■                        30% - pn02 
 Casos processados: 9,835/32,105 ■■■■■■■■■■                        31% - pa02 
 Casos processados: 9,980/32,105 ■■■■■■■■■■                        31% - dn03 
 Casos processados: 10,253/32,105 ■■■■■■■■■■■                       32% - da03 
 Casos processados: 10,494/32,105 ■■■■■■■■■■■                       33% - pn03 
 Casos processados: 10,540/32,105 ■■■■■■■■■■■                       33% - pa03 
 Casos processados: 10,600/32,105 ■■■■■■■■■■■                       33% - dn04 
 Casos processados: 10,726/32,105 ■■■■■■■■■■■                       33% - da04 
 Casos processados: 10,907/32,105 ■■■■■■■■■■■                       34% - dl01 
 Casos processados: 12,685/32,105 ■■■■■■■■■■■■■                     40% - pl01 
 Casos processados: 13,177/32,105 ■■■■■■■■■■■■■                     41% - dl02 
 Casos processados: 15,853/32,105 ■■■■■■■■■■■■■■■■                  49% - pl02 
 Casos processados: 16,806/32,105 ■■■■■■■■■■■■■■■■■                 52% - dl03 
 Casos processados: 16,961/32,105 ■■■■■■■■■■■■■■■■■                 53% - pl03 
 Casos processados: 17,004/32,105 ■■■■■■■■■■■■■■■■■                 53% - dl04 
 Casos processados: 17,252/32,105 ■■■■■■■■■■■■■■■■■                 54% - dc01 
 Casos processados: 21,884/32,105 ■■■■■■■■■■■■■■■■■■■■■             68% - dc02 
 Casos processados: 31,464/32,105 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■    98% - db01 
 Casos processados: 31,878/32,105 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■   99% - dm01 
 Casos processados: 32,085/32,105 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - Fim! 
ℹ Preparando resultados
Foram encontrados e resolvidos 2128 casos de empate.
 Casos processados: 32,105/32,105 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - Fim! 

Warning messages:
1: In enderecobr::padronizar_enderecos(enderecos = enderecos, campos_do_endereco = enderecobr::correspondencia_campos(logradouro = campos_endereco[["logradouro"]],  :
  Alguns números não puderam ser convertidos para integer, introduzindo NAs no
resultado.
2: In enderecobr::padronizar_enderecos(enderecos = enderecos, campos_do_endereco = enderecobr::correspondencia_campos(logradouro = campos_endereco[["logradouro"]],  :
  Alguns números não puderam ser convertidos para integer, introduzindo NAs no
resultado.
ℹ Padronizando endereços de entrada
ℹ Utilizando dados do CNEFE armazenados localmente
ℹ Geolocalizando endereços
 Casos processados: 0/34,289 ■                                  0% - dn01 
 Casos processados: 914/34,289 ■■                                 3% - da01 
 Casos processados: 1,729/34,289 ■■■                                5% - pn01 
 Casos processados: 2,092/34,289 ■■■                                6% - pa01 
 Casos processados: 2,438/34,289 ■■■                                7% - dn02 
 Casos processados: 3,621/34,289 ■■■■                              11% - da02 
 Casos processados: 4,818/34,289 ■■■■■                             14% - pn02 
 Casos processados: 5,008/34,289 ■■■■■                             15% - pa02 
 Casos processados: 5,248/34,289 ■■■■■■                            15% - dn03 
 Casos processados: 5,346/34,289 ■■■■■■                            16% - da03 
 Casos processados: 5,450/34,289 ■■■■■■                            16% - pn03 
 Casos processados: 5,482/34,289 ■■■■■■                            16% - pa03 
 Casos processados: 5,532/34,289 ■■■■■■                            16% - dn04 
 Casos processados: 5,612/34,289 ■■■■■■                            16% - da04 
 Casos processados: 5,739/34,289 ■■■■■■                            17% - dl01 
 Casos processados: 6,310/34,289 ■■■■■■■                           18% - pl01 
 Casos processados: 6,564/34,289 ■■■■■■■                           19% - dl02 
 Casos processados: 9,594/34,289 ■■■■■■■■■                         28% - pl02 
 Casos processados: 10,613/34,289 ■■■■■■■■■■                        31% - dl03 
 Casos processados: 10,683/34,289 ■■■■■■■■■■                        31% - pl03 
 Casos processados: 10,736/34,289 ■■■■■■■■■■                        31% - dl04 
 Casos processados: 10,967/34,289 ■■■■■■■■■■■                       32% - dc01 
 Casos processados: 19,976/34,289 ■■■■■■■■■■■■■■■■■■                58% - dc02 
 Casos processados: 32,473/34,289 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■     95% - db01 
 Casos processados: 33,601/34,289 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■    98% - dm01 
 Casos processados: 34,283/34,289 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - Fim! 
ℹ Preparando resultados
Foram encontrados e resolvidos 2450 casos de empate.
 Casos processados: 34,289/34,289 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  100% - Fim! 

Warning messages:
1: In enderecobr::padronizar_enderecos(enderecos = enderecos, campos_do_endereco = enderecobr::correspondencia_campos(logradouro = campos_endereco[["logradouro"]],  :
  Alguns números não puderam ser convertidos para integer, introduzindo NAs no
resultado.
2: In enderecobr::padronizar_enderecos(enderecos = enderecos, campos_do_endereco = enderecobr::correspondencia_campos(logradouro = campos_endereco[["logradouro"]],  :
  Alguns números não puderam ser convertidos para integer, introduzindo NAs no
resultado.
# Veja os resultados
summary(resultados_geocod)
                Length Class      Mode
esc_geocod_2022 9      data.frame list
esc_geocod_2023 9      data.frame list
esc_geocod_2024 9      data.frame list
esc_geocod_2025 9      data.frame list
str(resultados_geocod)
List of 4
 $ esc_geocod_2022:'data.frame':    29162 obs. of  9 variables:
  ..$ sg_uf               : chr [1:29162] "RO" "RO" "RO" "RO" ...
  ..$ nm_mun              : chr [1:29162] "Porto Velho" "Porto Velho" "Porto Velho" "Porto Velho" ...
  ..$ cod_escola          : chr [1:29162] "11000325" "11000546" "11000562" "11000635" ...
  ..$ lat_2022            : num [1:29162] -8.79 -9.78 -9.69 -8.78 -9.32 ...
  ..$ lon_2022            : num [1:29162] -63.9 -66.6 -65.5 -63.8 -64.3 ...
  ..$ precisao_2022       : chr [1:29162] "numero_aproximado" "cep" "cep" "logradouro" ...
  ..$ desvio_metros_2022  : int [1:29162] 6 14393 49470 210 83271 17466 120198 6 120198 158686 ...
  ..$ tipo_resultado_2022 : chr [1:29162] "da03" "dc02" "dc02" "dl03" ...
  ..$ ano_censos_pres_2022: chr [1:29162] "2022, 2023" "2022" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" ...
 $ esc_geocod_2023:'data.frame':    30386 obs. of  9 variables:
  ..$ sg_uf               : chr [1:30386] "RO" "RO" "RO" "RO" ...
  ..$ nm_mun              : chr [1:30386] "Porto Velho" "Porto Velho" "Porto Velho" "Porto Velho" ...
  ..$ cod_escola          : chr [1:30386] "11000325" "11000562" "11000635" "11001011" ...
  ..$ lat_2023            : num [1:30386] -8.79 -9.73 -9.11 -9.32 -8.42 ...
  ..$ lon_2023            : num [1:30386] -63.9 -65.5 -63.9 -64.3 -63.5 ...
  ..$ precisao_2023       : chr [1:30386] "numero_aproximado" "cep" "cep" "cep" ...
  ..$ desvio_metros_2023  : int [1:30386] 6 29046 120198 83271 17466 120198 6 120198 158686 689 ...
  ..$ tipo_resultado_2023 : chr [1:30386] "da03" "dc01" "dc02" "dc02" ...
  ..$ ano_censos_pres_2023: chr [1:30386] "2022, 2023" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" ...
 $ esc_geocod_2024:'data.frame':    32105 obs. of  9 variables:
  ..$ sg_uf               : chr [1:32105] "RO" "RO" "RO" "RO" ...
  ..$ nm_mun              : chr [1:32105] "Porto Velho" "Porto Velho" "Porto Velho" "Porto Velho" ...
  ..$ cod_escola          : chr [1:32105] "11000562" "11000635" "11001011" "11001070" ...
  ..$ lat_2024            : num [1:32105] -9.73 -9.11 -9.11 -8.42 -9.11 ...
  ..$ lon_2024            : num [1:32105] -65.5 -63.9 -63.9 -63.5 -63.9 ...
  ..$ precisao_2024       : chr [1:32105] "cep" "cep" "cep" "cep" ...
  ..$ desvio_metros_2024  : int [1:32105] 29046 120198 120198 17466 120198 6 120198 158686 689 35351 ...
  ..$ tipo_resultado_2024 : chr [1:32105] "dc01" "dc02" "dc02" "dc02" ...
  ..$ ano_censos_pres_2024: chr [1:32105] "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" ...
 $ esc_geocod_2025:'data.frame':    34289 obs. of  9 variables:
  ..$ sg_uf               : chr [1:34289] "RO" "RO" "RO" "RO" ...
  ..$ nm_mun              : chr [1:34289] "Porto Velho" "Porto Velho" "Porto Velho" "Porto Velho" ...
  ..$ cod_escola          : chr [1:34289] "11000562" "11000635" "11001011" "11001070" ...
  ..$ lat_2025            : num [1:34289] -9.69 -9.11 -9.11 -8.42 -9.11 ...
  ..$ lon_2025            : num [1:34289] -65.5 -63.9 -63.9 -63.5 -63.9 ...
  ..$ precisao_2025       : chr [1:34289] "cep" "cep" "cep" "cep" ...
  ..$ desvio_metros_2025  : int [1:34289] 49470 120198 120198 17466 120198 120198 120198 158686 1002 35351 ...
  ..$ tipo_resultado_2025 : chr [1:34289] "dc02" "dc02" "dc02" "dc02" ...
  ..$ ano_censos_pres_2025: chr [1:34289] "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" "2022, 2023, 2024, 2025" ...

Antes dos comentários sobre a geocodificação, mencione-se que as mensagens de atenção (warning messages) geradas estão apenas alertando para a impossibilidade de converter alguns números para o formato integer, padrão de representação utilizado pelo algoritmo. Sempre que isso ocorre, o algoritmo substitui esse valor por um valor faltante (NA).

Isso posto, observa-se que a lista criada (resultados_geocod) apresenta os dados geocodificados para cada um dos 4 anos analisados. Essa forma de visualização, porém, é de difícil compreensão.

Diante deste fato e do resultado que se quer obter, a seguir a lista será transformada em uma única estrutura tabular (escolas_geocod_tds_anos). A partir dos sufixos das variáveis, que indicam o ano de origem do dado para cada uma das escolas, comparações serão mais facilmente realizáveis.

# Transforme a lista com os resultados da geocoficação em uma única base tabular
escolas_geocod_tds_anos <- resultados_geocod |>
  reduce(full_join, by = c("sg_uf", "nm_mun", "cod_escola"))

# Veja os dados para as primeiras escolas da base única
escolas_geocod_tds_anos |>
  head() |> 
  knitr::kable()
sg_uf nm_mun cod_escola lat_2022 lon_2022 precisao_2022 desvio_metros_2022 tipo_resultado_2022 ano_censos_pres_2022 lat_2023 lon_2023 precisao_2023 desvio_metros_2023 tipo_resultado_2023 ano_censos_pres_2023 lat_2024 lon_2024 precisao_2024 desvio_metros_2024 tipo_resultado_2024 ano_censos_pres_2024 lat_2025 lon_2025 precisao_2025 desvio_metros_2025 tipo_resultado_2025 ano_censos_pres_2025
RO Porto Velho 11000325 -8.794654 -63.88509 numero_aproximado 6 da03 2022, 2023 -8.794654 -63.88509 numero_aproximado 6 da03 2022, 2023 NA NA NA NA NA NA NA NA NA NA NA NA
RO Porto Velho 11000546 -9.775360 -66.59998 cep 14393 dc02 2022 NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
RO Porto Velho 11000562 -9.685638 -65.46000 cep 49470 dc02 2022, 2023, 2024, 2025 -9.731319 -65.53329 cep 29046 dc01 2022, 2023, 2024, 2025 -9.731319 -65.53329 cep 29046 dc01 2022, 2023, 2024, 2025 -9.685638 -65.46000 cep 49470 dc02 2022, 2023, 2024, 2025
RO Porto Velho 11000635 -8.776310 -63.79908 logradouro 210 dl03 2022, 2023, 2024, 2025 -9.111448 -63.91765 cep 120198 dc02 2022, 2023, 2024, 2025 -9.111448 -63.91765 cep 120198 dc02 2022, 2023, 2024, 2025 -9.111448 -63.91765 cep 120198 dc02 2022, 2023, 2024, 2025
RO Porto Velho 11001011 -9.318474 -64.28872 cep 83271 dc02 2022, 2023, 2024, 2025 -9.318474 -64.28872 cep 83271 dc02 2022, 2023, 2024, 2025 -9.111448 -63.91765 cep 120198 dc02 2022, 2023, 2024, 2025 -9.111448 -63.91765 cep 120198 dc02 2022, 2023, 2024, 2025
RO Porto Velho 11001070 -8.418862 -63.49341 cep 17466 dc02 2022, 2023, 2024, 2025 -8.418862 -63.49341 cep 17466 dc02 2022, 2023, 2024, 2025 -8.418862 -63.49341 cep 17466 dc02 2022, 2023, 2024, 2025 -8.418862 -63.49341 cep 17466 dc02 2022, 2023, 2024, 2025

A partir da geocodificação e da criação de uma base única para armazenar esses dados, é possível verificar que o procedimento gerou dados para 39254 escolas. Esse número, contudo, é ligeiramente maior do que a base de entrada (escolas_sem_coord_geo), que possui 39171 escolas. Isso ocorre, pois no processo de geocodificação ocorreu a duplicação de algumas escolas, expostas a seguir.

# Crie um vetor para selecionar os casos duplicados
sel_esc_geocod_dupli <- duplicated(escolas_geocod_tds_anos$cod_escola) 

# Quantique os casos duplicados
sum(sel_esc_geocod_dupli)
[1] 83
# Selecione e apresente os 10 casos aleatórios de escolas duplicadas
escolas_geocod_tds_anos |> 
  filter(sel_esc_geocod_dupli) |> 
  slice_sample(n = 10) |> 
  kable()
sg_uf nm_mun cod_escola lat_2022 lon_2022 precisao_2022 desvio_metros_2022 tipo_resultado_2022 ano_censos_pres_2022 lat_2023 lon_2023 precisao_2023 desvio_metros_2023 tipo_resultado_2023 ano_censos_pres_2023 lat_2024 lon_2024 precisao_2024 desvio_metros_2024 tipo_resultado_2024 ano_censos_pres_2024 lat_2025 lon_2025 precisao_2025 desvio_metros_2025 tipo_resultado_2025 ano_censos_pres_2025
MT Santo Antônio de Leverger 51042045 NA NA NA NA NA NA NA NA NA NA NA NA -15.942145 -55.85528 cep 121370 dc02 2022, 2023, 2024 NA NA NA NA NA NA
MA Fortuna 21132046 NA NA NA NA NA NA -5.706096 -44.10157 cep 34040 dc02 2022, 2023, 2024, 2025 -5.706096 -44.10157 cep 34040 dc02 2022, 2023, 2024, 2025 -5.706096 -44.10157 cep 34040 dc02 2022, 2023, 2024, 2025
MT Santo Antônio de Leverger 51042053 NA NA NA NA NA NA NA NA NA NA NA NA -15.948544 -55.56117 cep 1127 dc01 2022, 2023, 2024 NA NA NA NA NA NA
AM Anori 13015656 NA NA NA NA NA NA NA NA NA NA NA NA -3.795525 -61.67254 cep 83658 dc02 2022, 2023, 2024, 2025 NA NA NA NA NA NA
MT Santo Antônio de Leverger 51041626 NA NA NA NA NA NA NA NA NA NA NA NA -16.592987 -55.21377 logradouro 6 dl02 2022, 2023, 2024, 2025 -16.592987 -55.21377 logradouro 6 dl02 2022, 2023, 2024, 2025
MT Tangará da Serra 51090457 NA NA NA NA NA NA NA NA NA NA NA NA -14.622953 -57.49594 municipio 36911 dm01 2022, 2023, 2024, 2025 -14.622953 -57.49594 municipio 36911 dm01 2022, 2023, 2024, 2025
AC Rio Branco 12015172 NA NA NA NA NA NA -10.039042 -67.78903 cep 2416 dc02 2022, 2023, 2024, 2025 -10.039042 -67.78903 cep 2416 dc02 2022, 2023, 2024, 2025 -10.039042 -67.78903 cep 2416 dc02 2022, 2023, 2024, 2025
MT Santo Antônio de Leverger 51041774 NA NA NA NA NA NA NA NA NA NA NA NA -15.942145 -55.85528 cep 121370 dc02 2022, 2023, 2024 NA NA NA NA NA NA
MA Graça Aranha 21203849 NA NA NA NA NA NA -5.407171 -44.33240 cep 889 dc01 2022, 2023, 2024, 2025 -5.407171 -44.33240 cep 889 dc01 2022, 2023, 2024, 2025 -5.407163 -44.33809 cep 9303 dc02 2022, 2023, 2024, 2025
MT Santo Antônio de Leverger 51056550 NA NA NA NA NA NA NA NA NA NA NA NA -15.942145 -55.85528 cep 121370 dc02 2022, 2023, 2024, 2025 -15.942145 -55.85528 cep 121370 dc02 2022, 2023, 2024, 2025

Uma vez que não deve haver duplicação na base das escolas geocodificadas, o próximo trecho eliminará esses casos. Em linhas gerais, a estratégia adotada consiste em:

  • Agrupar as escolas a partir dos seus códigos de identificação - dessa forma, a duplicação será reconhecida;
  • Identificar, para cada grupo de escolas, o menor desvio produzido no momento da geocodificação (o valor será salvo em uma variável auxiliar);
  • Preencher as variáveis com valores faltantes a partir da comparação dos casos, e,
  • Selecionar as escolas a partir dos menores valores de desvios existentes.
escolas_geocod_tds_anos <- escolas_geocod_tds_anos |> 
  # Agrupe os casos por código de escola
  group_by(cod_escola) %>%
  
  # Identifique, em cada grupo, o menor desvio gerado pela geocodificação
  mutate(menor_desvio_da_linha = pmin(desvio_metros_2022,desvio_metros_2023, desvio_metros_2024, desvio_metros_2025, na.rm = TRUE)) %>%
  
  # Compare, identifique os evetuais valores ausentes (NA) das variáveis da base e replique os valores para cima e para baixo dentro do mesmo código de escola
  fill(everything(), .direction = "downup") %>%
  
  # Rearrange a base considerando o menor valor do desvio por código de escola
  arrange(menor_desvio_da_linha) %>%

  # Remova a coluna auxiliar utilizada para identificar o menor desvio da geocodif. 
  select(-menor_desvio_da_linha) %>%

  # Selecione apenas a escola com o menor desvio global do mesmo código 
  distinct(cod_escola, .keep_all = TRUE) %>%

  # Desfaça os grupos criados  
  ungroup()

Eliminada a duplicação de escolas da base geocodificada, a seguir apresentam-se: i) a estrutura da atual base e ii) a presença das escolas geocodificadas ao longo do tempo.

# Veja a estrutura da base apenas com as escolas geocodificadas sem duplicação
glimpse(escolas_geocod_tds_anos)
Rows: 39,171
Columns: 27
$ sg_uf                <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "…
$ nm_mun               <chr> "Porto Velho", "Porto Velho", "Guajará-Mirim", "M…
$ cod_escola           <chr> "11000325", "11001267", "11006706", "11008598", "…
$ lat_2022             <dbl> -8.794654, -8.850409, -10.768905, -9.429623, -8.7…
$ lon_2022             <dbl> -63.88509, -63.94084, -65.33086, -62.00170, -63.8…
$ precisao_2022        <chr> "numero_aproximado", "numero_aproximado", "numero…
$ desvio_metros_2022   <int> 6, 6, 6, 6, 1222, 6, 6, 6, 971, 6, 6, 6, 6, 73, 6…
$ tipo_resultado_2022  <chr> "da03", "pa01", "da01", "pa01", "dc02", "dn01", "…
$ ano_censos_pres_2022 <chr> "2022, 2023", "2022, 2023, 2024, 2025", "2022", "…
$ lat_2023             <dbl> -8.794654, -8.850409, NA, -9.429623, -8.723806, -…
$ lon_2023             <dbl> -63.88509, -63.94084, NA, -62.00170, -63.84758, -…
$ precisao_2023        <chr> "numero_aproximado", "numero_aproximado", NA, "nu…
$ desvio_metros_2023   <int> 6, 6, NA, 6, 1222, 6, 6, 6, 6, 6, 6, 6, 6, 73, 6,…
$ tipo_resultado_2023  <chr> "da03", "pa01", NA, "pa01", "dc02", "dn01", "dn01…
$ ano_censos_pres_2023 <chr> "2022, 2023", "2022, 2023, 2024, 2025", NA, "2022…
$ lat_2024             <dbl> NA, -8.850409, NA, -9.429623, -8.751167, -9.92009…
$ lon_2024             <dbl> NA, -63.94084, NA, -62.00170, -63.90322, -63.0171…
$ precisao_2024        <chr> NA, "numero_aproximado", NA, "numero_aproximado",…
$ desvio_metros_2024   <int> NA, 6, NA, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 73, 271,…
$ tipo_resultado_2024  <chr> NA, "pa01", NA, "pa01", "dn01", "dn01", "dn01", "…
$ ano_censos_pres_2024 <chr> NA, "2022, 2023, 2024, 2025", NA, "2022, 2023, 20…
$ lat_2025             <dbl> NA, -9.111448, NA, -9.423916, -8.751251, -9.91967…
$ lon_2025             <dbl> NA, -63.91765, NA, -62.07344, -63.90341, -63.0171…
$ precisao_2025        <chr> NA, "cep", NA, "cep", "cep", "cep", "numero", "ce…
$ desvio_metros_2025   <int> NA, 120198, NA, 50054, 36, 6, 6, 16596, 6, 134, 6…
$ tipo_resultado_2025  <chr> NA, "dc02", NA, "dc02", "dc01", "dc01", "dn01", "…
$ ano_censos_pres_2025 <chr> NA, "2022, 2023, 2024, 2025", NA, "2022, 2023, 20…
# Identifique a presença das escolas geocodificados ao longo dos anos
escolas_geocod_tds_anos |> 
  mutate(ano_censos_pres = case_when(
    is.na(ano_censos_pres_2025) & is.na(ano_censos_pres_2024) ~ ano_censos_pres_2023,
    is.na(ano_censos_pres_2025) & !is.na(ano_censos_pres_2024) ~ ano_censos_pres_2024,
    .default = ano_censos_pres_2025
  )) |> 
  count(ano_censos_pres, sort = T, name = "tot_esc") |> 
  mutate(prop = scales::percent(tot_esc/sum(tot_esc), accuracy = 0.1)) |> 
  janitor::adorn_totals() |> 
  knitr::kable(col.names = c("Presença nos censos (ano)", "Total de escolas", "Propoção (%)"), align = 'lcc')
Presença nos censos (ano) Total de escolas Propoção (%)
2022, 2023, 2024, 2025 24520 62.6%
2025 3657 9.3%
2024, 2025 2938 7.5%
2023, 2024, 2025 2627 6.7%
NA 1556 4.0%
2022, 2023 1279 3.3%
2022, 2023, 2024 1215 3.1%
2024 264 0.7%
2023, 2024 237 0.6%
2023 229 0.6%
2022, 2023, 2025 222 0.6%
2022, 2024, 2025 202 0.5%
2022, 2024 102 0.3%
2022, 2025 66 0.2%
2023, 2025 57 0.1%
Total 39171 -

Como demonstra a estrutura da base, com exceção das variáveis relacionadas à unidade federativa (sg_uf), ao nome do município (nm_mun) e ao código de identificação único da escola (cod_escola), para todas as outras existem uma versão relacionada a cada ano do censo analisado (lat_2023, lon_2023, precisao_2023, etc.). No caso específico das coordenadas geográficas, deve-se ter apenas um par de referência - em tese, o de maior acurácia.

Nesse sentido, baseando-se no menor valor de desvio da localização da escola e na busca pelo dado mais recente possível, as próximas linhas do código selecionarão o caso (escola) com as melhores coordenadas. Apenas para exemplificar o exposto, se o desvio constatado para uma escola for de 6 metros, em 2023, e de 36 metros, em 2024, o par de coordenadas selecionado seria o do primeiro ano (2023). Por sua vez, se o desvio encontrado para ambos os anos for o mesmo, as coordenadas recuperadas estariam atreladas ao ano de 2024 (mais recente e adequado possível). Por fim, para fins de registro e análise, o histórico dos dados constará na base gerada.

# Transforme as colunas anuais em formato longo
escolas_geocod_long <- escolas_geocod_tds_anos |> 
  pivot_longer(
    cols = matches("^(precisao_|desvio_metros_|lat_|lon_)\\d{4}$"),
    # cols = matches("^(desvio_metros_)\\d{4}$"), # Esse linha não empilha as coord. geo. 
    names_to = c(".value", "ano"),
    names_pattern = "^(.*)_(\\d{4})$") |> 
      relocate(ends_with(as.character(censo_esc_anos)), .after = "desvio_metros")

# Selecione a escola com o menor desvio
escolas_geocod_melhor_ano <- escolas_geocod_long |> 
  group_by(cod_escola, sg_uf, nm_mun) |>
  arrange(cod_escola, sg_uf, nm_mun, desvio_metros, desc(ano), .by_group = T) |> 
  slice_head(n = 1) |>
  ungroup() |>
  rename(melhor_ano = ano,
         melhor_desvio = desvio_metros,
         melhor_latitude = lat,
         melhor_longitude = lon,
         melhor_precisao = precisao)

# Adicione todas as variávies para análise histórica
escolas_geocod_compatib <- escolas_geocod_tds_anos |>
  left_join(escolas_geocod_melhor_ano) |> 
  relocate(.after = cod_escola, starts_with("melhor"))
Joining with `by = join_by(sg_uf, nm_mun, cod_escola, tipo_resultado_2022,
ano_censos_pres_2022, tipo_resultado_2023, ano_censos_pres_2023,
tipo_resultado_2024, ano_censos_pres_2024, tipo_resultado_2025,
ano_censos_pres_2025)`

A seguir, apresentam-se dois gráficos referentes à qualidade dos dados gerados, o primeiro para o Brasil, como um todo, e o segundo para as unidades de federativas (estados).

Code
# Crie um gráfico sobre a precisão das estimativas geradas durante a geocodificação (Brasil)
escolas_geocod_compatib |>
  summarize(n = n(), .by = melhor_precisao) |>
  mutate(
    prop = scales::percent((n / sum(n)), accuracy = 0.1),
    lab_val_abs_rel = str_c(n, "\n(", prop,")"),
    precisao = factor(
      melhor_precisao,
      levels = c("numero", "numero_aproximado", "logradouro", "cep", "localidade", "municipio"))) |>
  ggplot(aes(x = precisao, y = n, label = lab_val_abs_rel)) + # , label = (prop)
    geom_col(fill = "#4C6CB3") +
    geom_text(
      vjust = -0.25,
      size = 4,
      fontface = "bold") +
    scale_y_discrete(expand = expansion(mult = c(0.05, 0.15))) +
    scale_x_discrete(labels = c(
      "numero" = "Número",
      "numero_aproximado" = "Número aproximado",
      "logradouro" = "Logradouro",
      "cep" = "CEP",
      "localidade" = "Localidade",
      "municipio" = "Município")) +
    labs(
      title = "Distribuição das escolas geocodificadas segundo o nível de precisão (Brasil)",
      x = NULL,
      y = NULL) +
    theme_classic() +
    theme(
      axis.text.x = element_text(size = 15, angle = 45, vjust = 0.5),
      plot.title = element_text(size = 20),
      plot.title.position = "plot"
    )

Code
# Crie um gráfico sobre a precisão das estimativas geradas durante a geocodificação (Estados - UF)
escolas_geocod_compatib |>
  group_by(sg_uf, melhor_precisao, .drop = FALSE) |> 
  summarize(tot_escolas = n()) |> # , .by = melhor_precisao
  mutate(
    prop = scales::percent((tot_escolas / sum(tot_escolas)), accuracy = 0.1),
    lab_val_abs_rel = str_c(tot_escolas, " (", prop,")"),
    precisao = factor(
      melhor_precisao,
      levels = c("numero", "numero_aproximado", "logradouro", "cep", "localidade", "municipio"))
      ) |>
  drop_na() |> 
  ggplot(aes(x = precisao, y = tot_escolas, label = lab_val_abs_rel)) + # , label = (prop)
    geom_col(fill = "#4C6CB3") +
    geom_text(
      hjust = -0.15,
      size = 2.5,
      fontface = "bold") +
    scale_y_discrete(expand = expansion(mult = c(0.05, 0.15))) +
    scale_x_discrete(labels = c(
      "numero" = "Número",
      "numero_aproximado" = "Número aproximado",
      "logradouro" = "Logradouro",
      "cep" = "CEP",
      "localidade" = "Localidade",
      "municipio" = "Município")) +
    labs(
      title = "Distribuição das escolas geocodificadas segundo o nível de precisão (Estados - UF)",
      x = NULL,
      y = NULL) +
    theme_classic() +
    theme(
      axis.text.x = element_text(size = 5),
      plot.title = element_text(size = 20),
      plot.title.position = "plot"
    ) +
    facet_wrap(vars(sg_uf)) +
    coord_flip()
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by sg_uf and melhor_precisao.
ℹ Output is grouped by sg_uf.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(sg_uf, melhor_precisao))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

Crie uma base única com as coordenadas geográficas geradas

Para a criação de uma base onde todas as escolas terão um par de coordenadas geográficas associado, a seguir serão selecionadas apenas algumas das variáveis da base proveniente da geocodificação.

# Selecione o padrão de exclusão que será utilizado para excluri as colunas a seguir - neste caso, todas as variáveis que terminem com os seus respectivos anos
colunas_excluir <- "\\d{4}$"

# Exclua e adicione colunas de interesse e registre a fonte do dado
escolas_geocod_compatib <- escolas_geocod_compatib |>
  select(-any_of(matches(colunas_excluir))) |>
  mutate(fonte_coord_geo = "geocodebr")  |> 
  left_join(base_unica_map_com_rep, join_by(sg_uf, nm_mun, cod_escola, melhor_ano == ano_cn_escolar)) 

O próximo passo consiste em integrar ambas as bases com coordenadas geográficas (escolas_com_coord_geo e escolas_geocod_compatib).

# Junte as bases com coordenadas geográficas (originais e geocodificadas)
escolas_geo_tot <- escolas_com_coord_geo |>
  bind_rows(escolas_geocod_compatib)

Com a base única gerada (“escolas_geo_tot”), algumas transformações iniciais serão realizadas. Atreladas à organização das variáveis já existentes, as primeiras dizem respeito à criação de um campo único para armazenar as coordenadas geográficas - neste momento, verifica-se a existência das coordenadas geográficas provenientes do Catálogo de Escolas (“lat_inep” e “long_inep”) e as geradas pela geocodificação (“melhor_latitude” e “melhor_longitude”) - tratamento similar é realizado para o ano. Por sua vez, o outro grupo de modificações diz respeito ao ajuste da classe de algumas variáveis e a renomeação de algumas variáveis. Por fim, define-se um novo ordenamento para as variáveis e os casos.

escolas_geo_tot <- escolas_geo_tot |>
  mutate(
    # Junte as informações das coordenadas geográficas nos mesmos campos
    lat = if_else(!is.na(lat_inep), as.numeric(lat_inep), melhor_latitude),
    lon = if_else(!is.na(long_inep), as.numeric(long_inep), melhor_longitude),
    fonte_ano_cn_escolar = if_else(!is.na(melhor_ano), melhor_ano, ano_cn_escolar),
    # Modifique a classe de algumas variáveis
    across(c(fonte_ano_cn_escolar, tp_adm, sg_uf, cod_mun, nm_mun, fonte_coord_geo), as.factor)) |>
  select(!c(lat_inep, long_inep, melhor_ano, melhor_latitude, melhor_longitude, ano_cn_escolar)) |>
  # drop_na(c(lat, lon)) |>
  rename(
    precisao = melhor_precisao, 
    desvio = melhor_desvio
    ) |> 
  relocate(cod_escola, nm_escola, lat, lon, precisao, desvio, fonte_coord_geo, fonte_ano_cn_escolar, tp_adm, qt_mat_bas, sg_uf, nm_mun, cod_mun, cep, endereco, num_endereco, nm_bairro) |> 
  arrange(cod_escola)

escolas_geo_tot |>
  glimpse()
Rows: 189,545
Columns: 20
$ cod_escola           <chr> "11000023", "11000040", "11000058", "11000082", "…
$ nm_escola            <chr> "EEEE ABNAEL MACHADO DE LIMA - CENE", "EMEIEF PEQ…
$ lat                  <dbl> -8.758459, -8.793730, -8.760734, -8.765205, -8.76…
$ lon                  <dbl> -63.85401, -63.88392, -63.90199, -63.89618, -63.8…
$ precisao             <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ desvio               <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ fonte_coord_geo      <fct> catalogo_inep, catalogo_inep, catalogo_inep, cata…
$ fonte_ano_cn_escolar <fct> 2024, 2024, 2024, 2024, 2024, 2022, 2024, 2024, 2…
$ tp_adm               <fct> Pública - Estadual, Pública - Municipal, Privada,…
$ qt_mat_bas           <chr> "71", "207", "1135", "58", "556", "175", "1046", …
$ sg_uf                <fct> RO, RO, RO, RO, RO, RO, RO, RO, RO, RO, RO, RO, R…
$ nm_mun               <fct> Porto Velho, Porto Velho, Porto Velho, Porto Velh…
$ cod_mun              <fct> 1100205, 1100205, 1100205, 1100205, 1100205, 1100…
$ cep                  <chr> "76824556", "76808108", "76801123", "76804214", "…
$ endereco             <chr> "AVENIDA AMAZONAS", "RUA CAETANO", "AVENIDA CARLO…
$ num_endereco         <chr> "6492", "3256", "1135", "1483", "1056", "605", "4…
$ nm_bairro            <chr> "TIRADENTES", "CALADINHO", "CENTRO", "SANTA BARBA…
$ no_censos_pres       <int> 4, 4, 4, 3, 4, 1, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, 4…
$ ano_censos_pres      <chr> "2022, 2023, 2024, 2025", "2022, 2023, 2024, 2025…
$ tipo_censos_pres     <chr> "4_bases", "4_bases", "4_bases", "3_bases", "4_ba…

Realizadas esses primeiros ajustes, uma nova forma de registrar a presença das escolas ao longo do tempo é feita. Para isso, são criadas variáveis específicas para cada um dos anos dos censos analisados. Essas variáveis, por sua vez, indicarão a presença (“TRUE”) ou ausência (FALSE) da escola naquele ano.

escolas_geo_tot <- escolas_geo_tot |>
    mutate(
        pres_ano_22 = str_detect(ano_censos_pres, pattern = "2022"),
        pres_ano_23 = str_detect(ano_censos_pres, pattern = "2023"),
        pres_ano_24 = str_detect(ano_censos_pres, pattern = "2024"),
        pres_ano_25 = str_detect(ano_censos_pres, pattern = "2025")
    )

Com a base organizada, é possível ver, por exemplo, o resultado final a partir da fonte original/produtora do dado espacial.

# Visualize a fonte dos dados geográficos na base única gerada
escolas_geo_tot |>
  count(fonte_coord_geo, name = "tot_escolas") |>
  mutate(prop = tot_escolas / sum(tot_escolas)) |>
  arrange(desc("tot_escolas")) |>
  mutate(prop = scales::percent(prop, accuracy = 0.1)) |>
  knitr::kable(
    digits = 1,
    col.names = c("Fonte do dado geográfico", "No. de escolas", "Proporção (%)"),
    caption = "Origem dos dados geográficos associados às escolas",
    align = "lcc",
    format.args = list(big.mark = ".", decimal.mark = ","))
Origem dos dados geográficos associados às escolas
Fonte do dado geográfico No. de escolas Proporção (%)
catalogo_inep 150.374 79.3%
geocodebr 39.171 20.7%

Exportação dos dados

Salvando a base final sem o formato espacial

Após a união/junção e organização dos dados do Censo Escolar e do Catálogo de Escolas, uma primeira versão da base única já pode ser exportada em três formatos distintos: “csv”, “parquet” e “rds”.

Para isso, a seguir serão criadas duas estratégias para a exportação. Na primeira, a base será única, com colunas específicas para cada um dos anos indicando a presença (TRUE) ou a ausência (FALSE) da escola naquele ano. Ou seja, o filtro é realizado por colunas específicas para cada ano do censo.

# Exporte a base gerada no formato .csv
write_csv(escolas_geo_tot, file.path(pasta_dados_processados, str_c("escolas_geo_hist.csv")))

# Exporte a base gerada no formato .csv
write_parquet(escolas_geo_tot, file.path(pasta_dados_processados, str_c("escolas_geo_hist.parquet")))

# Exporte a base no formato .rds, nativo do R.
saveRDS(
  escolas_geo_tot,
  file.path(pasta_dados_processados, str_c("escolas_geo_hist.rds")))

Note que, ainda que apresente as coordenadas geográficas para todas as escolas, a base recém-exportada não é um objeto espacial. Para isso, ela precisa ser transformada, como será feito a seguir.

# Transforme a base em um objeto espacial do tipo "sf"
escolas_tot_geo <- st_as_sf(
  escolas_geo_tot |> drop_na(c(lon, lat)),
  coords = c("lon", "lat"),
  crs = 4674) # SIRGAS 2000

# Cheque se a classe do objeto foi realizada
class(escolas_tot_geo)

# Visualize rapidamente se a transformação ocorreu como esperado (os pontos deveriam formar uma ideia dos limites do Brasil)
plot(escolas_tot_geo["cod_escola"], main = "Distribuição das escolas brasileiras (2022 a 2025)")

Criado o objeto espacial, os dados serão exportados como geopackage, um formato de dados geoespacial aberto.

# Exporte o objeto espacial criado como geopackage
st_write(
  escolas_tot_geo,
  dsn = file.path(
    pasta_dados_processados,
    str_c("escolas_geo_hist.gpkg")),
  append = FALSE)