├── .Rbuildignore ├── .gitattributes ├── .github ├── .gitignore └── workflows │ ├── check.yaml │ ├── check_as_cran.yaml │ ├── pkgdown.yaml │ ├── rhub.yaml │ └── test-coverage.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── CRAN-SUBMISSION ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── RcppExports.R ├── busca_por_cep.R ├── cache.R ├── create_geocodebr_db.R ├── definir_campos.R ├── download_cnefe.R ├── error.R ├── geocode.R ├── geocode_reverso.R ├── geocodebr-package.R ├── match_cases.R ├── match_cases_probabilistic.R ├── match_weighted_cases.R ├── match_weighted_cases_probabilistic.R ├── message.R ├── progress_bar.R ├── trata_empates_geocode.R └── utils.R ├── README.Rmd ├── README.md ├── codecov.yml ├── codemeta.json ├── cran-comments.md ├── geocodebr.Rproj ├── inst ├── CITATION └── extdata │ ├── large_sample.parquet │ ├── munis_bbox.rds │ ├── pontos.rds │ ├── small_sample.csv │ └── states_bbox.rds ├── man ├── add_precision_col.Rd ├── arrow_open_dataset.Rd ├── busca_por_cep.Rd ├── cache_message.Rd ├── create_index.Rd ├── definir_campos.Rd ├── definir_pasta_cache.Rd ├── deletar_pasta_cache.Rd ├── download_cnefe.Rd ├── figures │ ├── colors.txt │ ├── ipea_logo.png │ ├── logo.png │ ├── logo.svg │ └── logo_gpt.png ├── geocode.Rd ├── geocode_reverso.Rd ├── geocodebr.Rd ├── listar_dados_cache.Rd ├── listar_pasta_cache.Rd ├── roxygen │ └── templates │ │ ├── cache.R │ │ ├── empates_section.R │ │ ├── n_cores.R │ │ ├── precision_section.R │ │ └── verboso.R └── update_input_db.Rd ├── pkgdown └── _pkgdown.yml ├── src ├── .gitignore ├── RcppExports.cpp └── distance_calcs.cpp ├── tests ├── tests_rafa │ ├── arrow_distinct.R │ ├── benchmark_LIKE.R │ ├── benchmark_reg_adm.R │ ├── busca_por_cep_alternativas.R │ ├── calculate_precision.R │ ├── fts_extension.R │ ├── generate_sample_data.R │ ├── geocoding_en.Rmd │ ├── geocoding_pt.Rmd │ ├── issue_50.R │ ├── meta.R │ ├── munis_bbox.R │ ├── reverse_geocode_alternatives.R │ ├── reverse_geocode_tests.R │ ├── rua_ipe_roxo.R │ ├── sankey_plot.R │ ├── serch_nearby_addresses.R │ ├── states_bbox.R │ ├── test_rafa.R │ └── teste_geocodebr_1km.csv ├── testthat.R └── testthat │ ├── _snaps │ ├── cache.md │ ├── definir_campos.md │ ├── download_cnefe.md │ ├── error.md │ └── message.md │ ├── test-busca_por_cep.R │ ├── test-cache.R │ ├── test-definir_campos.R │ ├── test-download_cnefe.R │ ├── test-error.R │ ├── test-geocode.R │ ├── test-geocode_reverso.R │ └── test-message.R └── vignettes ├── geocode.Rmd ├── geocode_reverso.Rmd └── geocodebr.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.github$ 4 | ^tests_rafa$ 5 | ^data_prep 6 | ^CRAN-SUBMISSION$ 7 | ^cran-comments\.md$ 8 | ^codecov\.yml$ 9 | ^docs$ 10 | .Rhistory 11 | .RData 12 | ^_pkgdown\.yml$ 13 | ^pkgdown$ 14 | ^\.pre-commit-config\.yaml$ 15 | ^README\.Rmd$ 16 | ^codemeta\.json$ 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Desativar deteccao de HTML 2 | *.html linguist-detectable=false 3 | 4 | # Interpretar .rmd como R 5 | *.Rmd linguist-language=R -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: check 10 | 11 | jobs: 12 | check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: windows-latest, r: 'release'} 22 | - {os: macOS-latest, r: 'release'} 23 | - {os: ubuntu-22.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 24 | - {os: ubuntu-22.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 25 | - {os: ubuntu-22.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 26 | 27 | env: 28 | RSPM: ${{ matrix.config.rspm }} 29 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - uses: r-lib/actions/setup-r@v2 35 | with: 36 | r-version: ${{ matrix.config.r }} 37 | 38 | - uses: r-lib/actions/setup-pandoc@v2 39 | 40 | - uses: r-lib/actions/setup-r-dependencies@v2 41 | with: 42 | extra-packages: any::rcmdcheck 43 | needs: check 44 | 45 | - uses: r-lib/actions/check-r-package@v2 46 | -------------------------------------------------------------------------------- /.github/workflows/check_as_cran.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: check_as_cran 10 | 11 | jobs: 12 | check_as_cran: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: ubuntu-22.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 22 | 23 | env: 24 | RSPM: ${{ matrix.config.rspm }} 25 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | steps: 28 | - uses: actions/checkout@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | r-version: ${{ matrix.config.r }} 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r-dependencies@v2 37 | with: 38 | extra-packages: any::rcmdcheck 39 | needs: check 40 | 41 | - uses: r-lib/actions/check-r-package@v2 42 | env: 43 | _R_CHECK_CRAN_INCOMING_: false 44 | NOT_CRAN: false 45 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | name: pkgdown 7 | 8 | jobs: 9 | pkgdown: 10 | runs-on: ubuntu-22.04 11 | env: 12 | RSPM: https://packagemanager.rstudio.com/cran/__linux__/jammy/latest 13 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - uses: r-lib/actions/setup-pandoc@v2 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | 22 | - uses: r-lib/actions/setup-r-dependencies@v2 23 | with: 24 | extra-packages: any::pkgdown, local::. 25 | needs: website 26 | 27 | - name: Build and deploy pkgdown site 28 | run: | 29 | git config --local user.name "GitHub Actions" 30 | git config --local user.email "actions@github.com" 31 | Rscript -e 'pkgdown::deploy_to_branch(new_process = FALSE)' 32 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@v1 55 | - uses: r-hub/actions/platform-info@v1 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/actions/setup-deps@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/run-check@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | steps: 79 | - uses: r-hub/actions/checkout@v1 80 | - uses: r-hub/actions/setup-r@v1 81 | with: 82 | job-config: ${{ matrix.config.job-config }} 83 | token: ${{ secrets.RHUB_TOKEN }} 84 | - uses: r-hub/actions/platform-info@v1 85 | with: 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | job-config: ${{ matrix.config.job-config }} 88 | - uses: r-hub/actions/setup-deps@v1 89 | with: 90 | job-config: ${{ matrix.config.job-config }} 91 | token: ${{ secrets.RHUB_TOKEN }} 92 | - uses: r-hub/actions/run-check@v1 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: test-coverage 10 | 11 | permissions: read-all 12 | 13 | jobs: 14 | test-coverage: 15 | runs-on: ubuntu-22.04 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | 22 | - uses: r-lib/actions/setup-r-dependencies@v2 23 | with: 24 | extra-packages: any::covr, any::xml2 25 | needs: coverage 26 | 27 | - name: Test coverage 28 | run: | 29 | cov <- covr::package_coverage( 30 | quiet = FALSE, 31 | clean = FALSE, 32 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 33 | ) 34 | covr::to_cobertura(cov) 35 | shell: Rscript {0} 36 | 37 | - uses: codecov/codecov-action@v4 38 | with: 39 | # Fail if error if not on PR, or if on PR and token is given 40 | fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }} 41 | file: ./cobertura.xml 42 | plugin: noop 43 | disable_search: true 44 | token: ${{ secrets.CODECOV_TOKEN }} 45 | 46 | - name: Show testthat output 47 | if: always() 48 | run: | 49 | ## -------------------------------------------------------------------- 50 | find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true 51 | shell: bash 52 | 53 | - name: Upload test results 54 | if: failure() 55 | uses: actions/upload-artifact@v4 56 | with: 57 | name: coverage-test-failures 58 | path: ${{ runner.temp }}/package 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.Rcheck/ 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Ruserdata 6 | censobr_*.tar.gz 7 | vignettes/*.html 8 | .parquet 9 | .tmp 10 | *.o 11 | *.so 12 | *.swp 13 | *.dll 14 | /docs/ 15 | docs 16 | /data_prep/data/* 17 | /data_prep/data_raw/* 18 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/lorenzwalthert/precommit 3 | rev: v0.4.3.9001 4 | hooks: 5 | - id: readme-rmd-rendered 6 | - id: codemeta-description-updated 7 | - id: pkgdown 8 | -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 0.2.0 2 | Date: 2025-05-07 13:46:57 UTC 3 | SHA: 80fd6e3553492146c87a05262faaa34fffd48d4f 4 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Type: Package 2 | Package: geocodebr 3 | Title: Geolocalização De Endereços Brasileiros (Geocoding Brazilian Addresses) 4 | Version: 0.2.09999 5 | Authors@R: c( 6 | person("Rafael H. M.", "Pereira", , "rafa.pereira.br@gmail.com", role = c("aut", "cre"), 7 | comment = c(ORCID = "0000-0003-2125-7465")), 8 | person("Daniel", "Herszenhut", , "dhersz@gmail.com", role = "aut", 9 | comment = c(ORCID = "0000-0001-8066-1105")), 10 | person("Arthur", "Bazolli", , "baz.arthur@gmail.com", role = "ctb"), 11 | person("Ipea - Instituto de Pesquisa Econômica Aplicada", role = c("cph", "fnd")) 12 | ) 13 | Description: Método simples e eficiente de geolocalizar dados no Brasil. O 14 | pacote é baseado em conjuntos de dados espaciais abertos de endereços 15 | brasileiros, utilizando como fonte principal o Cadastro Nacional de Endereços 16 | para Fins Estatísticos (CNEFE). O CNEFE é publicado pelo Instituto Brasileiro 17 | de Geografia e Estatística (IBGE), órgão oficial de estatísticas e geografia 18 | do Brasil. (A simple and efficient method for geolocating data in Brazil. The 19 | package is based on open spatial datasets of Brazilian addresses, primarily 20 | using the Cadastro Nacional de Endereços para Fins Estatísticos (CNEFE), 21 | published by the Instituto Brasileiro de Geografia e Estatística (IBGE), 22 | Brazil's official statistics and geography agency.) 23 | License: MIT + file LICENSE 24 | URL: https://github.com/ipeaGIT/geocodebr, 25 | https://ipeagit.github.io/geocodebr/ 26 | BugReports: https://github.com/ipeaGIT/geocodebr/issues 27 | Depends: 28 | R (>= 4.1.0) 29 | Imports: 30 | arrow (>= 15.0.1), 31 | checkmate, 32 | cli, 33 | data.table, 34 | DBI, 35 | dplyr, 36 | duckdb, 37 | enderecobr (>= 0.4.1), 38 | fs, 39 | glue, 40 | httr2 (>= 1.0.0), 41 | nanoarrow (>= 0.3.0.1), 42 | parallel, 43 | purrr, 44 | Rcpp, 45 | rlang, 46 | sf, 47 | sfheaders, 48 | tools 49 | Suggests: 50 | covr, 51 | dbplyr, 52 | geobr, 53 | ggplot2 (>= 3.3.1), 54 | knitr, 55 | rmarkdown, 56 | scales, 57 | testthat (>= 3.0.0) 58 | VignetteBuilder: 59 | knitr 60 | Config/testthat/edition: 3 61 | Encoding: UTF-8 62 | Roxygen: list(markdown = TRUE) 63 | RoxygenNote: 7.3.2 64 | LinkingTo: 65 | Rcpp 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2024 2 | COPYRIGHT HOLDER: geocodebr authors 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(busca_por_cep) 4 | export(definir_campos) 5 | export(definir_pasta_cache) 6 | export(deletar_pasta_cache) 7 | export(download_cnefe) 8 | export(geocode) 9 | export(geocode_reverso) 10 | export(listar_dados_cache) 11 | export(listar_pasta_cache) 12 | importFrom(Rcpp,sourceCpp) 13 | importFrom(data.table,"%chin%") 14 | importFrom(data.table,"%like%") 15 | importFrom(data.table,":=") 16 | importFrom(data.table,.GRP) 17 | importFrom(data.table,.I) 18 | importFrom(data.table,.N) 19 | importFrom(data.table,.SD) 20 | importFrom(dplyr,across) 21 | importFrom(dplyr,all_of) 22 | importFrom(dplyr,case_when) 23 | importFrom(dplyr,mutate) 24 | importFrom(dplyr,select) 25 | importFrom(stats,weighted.mean) 26 | useDynLib(geocodebr, .registration = TRUE) 27 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # geocodebr 0.2.09999 dev 2 | 3 | ## Correção de bugs (Bug fixes) 4 | 5 | - Resolvido bug que retornava erro se o input to usuario comecava o geocode direto a partir do match case 'pl01' 6 | 7 | 8 | # geocodebr 0.2.0 9 | 10 | ## Mudanças grandes (Major changes) 11 | 12 | - A função `geocode()` agora inclui busca com match probabilistico. [Encerra issue #34](https://github.com/ipeaGIT/geocodebr/issues/34). 13 | - Nova função `buscapor_cep()`. [Encerra issue #8](https://github.com/ipeaGIT/geocodebr/issues/8). 14 | - Nova função `geocode_reverso()`. [Encerra issue #35](https://github.com/ipeaGIT/geocodebr/issues/35). 15 | - A função `download_cnefe()` agora aceita o argumento `tabela` para baixar tabelas específicas. 16 | 17 | ## Mudanças pequenas (Minor changes) 18 | 19 | - Ajuste na solução de casos de empate mais refinada e agora detalhada na documentação da função `geocode()`. [Encerra issue #37](https://github.com/ipeaGIT/geocodebr/issues/37). O método adotado na solução de empates agora fica transparente na documentação da função `geocode()`. 20 | - Nova vignette sobre a função `geocode_reverso()` 21 | - Vignette sobre *Get Started* e da função `geocode()` reorganizadas 22 | 23 | ## Correção de bugs (Bug fixes) 24 | 25 | - Resolvido bug que decaracterizava colunas de classe `integer64` na tabela de input de endereços. [Encerra issue #40](https://github.com/ipeaGIT/geocodebr/issues/40). 26 | 27 | ## Novos contribuidores (New contributions) 28 | 29 | - Arthur Bazzolli 30 | 31 | # geocodebr 0.1.1 32 | 33 | ## Correção de bugs 34 | 35 | - Corrigido bug na organização de pastas do cache de dados. Fecha o [issue 29](https://github.com/ipeaGIT/geocodebr/issues/29). 36 | 37 | 38 | # geocodebr 0.1.0 39 | 40 | - Primeira versão estável. 41 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | rcpp_distance_haversine <- function(latFrom, lonFrom, latTo, lonTo, tolerance) { 5 | .Call(`_geocodebr_rcpp_distance_haversine`, latFrom, lonFrom, latTo, lonTo, tolerance) 6 | } 7 | 8 | -------------------------------------------------------------------------------- /R/busca_por_cep.R: -------------------------------------------------------------------------------- 1 | #' Busca por CEP 2 | #' 3 | #' Busca endereços e suas coordenadas geográficas a partir de um CEP. As 4 | #' coordenadas de output utilizam o sistema de coordenadas geográficas SIRGAS 5 | #' 2000, EPSG 4674. 6 | #' 7 | #' @param cep Vetor. Um CEP ou um vetor de CEPs com 8 dígitos. 8 | #' @param resultado_sf Lógico. Indica se o resultado deve ser um objeto espacial 9 | #' da classe `sf`. Por padrão, é `FALSE`, e o resultado é um `data.frame`. 10 | #' @template verboso 11 | #' @template cache 12 | #' 13 | #' @return Retorna um `data.frame` com os CEPs de input e os endereços presentes 14 | #' naquele CEP com suas coordenadas geográficas de latitude (`lat`) e 15 | #' longitude (`lon`). Alternativamente, o resultado pode ser um objeto `sf`. 16 | #' 17 | #' @examplesIf identical(tolower(Sys.getenv("NOT_CRAN")), "true") 18 | #' library(geocodebr) 19 | #' 20 | #' # amostra de CEPs 21 | #' ceps <- c("70390-025", "20071-001", "99999-999") 22 | #' 23 | #' df <- geocodebr::busca_por_cep( 24 | #' cep = ceps, 25 | #' verboso = FALSE 26 | #' ) 27 | #' 28 | #' df 29 | #' 30 | #' @export 31 | busca_por_cep <- function(cep, 32 | resultado_sf = FALSE, 33 | verboso = TRUE, 34 | cache = TRUE){ 35 | 36 | # check input 37 | checkmate::assert_vector(cep) 38 | checkmate::assert_logical(resultado_sf, any.missing = FALSE, len = 1) 39 | checkmate::assert_logical(verboso, any.missing = FALSE, len = 1) 40 | checkmate::assert_logical(cache, any.missing = FALSE, len = 1) 41 | 42 | 43 | # normalize input data ------------------------------------------------------- 44 | 45 | cep_padrao <- enderecobr::padronizar_ceps(cep) 46 | 47 | 48 | 49 | # download cnefe ------------------------------------------------------- 50 | 51 | # downloading cnefe 52 | cnefe_dir <- download_cnefe( 53 | tabela = 'municipio_logradouro_cep_localidade', 54 | verboso = verboso, 55 | cache = cache 56 | ) 57 | 58 | 59 | # Load CNEFE data and filter it to include only states 60 | # present in the input table, reducing the search scope 61 | # Narrow search global scope of cnefe to bounding box 62 | path_to_parquet <- paste0(listar_pasta_cache(), "/municipio_logradouro_cep_localidade.parquet") 63 | cnefe <- arrow_open_dataset( path_to_parquet ) 64 | 65 | # filtrar por uf ? 66 | 67 | 68 | output_df <- cnefe |> 69 | dplyr::select(cep, estado, municipio, logradouro, localidade, lat, lon) |> # Drop the n_casos column 70 | dplyr::filter(cep %in% cep_padrao) |> 71 | dplyr::collect() 72 | 73 | 74 | # add any missing cep 75 | missing_cep <- cep_padrao[!cep_padrao %in% output_df$cep] 76 | 77 | if (length(missing_cep) == length(cep_padrao)) { 78 | cli::cli_abort("Nenhum CEP foi encontrado.") 79 | } 80 | 81 | if (length(missing_cep)>0) { 82 | temp_dt <- data.table::data.table(cep= missing_cep) 83 | output_df <- data.table::rbindlist(list(output_df, temp_dt), fill = TRUE) 84 | } 85 | 86 | # convert df to simple feature 87 | if (isTRUE(resultado_sf)) { 88 | output_sf <- sfheaders::sf_point( 89 | obj = output_df, 90 | x = 'lon', 91 | y = 'lat', 92 | keep = TRUE 93 | ) 94 | 95 | sf::st_crs(output_sf) <- 4674 96 | return(output_sf) 97 | } 98 | 99 | return(output_df) 100 | } 101 | -------------------------------------------------------------------------------- /R/cache.R: -------------------------------------------------------------------------------- 1 | data_release <- "v0.2.0" 2 | 3 | listar_pasta_cache_padrao <- function() { 4 | fs::path( 5 | tools::R_user_dir("geocodebr", which = "cache"), 6 | glue::glue("data_release_{data_release}") 7 | ) 8 | } 9 | 10 | listar_arquivo_config <- function() { 11 | fs::path( 12 | tools::R_user_dir("geocodebr", which = "config"), 13 | "cache_dir" 14 | ) 15 | } 16 | 17 | #' Define um diretório de cache para o geocodebr 18 | #' 19 | #' Define um diretório de cache para os dados do geocodebr. Essa configuração 20 | #' é persistente entre sessões do R. 21 | #' 22 | #' @param path Uma string. O caminho para o diretório usado para armazenar os 23 | #' dados em cache. Se `NULL`, o pacote usará um diretório versionado salvo 24 | #' dentro do diretório retornado por [tools::R_user_dir()]. 25 | #' 26 | #' @return Retorna de forma invisível o caminho do diretório de cache. 27 | #' 28 | #' @examples 29 | #' definir_pasta_cache(tempdir()) 30 | #' 31 | #' # retoma pasta padrão do pacote 32 | #' definir_pasta_cache( path = NULL) 33 | #' 34 | #' @export 35 | definir_pasta_cache <- function(path) { 36 | checkmate::assert_string(path, null.ok = TRUE) 37 | 38 | if (is.null(path)) { 39 | cache_dir <- listar_pasta_cache_padrao() 40 | } else { 41 | cache_dir <- fs::path_norm(path) 42 | } 43 | 44 | cli::cli_inform( 45 | c("i" = "Definido como pasta de cache {.file {cache_dir}}."), 46 | class = "geocodebr_cache_dir" 47 | ) 48 | 49 | arquivo_config <- listar_arquivo_config() 50 | 51 | if (!fs::file_exists(arquivo_config)) { 52 | fs::dir_create(fs::path_dir(arquivo_config)) 53 | fs::file_create(arquivo_config) 54 | } 55 | 56 | cache_dir <- as.character(cache_dir) 57 | 58 | writeLines(cache_dir, con = arquivo_config) 59 | 60 | return(invisible(cache_dir)) 61 | } 62 | 63 | 64 | 65 | #' Obtém a pasta de cache usado no geocodebr 66 | #' 67 | #' Obtém o caminho da pasta utilizada para armazenar em cache os dados do 68 | #' geocodebr. Útil para inspecionar a pasta configurada com [definir_pasta_cache()] 69 | #' em uma sessão anterior do R. Retorna a pasta de cache padrão caso nenhuma 70 | #' pasta personalizado tenha sido configurada anteriormente. 71 | #' 72 | #' @return O caminho da pasta de cache. 73 | #' 74 | #' @examples 75 | #' listar_pasta_cache() 76 | #' 77 | #' @export 78 | listar_pasta_cache <- function() { 79 | arquivo_config <- listar_arquivo_config() 80 | 81 | if (fs::file_exists(arquivo_config)) { 82 | cache_dir <- readLines(arquivo_config) 83 | cache_dir <- fs::path_norm(cache_dir) 84 | } else { 85 | cache_dir <- listar_pasta_cache_padrao() 86 | } 87 | 88 | cache_dir <- as.character(cache_dir) 89 | 90 | return(cache_dir) 91 | } 92 | 93 | #' Listar dados em cache 94 | #' 95 | #' Lista os dados salvos localmente na pasta de cache 96 | #' 97 | #' @param print_tree Um valor lógico. Indica se o conteúdo da pasta de cache 98 | #' deve ser exibido em um formato de árvore. O padrão é `FALSE`. 99 | #' 100 | #' @return O caminho para os arquivos em cache 101 | #' 102 | #' @examples 103 | #' listar_dados_cache() 104 | #' 105 | #' listar_dados_cache(print_tree = TRUE) 106 | #' 107 | #' @export 108 | listar_dados_cache <- function(print_tree = FALSE) { 109 | checkmate::assert_logical(print_tree, any.missing = FALSE, len = 1) 110 | 111 | cache_dir <- listar_pasta_cache() 112 | 113 | if (!fs::dir_exists(cache_dir)) return(character(0)) 114 | 115 | cached_data <- list.files(cache_dir, recursive = TRUE, full.names = TRUE) 116 | 117 | if (print_tree) { 118 | fs::dir_tree(cache_dir) 119 | return(invisible(cached_data)) 120 | } 121 | 122 | return(cached_data) 123 | } 124 | 125 | 126 | #' Deletar pasta de cache do geocodebr 127 | #' 128 | #' Deleta todos arquivos da pasta do cache. 129 | #' 130 | #' @return Retorna de forma invisível o caminho do diretório de cache. 131 | #' 132 | #' @examplesIf identical(TRUE, FALSE) 133 | #' deletar_pasta_cache() 134 | #' 135 | #' @export 136 | deletar_pasta_cache <- function() { 137 | cache_dir <- listar_pasta_cache() 138 | 139 | unlink(cache_dir, recursive = TRUE) 140 | 141 | message_removed_cache_dir(cache_dir) 142 | 143 | return(invisible(cache_dir)) 144 | } 145 | 146 | message_removed_cache_dir <- function(cache_dir) { 147 | geocodebr_message( 148 | c( 149 | "v" = "Deletada a pasta de cache que se encontrava em {.path {cache_dir}}." 150 | ) 151 | ) 152 | } 153 | -------------------------------------------------------------------------------- /R/create_geocodebr_db.R: -------------------------------------------------------------------------------- 1 | create_geocodebr_db <- function( # nocov start 2 | db_path = "tempdir", 3 | n_cores = NULL){ 4 | 5 | # check input 6 | checkmate::assert_number(n_cores, null.ok = TRUE) 7 | # checkmate::assert_string(db_path, pattern = "tempdir|memory") 8 | 9 | 10 | # this creates a local database which allows DuckDB to 11 | # perform **larger-than-memory** workloads 12 | if(db_path == 'tempdir'){ 13 | db_path <- tempfile(pattern = 'geocodebr', fileext = '.duckdb') 14 | } 15 | 16 | if(db_path == 'memory'){ 17 | con <- duckdb::dbConnect(duckdb::duckdb(), dbdir= ":memory:" ) 18 | } 19 | 20 | # create db connection 21 | con <- duckdb::dbConnect( 22 | duckdb::duckdb( bigint = "integer64" ), 23 | dbdir= db_path 24 | ) # db_path ":memory:" 25 | 26 | # Set Number of cores for parallel operation 27 | if (is.null(n_cores)) { 28 | n_cores <- parallel::detectCores() 29 | n_cores <- n_cores - 1 30 | if (n_cores<1) {n_cores <- 1} 31 | } 32 | 33 | DBI::dbExecute(con, sprintf("SET threads = %s;", n_cores)) 34 | 35 | # Set Memory limit 36 | # DBI::dbExecute(con, "SET memory_limit = '8GB'") 37 | 38 | return(con) 39 | } # nocov end 40 | -------------------------------------------------------------------------------- /R/definir_campos.R: -------------------------------------------------------------------------------- 1 | #' Especifica as colunas que descrevem os campos dos endereços 2 | #' 3 | #' Cria um vetor de caracteres especificando as colunas que representam cada 4 | #' campo do endereço na tabela de endereços. Os campos `estado` e `municipio` 5 | #' são obrigatórios. 6 | 7 | #' @param estado Uma string. O nome da coluna que representa o estado do 8 | #' endereço. Campo obrigatório. Na tabela de endereços, essa coluna pode 9 | #' conter os nomes dos estados por extenso, ou a abrevição oficial dos estados 10 | #' com duas letras, e.g. "AM", "SP", "DF", "RJ". 11 | #' @param municipio Uma string. O nome da coluna que representa o município do 12 | #' endereço. Campo obrigatório. Na tabela de endereços, essa coluna pode 13 | #' conter o nome dos municípios, ou o seu código IBGE de 7 dígitos. 14 | #' @param logradouro Uma string. O nome da coluna que representa o *logradouro* 15 | #' (endereço da rua) do endereço. Pode ser `NULL` se o campo não estiver 16 | #' especificado na tabela de endereços. Na tabela de endereços, essa coluna 17 | #' deve incluir o *tipo* do lograoduro, indicando se trata-se de uma "Rua" ou 18 | #' "Avenida" etc, por exemplo "Avenida Presidente Getúlio Vargas". Além disso, 19 | #' essa coluna *não* deve incluir o `numero` do endereço, pois o número deve 20 | #' ser indicado numa coluna separada. 21 | #' @param numero Uma string. O nome da coluna que representa o número do endereço. 22 | #' Pode ser `NULL` se o campo não estiver especificado na tabela de endereços. 23 | #' Na tabela de endereços, valores como `0` ou caracteres não numerciso como 24 | #' `"S/N"` ou `"10a"` são considerados como `NA`. 25 | #' @param cep Uma string. O nome da coluna que representa o *CEP* (Código de 26 | #' Endereçamento Postal) do endereço. Pode ser `NULL` se o campo não estiver 27 | #' especificado na tabela de endereços. 28 | #' @param localidade Uma string. O nome da coluna que representa a localidade 29 | #' (equivalente ao 'bairro' em áreas urbanas) do endereço. Pode ser `NULL` se 30 | #' esse campo não estiver presente na tabela de endereços. 31 | #' 32 | #' @return Um vetor de caracteres no qual os nomes são os campos do endereço e os 33 | #' valores são as colunas que os representam na tabela de endereços. 34 | #' 35 | #' @examples 36 | #' definir_campos( 37 | #' logradouro = "Nome_logradouro", 38 | #' numero = "Numero", 39 | #' cep = "CEP", 40 | #' localidade = "Bairro", 41 | #' municipio = "Cidade", 42 | #' estado = "UF" 43 | #' ) 44 | #' 45 | #' @export 46 | definir_campos <- function(estado, 47 | municipio, 48 | logradouro = NULL, 49 | numero = NULL, 50 | cep = NULL, 51 | localidade = NULL) { 52 | 53 | col <- checkmate::makeAssertCollection() 54 | checkmate::assert_string(logradouro, null.ok = TRUE, add = col) 55 | checkmate::assert_string(numero, null.ok = TRUE, add = col) 56 | checkmate::assert_string(cep, null.ok = TRUE, add = col) 57 | checkmate::assert_string(localidade, null.ok = TRUE, add = col) 58 | checkmate::assert_string(municipio, null.ok = TRUE, add = col) 59 | checkmate::assert_string(estado, null.ok = TRUE, add = col) 60 | checkmate::reportAssertions(col) 61 | 62 | address_fields <- c( 63 | logradouro = logradouro, 64 | numero = numero, 65 | cep = cep, 66 | localidade = localidade, 67 | municipio = municipio, 68 | estado = estado 69 | ) 70 | 71 | if (is.null(address_fields)) error_null_address_fields() 72 | 73 | return(address_fields) 74 | } 75 | 76 | error_null_address_fields <- function() { 77 | geocodebr_error( 78 | "Pelo menos um campo n\u00e3o pode ser nulo {.code NULL}.", 79 | call = rlang::caller_env() 80 | ) 81 | } 82 | -------------------------------------------------------------------------------- /R/download_cnefe.R: -------------------------------------------------------------------------------- 1 | #' Faz download dos dados do CNEFE 2 | #' 3 | #' Faz o download de uma versão pre-processada e enriquecida do CNEFE (Cadastro 4 | #' Nacional de Endereços para Fins Estatísticos) que foi criada para o uso deste 5 | #' pacote. 6 | #' 7 | #' @param tabela Nome da tabela para ser baixada. Por padrão, baixa `"todas"`. 8 | #' @template verboso 9 | #' @template cache 10 | #' 11 | #' @return Retorna o caminho para o diretório onde os dados foram salvos. 12 | #' 13 | #' @examplesIf identical(tolower(Sys.getenv("NOT_CRAN")), "true") 14 | #' download_cnefe(verboso = FALSE) 15 | #' 16 | #' @export 17 | download_cnefe <- function(tabela = "todas", verboso = TRUE, cache = TRUE) { 18 | 19 | all_files <- c( 20 | "municipio_logradouro_numero_localidade.parquet", # 4 largest files ok 3 21 | "municipio_logradouro_numero_cep_localidade.parquet", # 4 largest files ok 1 22 | "municipio.parquet", 23 | "municipio_cep.parquet", 24 | "municipio_cep_localidade.parquet", 25 | "municipio_localidade.parquet", 26 | # "municipio_logradouro.parquet", 27 | # "municipio_logradouro_numero_cep.parquet", # 4 largest files 28 | # "municipio_logradouro_cep.parquet", 29 | "municipio_logradouro_cep_localidade.parquet", # ok 1 30 | # "municipio_logradouro_numero.parquet", # 4 largest files 31 | "municipio_logradouro_localidade.parquet" # ok 3 32 | ) 33 | all_files_basename <- fs::path_ext_remove(all_files) 34 | 35 | 36 | # check input 37 | checkmate::assert_logical(verboso, any.missing = FALSE, len = 1) 38 | checkmate::assert_logical(cache, any.missing = FALSE, len = 1) 39 | 40 | # seleciona tabela 41 | if (tabela != "todas") { 42 | 43 | if (!any(all_files %like% tabela)){ 44 | cli::cli_abort("A 'tabela' deve ser uma das seguintes op\u00e7\u00f5es: {all_files_basename}") 45 | } 46 | 47 | all_files <- all_files_basename[all_files_basename == tabela] 48 | all_files <- paste0(all_files, ".parquet") 49 | } 50 | 51 | 52 | data_urls <- glue::glue( 53 | "https://github.com/ipeaGIT/padronizacao_cnefe/releases/", 54 | "download/{data_release}/{all_files}" 55 | ) 56 | 57 | if (!cache) { 58 | data_dir <- as.character(fs::path_norm(tempfile("standardized_cnefe"))) 59 | } else { 60 | data_dir <- listar_pasta_cache() 61 | } 62 | fs::dir_create(data_dir) 63 | 64 | # we only need to download data that hasn't been downloaded yet. note that if 65 | # cache=FALSE data_dir is always empty, so we download all required data 66 | 67 | existing_files <- list.files(data_dir) 68 | 69 | files_to_download <- setdiff(all_files, existing_files) 70 | files_to_download <- data_urls[all_files %in% files_to_download] 71 | 72 | if (length(files_to_download) == 0) { 73 | 74 | if (verboso) { message_usando_cnefe_local() } 75 | 76 | return(invisible(data_dir)) 77 | } 78 | 79 | downloaded_files <- download_files(data_dir, files_to_download, verboso) 80 | 81 | # the download_dir object below should be identical to data_dir, but we return 82 | # its value, instead of data_dir, just to make sure the that data is 83 | # downloaded to the correct dir and that nothing went wrong between setting 84 | # data_dir and downloading the data 85 | 86 | download_dir <- unique(fs::path_dir(downloaded_files)) 87 | 88 | return(invisible(download_dir)) 89 | } 90 | 91 | 92 | download_files <- function(data_dir, files_to_download, verboso) { 93 | requests <- lapply(files_to_download, httr2::request) 94 | 95 | dest_files <- fs::path(data_dir, basename(files_to_download)) 96 | 97 | responses <- perform_requests_in_parallel(requests, dest_files, verboso) 98 | 99 | response_errored <- purrr::map_lgl( 100 | responses, 101 | function(r) inherits(r, "error") 102 | ) 103 | 104 | if (any(response_errored)) error_cnefe_download_failed() 105 | 106 | return(dest_files) 107 | } 108 | 109 | perform_requests_in_parallel <- function(requests, dest_files, verboso) { 110 | # we create this wrapper around httr2::req_perform_parallel just for testing 111 | # purposes. it's easier to mock this function when testing than to mock a 112 | # function from another package. 113 | # 114 | # related test: "errors if could not download the data for one or more states" 115 | # in test-download_cnefe 116 | # 117 | # related help page: 118 | # https://testthat.r-lib.org/reference/local_mocked_bindings.html 119 | 120 | if (verboso) { message_baixando_cnefe() } 121 | 122 | httr2::req_perform_parallel( 123 | requests, 124 | paths = dest_files, 125 | on_error = "continue", 126 | progress = ifelse(verboso == TRUE, 'z', FALSE) 127 | ) 128 | } 129 | 130 | error_cnefe_download_failed <- function() { 131 | geocodebr_error( 132 | c( 133 | "Could not download one or more CNEFE data files.", 134 | "i" = "Please try again later." 135 | ), 136 | call = rlang::caller_env(n = 2) 137 | ) 138 | } 139 | -------------------------------------------------------------------------------- /R/error.R: -------------------------------------------------------------------------------- 1 | geocodebr_error <- function(message, call, .envir = parent.frame()) { 2 | error_call <- sys.call(-1) 3 | error_function <- as.name(error_call[[1]]) 4 | 5 | error_classes <- c( 6 | paste0("geocodebr_error_", sub("^error_", "", error_function)), 7 | "geocodebr_error" 8 | ) 9 | 10 | cli::cli_abort(message, class = error_classes, call = call, .envir = .envir) 11 | } 12 | -------------------------------------------------------------------------------- /R/geocode_reverso.R: -------------------------------------------------------------------------------- 1 | #' Geocode reverso de coordenadas espaciais no Brasil 2 | #' 3 | #' @description 4 | #' Geocode reverso de coordenadas geográficas para endereços. A função recebe um 5 | #' `sf data frame` com pontos e retorna o endereço mais próximo dando uma 6 | #' distância máxima de busca. 7 | #' 8 | #' @param pontos Uma tabela de dados com classe espacial `sf data frame` no 9 | #' sistema de coordenadas geográficas SIRGAS 2000, EPSG 4674. 10 | #' @param dist_max Integer. Distancia máxima aceitável (em metros) entre os 11 | #' pontos de input e o endereço Por padrão, a distância é de 1000 metros. 12 | #' @template verboso 13 | #' @template cache 14 | #' @template n_cores 15 | #' 16 | #' @return Retorna o `sf data.frame` de input adicionado das colunas do endereço 17 | #' encontrado. O output inclui uma coluna "distancia_metros" que indica 18 | #' a distância entre o ponto de input e o endereço mais próximo 19 | #' encontrado. 20 | #' 21 | #' @examplesIf identical(tolower(Sys.getenv("NOT_CRAN")), "true") 22 | #' library(geocodebr) 23 | #' library(sf) 24 | #' 25 | #' # ler amostra de dados 26 | #' pontos <- readRDS( 27 | #' system.file("extdata/pontos.rds", package = "geocodebr") 28 | #' ) 29 | #' 30 | #' pontos <- pontos[1:50,] 31 | #' 32 | #' # geocode reverso 33 | #' df_enderecos <- geocodebr::geocode_reverso( 34 | #' pontos = pontos, 35 | #' dist_max = 1000, 36 | #' verboso = TRUE, 37 | #' n_cores = 1 38 | #' ) 39 | #' 40 | #' @export 41 | geocode_reverso <- function(pontos, 42 | dist_max = 1000, 43 | verboso = TRUE, 44 | cache = TRUE, 45 | n_cores = 1){ 46 | 47 | # check input 48 | checkmate::assert_class(pontos, 'sf') 49 | checkmate::assert_number(dist_max, lower = 500, upper = 100000) # max 100 Km 50 | checkmate::assert_logical(verboso) 51 | checkmate::assert_logical(cache) 52 | checkmate::assert_number(n_cores) 53 | 54 | # check if geometry type is POINT 55 | if (any(sf::st_geometry_type(pontos) != 'POINT')) { 56 | cli::cli_abort("Input precisa ser um sf data frame com geometria do tipo POINT.") 57 | } 58 | 59 | epsg <- sf::st_crs(pontos)$epsg 60 | if (epsg != 4674) { 61 | cli::cli_abort("Dados de input precisam estar com sistema de coordenadas geogr\u00e1ficas SIRGAS 2000, EPSG 4674.") 62 | } 63 | 64 | 65 | # prep input ------------------------------------------------------- 66 | 67 | # converte para data.frame 68 | coords <- sfheaders::sf_to_df(pontos, fill = TRUE) 69 | data.table::setDT(coords) 70 | coords[, c('sfg_id', 'point_id') := NULL] 71 | data.table::setnames(coords, old = c('x', 'y'), new = c('lon', 'lat')) 72 | 73 | # create temp id 74 | coords[, tempidgeocodebr := 1:nrow(coords) ] 75 | 76 | # convert max_dist to degrees 77 | # 1 degree of latitude is always 111320 meters 78 | margin_lat <- dist_max / 111320 79 | 80 | # 1 degree of longitude is 111320 * cos(lat) 81 | coords[, c("lat_min", "lat_max") := .(lat - margin_lat, lat + margin_lat)] 82 | 83 | coords[, c("lon_min", "lon_max") := .(lon - dist_max / 111320 * cos(lat), 84 | lon + dist_max / 111320 * cos(lat)) 85 | ] 86 | 87 | # get bounding box around input points 88 | # using a range of max dist around input points 89 | bbox_lat_min <- min(coords$lat_min) 90 | bbox_lat_max <- max(coords$lat_max) 91 | bbox_lon_min <- min(coords$lon_min) 92 | bbox_lon_max <- max(coords$lon_max) 93 | 94 | 95 | # check if input falls within Brazil 96 | bbox_brazil <- data.frame( 97 | xmin = -73.99044997, 98 | ymin = -33.75208127, 99 | xmax = -28.83594354, 100 | ymax = 5.27184108 101 | ) 102 | 103 | error_msg <- 'Coordenadas de input localizadas fora do bounding box do Brasil.' 104 | if(bbox_lon_min < bbox_brazil$xmin | 105 | bbox_lon_max > bbox_brazil$xmax | 106 | bbox_lat_min < bbox_brazil$ymin | 107 | bbox_lat_max > bbox_brazil$ymax) { stop(error_msg) } 108 | 109 | 110 | # download cnefe ------------------------------------------------------- 111 | 112 | # downloading cnefe 113 | cnefe_dir <- download_cnefe( 114 | tabela = 'municipio_logradouro_numero_cep_localidade', 115 | verboso = verboso, 116 | cache = cache 117 | ) 118 | 119 | 120 | # limita escopo de busca aos municipios ------------------------------------------------------- 121 | 122 | # determine potential municipalities 123 | bbox_munis <- readRDS(system.file("extdata/munis_bbox.rds", package = "geocodebr")) 124 | 125 | get_muni <- function(i){ # i=10 126 | temp <- coords[i,] 127 | potential_muni <- dplyr::filter( 128 | bbox_munis, 129 | xmin <= temp$lon_min & 130 | xmax >= temp$lon_max & 131 | ymin <= temp$lat_min & 132 | ymax >= temp$lat_max)$code_muni 133 | return(potential_muni) 134 | } 135 | 136 | potential_munis <- lapply(X=1:nrow(coords), FUN=get_muni) 137 | potential_munis <- unlist(potential_munis) |> unique() 138 | 139 | potential_munis <- enderecobr::padronizar_municipios(potential_munis) 140 | # Load CNEFE data and filter it to include only states 141 | # present in the input table, reducing the search scope 142 | # Narrow search global scope of cnefe to bounding box 143 | path_to_parquet <- paste0(listar_pasta_cache(), "/municipio_logradouro_numero_cep_localidade.parquet") 144 | filtered_cnefe <- arrow_open_dataset( path_to_parquet ) |> 145 | dplyr::filter(municipio %in% potential_munis) |> 146 | dplyr::compute() 147 | 148 | 149 | # creating a temporary db and register the input table data 150 | con <- create_geocodebr_db(n_cores = n_cores) 151 | 152 | # register filtered_cnefe to db 153 | duckdb::duckdb_register_arrow(con, "filtered_cnefe", filtered_cnefe) 154 | 155 | # Convert input data frame to DuckDB table 156 | duckdb::dbWriteTable(con, "input_table_db", coords, 157 | temporary = TRUE) 158 | 159 | 160 | 161 | 162 | # Find cases nearby ------------------------------------------------------- 163 | 164 | query_filter_cases_nearby <- glue::glue( 165 | "SELECT 166 | input_table_db.*, 167 | filtered_cnefe.endereco_completo, 168 | filtered_cnefe.estado, 169 | filtered_cnefe.municipio, 170 | filtered_cnefe.logradouro, 171 | filtered_cnefe.numero, 172 | filtered_cnefe.cep, 173 | filtered_cnefe.localidade, 174 | filtered_cnefe.lat AS lat_cnefe, 175 | filtered_cnefe.lon AS lon_cnefe 176 | FROM 177 | input_table_db, filtered_cnefe 178 | WHERE 179 | input_table_db.lat_min < filtered_cnefe.lat 180 | AND input_table_db.lat_max > filtered_cnefe.lat 181 | AND input_table_db.lon_min < filtered_cnefe.lon 182 | AND input_table_db.lon_max > filtered_cnefe.lon;" 183 | ) 184 | 185 | output <- DBI::dbGetQuery(con, query_filter_cases_nearby) 186 | 187 | 188 | # organize output ------------------------------------------------- 189 | 190 | data.table::setDT(output) 191 | output[, c('lon_min', 'lon_max', 'lat_min', 'lat_max') := NULL] 192 | 193 | # calculate distances between pairs of coodinates 194 | # 66666666make it faster with rcpp_distance_haversine 195 | # output[, distancia_metros2 := rcpp_distance_haversine( 196 | # lat, lon, lat_cnefe, lon_cnefe, tolerance = 1e10)] 197 | output[, distancia_metros := dt_haversine(lat, lon, lat_cnefe, lon_cnefe)] 198 | 199 | # find the closest point 200 | output <- output[output[, .I[distancia_metros == min(distancia_metros)], by = tempidgeocodebr]$V1] 201 | 202 | # sort data 203 | output <- output[order(tempidgeocodebr)] 204 | output[, tempidgeocodebr := NULL] 205 | 206 | duckdb::duckdb_unregister_arrow(con, "filtered_cnefe") 207 | duckdb::dbDisconnect(con) 208 | 209 | # convert df to simple feature 210 | output_sf <- sfheaders::sf_point( 211 | obj = output, 212 | x = 'lon', 213 | y = 'lat', 214 | keep = TRUE 215 | ) 216 | 217 | sf::st_crs(output_sf) <- 4674 218 | 219 | return(output_sf) 220 | } 221 | 222 | -------------------------------------------------------------------------------- /R/geocodebr-package.R: -------------------------------------------------------------------------------- 1 | #' Package: geocodebr: Geolocalização De Endereços Brasileiros (Geocoding 2 | #' Brazilian Addresses) 3 | #' 4 | #' @name geocodebr 5 | #' @aliases geocodebr-package 6 | #' @useDynLib geocodebr, .registration = TRUE 7 | #' 8 | #' @importFrom dplyr mutate select across case_when all_of 9 | #' @importFrom data.table := .I .SD %chin% .GRP .N %like% 10 | #' @importFrom stats weighted.mean 11 | #' @importFrom Rcpp sourceCpp 12 | #' 13 | #' @keywords internal 14 | "_PACKAGE" 15 | 16 | utils::globalVariables( 17 | c( 18 | "year", "temp_local_file", "lon_min", "lon_max", "lat_min", "lat_max", ".", 19 | "lon_diff", "lat_diff", "lon", "lat", "estado", "municipio", 20 | "tempidgeocodebr", "input_padrao", "dist_geocodebr", "empate", "contagem_cnefe", 21 | "temp_lograd_determ", "similaridade_logradouro", 22 | 23 | # due to reverse geocoding draft 24 | "cep", "lat_cnefe", "localidade", "lon_cnefe", "distancia_metros", "logradouro", 25 | "numero", "xmax", "xmin", "ymax", "ymin", 26 | 27 | # due to empates 28 | "endereco_encontrado", "logradouro_encontrado" 29 | ) 30 | ) 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /R/match_cases.R: -------------------------------------------------------------------------------- 1 | match_cases <- function( # nocov start 2 | con = con, 3 | x = 'input_padrao_db', 4 | y = 'filtered_cnefe', 5 | output_tb = "output_db", 6 | key_cols = key_cols, 7 | match_type = match_type, 8 | resultado_completo){ 9 | 10 | # read corresponding parquet file 11 | table_name <- paste(key_cols, collapse = "_") 12 | table_name <- gsub('estado_municipio', 'municipio', table_name) 13 | 14 | # get corresponding parquet table 15 | table_name <- get_reference_table(match_type) 16 | 17 | # build path to local file 18 | path_to_parquet <- paste0(listar_pasta_cache(), "/", table_name, ".parquet") 19 | 20 | # determine geographical scope of the search 21 | input_states <- DBI::dbGetQuery(con, "SELECT DISTINCT estado FROM input_padrao_db;")$estado 22 | input_municipio <- DBI::dbGetQuery(con, "SELECT DISTINCT municipio FROM input_padrao_db;")$municipio 23 | 24 | # Load CNEFE data and write to DuckDB 25 | # filter cnefe to include only states and municipalities 26 | # present in the input table, reducing the search scope 27 | filtered_cnefe <- arrow_open_dataset( path_to_parquet ) |> 28 | dplyr::filter(estado %in% input_states) |> 29 | dplyr::filter(municipio %in% input_municipio) |> 30 | dplyr::compute() 31 | 32 | 33 | # register filtered_cnefe to db 34 | duckdb::duckdb_register_arrow(con, "filtered_cnefe", filtered_cnefe) 35 | 36 | # Create the JOIN condition by concatenating the key columns 37 | join_condition <- paste( 38 | glue::glue("filtered_cnefe.{key_cols} = {x}.{key_cols}"), 39 | collapse = ' AND ' 40 | ) 41 | 42 | # cols that cannot be null 43 | cols_not_null <- paste( 44 | glue::glue("{x}.{key_cols} IS NOT NULL"), 45 | collapse = ' AND ' 46 | ) 47 | 48 | # whether to keep all columns in the result 49 | colunas_encontradas <- "" 50 | additional_cols <- "" 51 | 52 | if (isTRUE(resultado_completo)) { 53 | 54 | colunas_encontradas <- paste0( 55 | glue::glue("{key_cols}_encontrado"), 56 | collapse = ', ') 57 | 58 | colunas_encontradas <- gsub('localidade_encontrado', 'localidade_encontrada', colunas_encontradas) 59 | colunas_encontradas <- paste0(", ", colunas_encontradas) 60 | 61 | additional_cols <- paste0( 62 | glue::glue("filtered_cnefe.{key_cols} AS {key_cols}_encontrado"), 63 | collapse = ', ') 64 | 65 | additional_cols <- gsub('localidade_encontrado', 'localidade_encontrada', additional_cols) 66 | additional_cols <- paste0(", ", additional_cols) 67 | 68 | } 69 | 70 | # summarize query 71 | query_match <- glue::glue( 72 | "INSERT INTO output_db (tempidgeocodebr, lat, lon, tipo_resultado, endereco_encontrado, contagem_cnefe {colunas_encontradas}) 73 | SELECT {x}.tempidgeocodebr, filtered_cnefe.lat, filtered_cnefe.lon, 74 | '{match_type}' AS tipo_resultado, filtered_cnefe.endereco_completo AS endereco_encontrado, 75 | filtered_cnefe.n_casos AS contagem_cnefe {additional_cols} 76 | FROM {x} 77 | LEFT JOIN filtered_cnefe 78 | ON {join_condition} 79 | WHERE {cols_not_null} AND filtered_cnefe.lon IS NOT NULL;" 80 | ) 81 | 82 | DBI::dbSendQueryArrow(con, query_match) 83 | # a <- DBI::dbReadTable(con, 'output_db') 84 | 85 | duckdb::duckdb_unregister_arrow(con, "filtered_cnefe") 86 | 87 | # UPDATE input_padrao_db: Remove observations found in previous step 88 | temp_n <- update_input_db( 89 | con, 90 | update_tb = x, 91 | reference_tb = output_tb 92 | ) 93 | 94 | return(temp_n) 95 | } # nocov end 96 | -------------------------------------------------------------------------------- /R/match_weighted_cases.R: -------------------------------------------------------------------------------- 1 | match_weighted_cases <- function( # nocov start 2 | con = con, 3 | x = 'input_padrao_db', 4 | y = 'filtered_cnefe', 5 | output_tb = "output_db", 6 | key_cols = key_cols, 7 | match_type = match_type, 8 | resultado_completo){ 9 | 10 | # get corresponding parquet table 11 | table_name <- get_reference_table(match_type) 12 | 13 | # build path to local file 14 | path_to_parquet <- paste0(listar_pasta_cache(), "/", table_name, ".parquet") 15 | 16 | # determine geographical scope of the search 17 | input_states <- DBI::dbGetQuery(con, "SELECT DISTINCT estado FROM input_padrao_db;")$estado 18 | input_municipio <- DBI::dbGetQuery(con, "SELECT DISTINCT municipio FROM input_padrao_db;")$municipio 19 | 20 | # Load CNEFE data and write to DuckDB 21 | # filter cnefe to include only states and municipalities 22 | # present in the input table, reducing the search scope 23 | filtered_cnefe <- arrow_open_dataset( path_to_parquet ) |> 24 | dplyr::filter(estado %in% input_states) |> 25 | dplyr::filter(municipio %in% input_municipio) |> 26 | dplyr::compute() 27 | 28 | # register filtered_cnefe to db 29 | duckdb::duckdb_register_arrow(con, "filtered_cnefe", filtered_cnefe) 30 | 31 | # cols that cannot be null 32 | cols_not_null <- paste( 33 | glue::glue("{x}.{key_cols} IS NOT NULL"), 34 | collapse = ' AND ' 35 | ) 36 | 37 | # remove numero from key cols to allow for the matching 38 | key_cols <- key_cols[key_cols != 'numero'] 39 | 40 | # Create the JOIN condition by concatenating the key columns 41 | join_condition <- paste( 42 | glue::glue("{y}.{key_cols} = {x}.{key_cols}"), 43 | collapse = ' AND ' 44 | ) 45 | 46 | 47 | # whether to keep all columns in the result 48 | colunas_encontradas <- "" 49 | additional_cols <- "" 50 | 51 | if (isTRUE(resultado_completo)) { 52 | 53 | colunas_encontradas <- paste0( 54 | glue::glue("{key_cols}_encontrado"), 55 | collapse = ', ') 56 | 57 | colunas_encontradas <- gsub('localidade_encontrado', 'localidade_encontrada', colunas_encontradas) 58 | colunas_encontradas <- paste0(", ", colunas_encontradas) 59 | 60 | additional_cols <- paste0( 61 | glue::glue("filtered_cnefe.{key_cols} AS {key_cols}_encontrado"), 62 | collapse = ', ') 63 | 64 | additional_cols <- gsub('localidade_encontrado', 'localidade_encontrada', additional_cols) 65 | additional_cols <- paste0(", ", additional_cols) 66 | 67 | } 68 | 69 | 70 | # 1st step: match -------------------------------------------------------- 71 | 72 | # match query 73 | query_match <- glue::glue( 74 | "CREATE OR REPLACE TEMPORARY VIEW temp_db AS 75 | SELECT {x}.tempidgeocodebr, {x}.numero, {y}.numero AS numero_cnefe, 76 | {y}.lat, {y}.lon, 77 | REGEXP_REPLACE( {y}.endereco_completo, ', \\d+ -', CONCAT(', ', {x}.numero, ' (aprox) -')) AS endereco_encontrado, 78 | {y}.n_casos AS contagem_cnefe {additional_cols} 79 | FROM {x} 80 | LEFT JOIN {y} 81 | ON {join_condition} 82 | WHERE {cols_not_null} AND {y}.numero IS NOT NULL AND lon IS NOT NULL;" 83 | ) 84 | 85 | DBI::dbSendQueryArrow(con, query_match) 86 | # a <- DBI::dbReadTable(con, 'temp_db') 87 | 88 | 89 | 90 | # 2nd step: aggregate -------------------------------------------------------- 91 | 92 | # summarize query 93 | query_aggregate <- glue::glue( 94 | "INSERT INTO output_db (tempidgeocodebr, lat, lon, tipo_resultado, endereco_encontrado, contagem_cnefe) 95 | SELECT tempidgeocodebr, 96 | SUM((1/ABS(numero - numero_cnefe) * lat)) / SUM(1/ABS(numero - numero_cnefe)) AS lat, 97 | SUM((1/ABS(numero - numero_cnefe) * lon)) / SUM(1/ABS(numero - numero_cnefe)) AS lon, 98 | '{match_type}' AS tipo_resultado, 99 | FIRST(endereco_encontrado) AS endereco_encontrado, FIRST(contagem_cnefe) AS contagem_cnefe 100 | FROM temp_db 101 | GROUP BY tempidgeocodebr, endereco_encontrado;" 102 | ) 103 | 104 | 105 | 106 | if (isTRUE(resultado_completo)) { 107 | 108 | additional_cols <- paste0( 109 | glue::glue("FIRST({key_cols}_encontrado)"), 110 | collapse = ', ') 111 | 112 | additional_cols <- gsub('localidade_encontrado', 'localidade_encontrada', additional_cols) 113 | additional_cols <- paste0(", ", additional_cols) 114 | 115 | query_aggregate <- glue::glue( 116 | "INSERT INTO output_db (tempidgeocodebr, lat, lon, tipo_resultado, endereco_encontrado, contagem_cnefe {colunas_encontradas}) 117 | SELECT tempidgeocodebr, 118 | SUM((1/ABS(numero - numero_cnefe) * lat)) / SUM(1/ABS(numero - numero_cnefe)) AS lat, 119 | SUM((1/ABS(numero - numero_cnefe) * lon)) / SUM(1/ABS(numero - numero_cnefe)) AS lon, 120 | '{match_type}' AS tipo_resultado, 121 | FIRST(endereco_encontrado) AS endereco_encontrado, 122 | FIRST(contagem_cnefe) AS contagem_cnefe {additional_cols} 123 | FROM temp_db 124 | GROUP BY tempidgeocodebr, endereco_encontrado;" 125 | ) 126 | } 127 | 128 | DBI::dbSendQueryArrow(con, query_aggregate) 129 | # b <- DBI::dbReadTable(con, 'output_db') 130 | 131 | 132 | duckdb::duckdb_unregister_arrow(con, "filtered_cnefe") 133 | 134 | # UPDATE input_padrao_db: Remove observations found in previous step 135 | temp_n <- update_input_db( 136 | con, 137 | update_tb = x, 138 | reference_tb = output_tb 139 | ) 140 | 141 | return(temp_n) 142 | } # nocov end 143 | -------------------------------------------------------------------------------- /R/message.R: -------------------------------------------------------------------------------- 1 | geocodebr_message <- function(message, .envir = parent.frame()) { 2 | message_call <- sys.call(-1) 3 | message_function <- as.name(message_call[[1]]) 4 | 5 | message_classes <- c( 6 | paste0("geocodebr_message_", sub("^message_", "", message_function)), 7 | "geocodebr_message" 8 | ) 9 | 10 | cli::cli_inform(message, class = message_classes, .envir = .envir) 11 | } 12 | 13 | message_standardizing_addresses <- function() { 14 | geocodebr_message(c("i" = "Padronizando endere\u00e7os de entrada")) 15 | } 16 | 17 | message_baixando_cnefe <- function() { 18 | geocodebr_message(c("i" = "Baixando dados do CNEFE")) 19 | } 20 | 21 | message_usando_cnefe_local <- function() { 22 | geocodebr_message(c("i" = "Utilizando dados do CNEFE armazenados localmente")) 23 | } 24 | 25 | message_looking_for_matches <- function() { 26 | geocodebr_message(c("i" = "Geolocalizando endere\u00e7os")) 27 | } 28 | 29 | message_preparando_output <- function() { 30 | geocodebr_message(c("i" = "Preparando resultados")) 31 | } 32 | -------------------------------------------------------------------------------- /R/progress_bar.R: -------------------------------------------------------------------------------- 1 | 2 | create_progress_bar <- function(standard_locations, .envir = parent.frame()) { 3 | cli::cli_progress_bar( 4 | total = nrow(standard_locations), 5 | format = "Endere\u00e7os processados: {formatC(cli::pb_current, big.mark = ',', format = 'd')}/{formatC(cli::pb_total, big.mark = ',', format = 'd')} {cli::pb_bar} {cli::pb_percent} - {cli::pb_status}", 6 | clear = FALSE, 7 | .envir = .envir 8 | ) 9 | } 10 | 11 | update_progress_bar <- function(matched_rows, 12 | formatted_case, 13 | .envir = parent.frame()) { 14 | cli::cli_progress_update( 15 | set = matched_rows, 16 | status = glue::glue("Procurando {formatted_case}"), 17 | force = TRUE, 18 | .envir = .envir 19 | ) 20 | } 21 | 22 | finish_progress_bar <- function(matched_rows, .envir = parent.frame()) { 23 | cli::cli_progress_update( 24 | set = matched_rows, 25 | status = "Fim!", 26 | force = TRUE, 27 | .envir = .envir 28 | ) 29 | } 30 | 31 | -------------------------------------------------------------------------------- /R/trata_empates_geocode.R: -------------------------------------------------------------------------------- 1 | 2 | trata_empates_geocode <- function(output_df = parent.frame()$output_df, 3 | resolver_empates = parent.frame()$resolver_empates, 4 | verboso = parent.frame()$verboso) { # nocov start 5 | 6 | # encontra possiveis casos de empate 7 | data.table::setDT(output_df)[, empate := ifelse(.N > 1, TRUE, FALSE), by = tempidgeocodebr] 8 | 9 | # # calcula distancias entre casos empatados 10 | output_df[empate == TRUE, 11 | dist_geocodebr := rcpp_distance_haversine( 12 | lat, lon, 13 | data.table::shift(lat, type = "lead"), 14 | data.table::shift(lon, type = "lead"), 15 | tolerance = 1e10 16 | ), 17 | by = tempidgeocodebr 18 | ] 19 | 20 | 21 | # MANTEM apenas casos de empate que estao a mais de 300 metros 22 | output_df2 <- output_df[ empate==FALSE | 23 | empate==TRUE & dist_geocodebr == 0 | 24 | empate==TRUE & dist_geocodebr > 300 25 | ] 26 | 27 | # update casos de empate 28 | output_df2[, empate := ifelse(.N > 1, TRUE, FALSE), by = tempidgeocodebr] 29 | 30 | # conta numero de casos empatados 31 | ids_empate <- output_df2[empate == TRUE, ]$tempidgeocodebr 32 | n_casos_empate <- unique(ids_empate) |> length() 33 | 34 | 35 | # se nao for para resolver empates: 36 | # - gera warning 37 | # - retorna resultado assim mesmo 38 | if (isFALSE(resolver_empates)) { 39 | 40 | cli::cli_warn( 41 | "Foram encontrados {n_casos_empate} casos de empate. Estes casos foram 42 | marcados com valor `TRUE` na coluna 'empate', e podem ser inspecionados na 43 | coluna 'endereco_encontrado'. Alternativamente, use `resolver_empates = TRUE` 44 | para que o pacote lide com os empates automaticamente. Ver 45 | documenta\u00e7\u00e3o da fun\u00e7\u00e3o." 46 | ) 47 | } 48 | 49 | 50 | 51 | # se for para resolver empates, trata de 3 casos separados 52 | # a) nao empatados 53 | # b) empatados perdidos (dist > 1Km e lograoduros ambiguos) 54 | # solucao: usa caso com maior contagem_cnefe 55 | # c) empatados mas que da pra salvar (dist < 1km e logradouros nao ambiguos) 56 | # solucao: agrega casos provaveis de serem na mesma rua com media ponderada 57 | # das coordenadas, mas retorna endereco_encontrado do caso com maior 58 | # contagem_cnefe 59 | # questao documnetada no issue 37 60 | 61 | if (isTRUE(resolver_empates)) { 62 | 63 | # a) casos sem empate 64 | df_sem_empate <- output_df2[empate == FALSE] 65 | ids_sem_empate <- df_sem_empate$tempidgeocodebr 66 | 67 | 68 | # b) empatados perdidos (dis > 1Km e lograoduros ambiguos) --------------------------- 69 | 70 | # identifica lograoduros ambiguos (e.g. RUA A) 71 | num_ext <- c( 72 | 'UM', 73 | 'DOIS', 74 | 'TRES', 75 | 'QUATRO', 76 | 'CINCO', 77 | 'SEIS', 78 | 'SETE', 79 | 'OITO', 80 | 'NOVE', 81 | 'DEZ', 82 | 'ONZE', 83 | 'DOZE', 84 | 'TREZE', 85 | 'QUATORZE', 86 | 'QUINZE', 87 | 'DEZESSEIS', 88 | 'DEZESSETE', 89 | 'DEZOITO' , 90 | 'DEZENOVE', 91 | 'VINTE', 92 | 'TRINTA', 93 | 'QUARENTA', 94 | 'CINQUENTA', 95 | 'SESSENTA', 96 | 'SETENTA', 97 | 'OITENTA', 98 | 'NOVENTA' 99 | ) 100 | 101 | # ruas_letras <- paste(paste("RUA", LETTERS), collapse = " |") 102 | # ruas_numerais <- paste(paste("RUA", 1:30), collapse = " |") 103 | # ruas_letras <- paste0(ruas_letras, " ") 104 | # ruas_numerais <- paste0(ruas_numerais, " ") 105 | 106 | ruas_num_ext <- paste(paste("RUA", num_ext), collapse = " |") 107 | ruas_num_ext <- paste0(ruas_num_ext, " ") 108 | 109 | # casos empatados muito distantes 110 | 111 | # ao menos um ponto mais longe q 1Km 112 | ids_empate_too_distant <- output_df2[empate == TRUE & dist_geocodebr>1000, ]$tempidgeocodebr 113 | ## a distancia entre 1o e ultimo ponto maior q 1 Km 114 | # ids_empate_too_distant <- output_df2[empate == TRUE & sum(dist_geocodebr)>1000, ]$tempidgeocodebr 115 | 116 | # tictoc::tic() 117 | # empates_perdidos <- output_df2[ 118 | # empate == TRUE & 119 | # ( 120 | # tempidgeocodebr %in% ids_empate_too_distant | 121 | # endereco_encontrado %like% ruas_letras | 122 | # endereco_encontrado %like% ruas_numerais | 123 | # endereco_encontrado %like% ruas_num_ext | 124 | # endereco_encontrado %like% 'ESTRADA|RODOVIA' 125 | # ) 126 | # ] 127 | # tictoc::toc() 128 | 129 | empates_perdidos <- output_df2[ 130 | empate == TRUE & 131 | ( 132 | tempidgeocodebr %in% ids_empate_too_distant | 133 | endereco_encontrado %like% "^(RUA|TRAVESSA|RAMAL|BECO|BLOCO)\\s+([A-Z]{1,2}|[0-9]{1,3}|[A-Z]{1,2}[0-9]{1,2}|[A-Z]{1,2}\\s+[0-9]{1,2}|[0-9]{1,2}[A-Z]{1,2})\\s+" | 134 | endereco_encontrado %like% ruas_num_ext | 135 | endereco_encontrado %like% 'ESTRADA|RODOVIA' 136 | ) 137 | ] 138 | 139 | # ainda dah pra salvar enderecos com datas (e.g. 'RUA 15 DE NOVEMBRO') 140 | meses_pattern <- "\\b\\DE (JANEIRO|FEVEREIRO|MAR\u00c7O|ABRIL|MAIO|JUNHO|JULHO|AGOSTO|SETEMBRO|OUTUBRO|NOVEMBRO|DEZEMBRO)\\b" 141 | empates_perdidos <- empates_perdidos[ ! grepl(meses_pattern, logradouro_encontrado) ] 142 | 143 | # selecting the row with max 'contagem_cnefe' 144 | empates_perdidos <- empates_perdidos[empates_perdidos[, .I[contagem_cnefe == max(contagem_cnefe, na.rm=TRUE)], by = tempidgeocodebr]$V1] 145 | empates_perdidos <- empates_perdidos[empates_perdidos[, .I[1], by = tempidgeocodebr]$V1] 146 | 147 | 148 | # c) casos de empate que podem ser salvos --------------------------------- 149 | ids_empate_salve <- output_df2[!tempidgeocodebr %in% c(ids_sem_empate, empates_perdidos$tempidgeocodebr)]$tempidgeocodebr 150 | empates_salve <- output_df2[ tempidgeocodebr %in% ids_empate_salve ] 151 | 152 | if (nrow(empates_salve)>0){ 153 | # check if we have every id TRUE: no id should be left behind 154 | length(unique(output_df2$tempidgeocodebr)) == sum( 155 | length(ids_sem_empate), 156 | length(unique(empates_perdidos$tempidgeocodebr)) , 157 | length(unique(ids_empate_salve)) 158 | ) 159 | 160 | # calcula media ponderada das coordenadas 161 | # fica com caso que tem max 'contagem_cnefe' 162 | empates_salve[, c('lat', 'lon') := list(weighted.mean(lat, w = contagem_cnefe), 163 | weighted.mean(lon, w = contagem_cnefe) 164 | ), 165 | by = tempidgeocodebr] 166 | 167 | # selecting the row with max 'contagem_cnefe' 168 | empates_salve <- empates_salve[empates_salve[, .I[contagem_cnefe == max(contagem_cnefe, na.rm=TRUE)], by = tempidgeocodebr]$V1] 169 | empates_salve <- empates_salve[empates_salve[, .I[1], by = tempidgeocodebr]$V1] 170 | 171 | } 172 | 173 | 174 | # junta tudo 175 | output_df2 <- data.table::rbindlist(list(df_sem_empate, empates_salve, empates_perdidos)) 176 | output_df2[, 'contagem_cnefe' := NULL] 177 | 178 | # reorder columns 179 | output_df2 <- output_df2[order(tempidgeocodebr)] 180 | 181 | if (verboso) { 182 | plural <- ifelse(n_casos_empate==1, 'caso', 'casos') 183 | message(glue::glue( 184 | "Foram encontrados e resolvidos {n_casos_empate} {plural} de empate." 185 | )) 186 | } 187 | } 188 | 189 | # drop geocodebr dist columns 190 | output_df2[, dist_geocodebr := NULL] 191 | 192 | return(output_df2) 193 | } # nocov end 194 | 195 | 196 | 197 | 198 | 199 | 200 | # calculate distances between pairs of coodinates 201 | dt_haversine <- function(lat_from, lon_from, lat_to, lon_to, r = 6378137){ # nocov start 202 | radians <- pi/180 203 | lat_to <- lat_to * radians 204 | lat_from <- lat_from * radians 205 | lon_to <- lon_to * radians 206 | lon_from <- lon_from * radians 207 | dLat <- (lat_to - lat_from) 208 | dLon <- (lon_to - lon_from) 209 | a <- (sin(dLat/2)^2) + (cos(lat_from) * cos(lat_to)) * (sin(dLon/2)^2) 210 | dist <- 2 * atan2(sqrt(a), sqrt(1 - a)) * r 211 | return(dist) 212 | } # nocov end 213 | 214 | # Rcpp::sourceCpp("./src/distance_calcs.cpp") 215 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | 16 | # geocodebr: Geolocalização de Endereços Brasileiros 17 | 18 | [![CRAN 19 | status](https://www.r-pkg.org/badges/version/geocodebr)](https://CRAN.R-project.org/package=geocodebr) 20 | [![CRAN/METACRAN Total downloads](https://cranlogs.r-pkg.org/badges/grand-total/geocodebr?color=blue)](https://CRAN.R-project.org/package=geocodebr) 21 | [![check](https://github.com/ipeaGIT/geocodebr/workflows/check/badge.svg)](https://github.com/ipeaGIT/geocodebr/actions) 22 | [![Codecov test 23 | coverage](https://codecov.io/gh/ipeaGIT/geocodebr/branch/main/graph/badge.svg)](https://app.codecov.io/gh/ipeaGIT/geocodebr?branch=main) 24 | [![Lifecycle: 25 | experimental](https://lifecycle.r-lib.org/articles/figures/lifecycle-experimental.svg)](https://lifecycle.r-lib.org/articles/stages.html) 26 | 27 | O **{geocodebr}** é um pacote computacional para geolicalização de endereços Brasileiros. O pacote oferece uma maneira simples e eficiente de geolocalizar 28 | dados sem limite de número de consultas. O pacote é baseado em conjuntos de dados espaciais abertos de endereços brasileiros, utilizando como fonte principal o Cadastro Nacional de Endereços para Fins Estatísticos (CNEFE). O CNEFE é 29 | [publicado](https://www.ibge.gov.br/estatisticas/sociais/populacao/38734-cadastro-nacional-de-enderecos-para-fins-estatisticos.html) pelo Instituto Brasileiro de Geografia e Estatística (IBGE). Atualmente, o pacote está disponível apenas em R. 30 | 31 | 32 | ## Instalação 33 | 34 | A última versão estável pode ser baixada do CRAN com o comando a seguir: 35 | 36 | ```r 37 | # from CRAN 38 | install.packages("geocodebr") 39 | ``` 40 | 41 | Caso prefira, a versão em desenvolvimento: 42 | ```r 43 | # install.packages("remotes") 44 | remotes::install_github("ipeaGIT/geocodebr") 45 | ``` 46 | 47 | ## Utilização 48 | 49 | O {geocodebr} possui três funções principais para geolocalização de dados: 50 | 51 | 1. `geocode()` 52 | 2. `geocode_reverso()` 53 | 3. `busca_por_cep()` 54 | 55 | 56 | ### 1. Geolocalização: de endereços para coordenadas espaciais 57 | 58 | Uma que você possui uma tabela de dados (`data.frame`) com endereços no Brasil, a geolocalização desses dados pode ser feita em apenas dois passos: 59 | 60 | 1. O primeiro passo é usar a função `definir_campos()` para indicar os nomes das colunas no seu `data.frame` que correspondem a cada campo dos endereços. 61 | 62 | 2. O segundo passo é usar a função `geocode()` para encontrar as coordenadas geográficas dos endereços de input. 63 | 64 | 65 | ```{r, eval=TRUE} 66 | library(geocodebr) 67 | library(sf) 68 | 69 | # carregando uma amostra de dados 70 | input_df <- read.csv(system.file("extdata/small_sample.csv", package = "geocodebr")) 71 | 72 | # Primeiro passo: inidicar o nome das colunas com cada campo dos enderecos 73 | campos <- geocodebr::definir_campos( 74 | logradouro = "nm_logradouro", 75 | numero = "Numero", 76 | cep = "Cep", 77 | localidade = "Bairro", 78 | municipio = "nm_municipio", 79 | estado = "nm_uf" 80 | ) 81 | 82 | # Segundo passo: geolocalizar 83 | df <- geocodebr::geocode( 84 | enderecos = input_df, 85 | campos_endereco = campos, 86 | resultado_completo = FALSE, 87 | resolver_empates = FALSE, 88 | resultado_sf = FALSE, 89 | verboso = FALSE, 90 | cache = TRUE, 91 | n_cores = 1 92 | ) 93 | 94 | ``` 95 | 96 | Os resultados do **{geocodebr}** são classificados em seis categorias gerais de `precisao`, dependendo do nível de exatidão com que cada endereço de input foi encontrado nos dados do CNEFE. Para mais informações, consulte a documentação da função ou a [**vignette "geocode"**](https://ipeagit.github.io/geocodebr/articles/geocode.html). 97 | 98 | 99 | ### 2. Geolocalização reversa: de coordenadas espaciais para endereços 100 | 101 | A função `geocode_reverso()`, por sua vez, permite a geolocalização reversa, ou seja, a busca de endereços próximos a um conjunto de coordenadas geográficas. A função pode ser útil, por exemplo, para identificar endereços próximos a pontos de interesse, como escolas, hospitais, ou locais de acidentes. 102 | 103 | Mais detalhes na [**vignette "geocode"**](https://ipeagit.github.io/geocodebr/articles/geocode_reverso.html). 104 | 105 | ```{r, eval=TRUE} 106 | # amostra de pontos espaciais 107 | pontos <- readRDS( 108 | system.file("extdata/pontos.rds", package = "geocodebr") 109 | ) 110 | 111 | pontos <- pontos[1:20,] 112 | 113 | # geocode reverso 114 | df_enderecos <- geocodebr::geocode_reverso( 115 | pontos = pontos, 116 | dist_max = 1000, 117 | verboso = FALSE, 118 | n_cores = 1 119 | ) 120 | 121 | ``` 122 | ### 3. Busca por CEPs 123 | 124 | Por fim, a função `busca_por_cep()` permite fazer consultas de CEPs para encontrar endereços associados a cada CEP e suas coordenadas espaciais. 125 | 126 | ```{r, eval=TRUE} 127 | # amostra de CEPs 128 | ceps <- c("70390-025", "20071-001") 129 | 130 | df_ceps <- geocodebr::busca_por_cep( 131 | cep = ceps, 132 | resultado_sf = FALSE, 133 | verboso = FALSE 134 | ) 135 | ``` 136 | 137 | 138 | ## Projetos relacionados 139 | 140 | Existem diversos pacotes de geolocalização disponíveis, muitos dos quais podem ser utilizados em R (listados abaixo). A maioria dessas alternativas depende de softwares e conjuntos de dados comerciais, geralmente impondo limites de número de consultas gratuitas. Em contraste, as principais vantagens do **{geocodebr}** são que o pacote: (a) é completamente gratuito, permitindo consultas ilimitadas sem nenhum custo; (b) opera com alta velocidade e escalabilidade eficiente, permitindo geocodificar milhões de endereços em apenas alguns minutos, sem a necessidade de infraestrutura computacional avançada ou de alto desempenho. 141 | 142 | 143 | - [{arcgisgeocode}](https://cran.r-project.org/package=arcgisgeocode) and [{arcgeocoder}](https://cran.r-project.org/package=arcgeocoder): utiliza serviço de geocode do ArcGIS 144 | - [{nominatimlite}](https://cran.r-project.org/package=nominatimlite): baseado dados do OSM 145 | - [{photon}](https://cran.r-project.org/package=photon): baseado dados do OSM 146 | - [{tidygeocoder}](https://cran.r-project.org/package=tidygeocoder): API para diversos servicos de geolocalização 147 | - [{googleway}](https://cran.r-project.org/package=googleway) and [{mapsapi}](https://cran.r-project.org/package=mapsapi): interface para API do Google Maps 148 | 149 | 150 | ## Nota IPEA 151 | 152 | Os dados originais do CNEFE são coletados pelo Instituto Brasileiro de Geografia e Estatística (IBGE). O **{geocodebr}** foi desenvolvido por uma equipe do Instituto de Pesquisa Econômica Aplicada (Ipea) 153 | 154 | 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # geocodebr: Geolocalização de Endereços Brasileiros 5 | 6 | [![CRAN 7 | status](https://www.r-pkg.org/badges/version/geocodebr)](https://CRAN.R-project.org/package=geocodebr) 8 | [![CRAN/METACRAN Total 9 | downloads](https://cranlogs.r-pkg.org/badges/grand-total/geocodebr?color=blue)](https://CRAN.R-project.org/package=geocodebr) 10 | [![check](https://github.com/ipeaGIT/geocodebr/workflows/check/badge.svg)](https://github.com/ipeaGIT/geocodebr/actions) 11 | [![Codecov test 12 | coverage](https://codecov.io/gh/ipeaGIT/geocodebr/branch/main/graph/badge.svg)](https://app.codecov.io/gh/ipeaGIT/geocodebr?branch=main) 13 | [![Lifecycle: 14 | experimental](https://lifecycle.r-lib.org/articles/figures/lifecycle-experimental.svg)](https://lifecycle.r-lib.org/articles/stages.html) 15 | 16 | O **{geocodebr}** é um pacote computacional para geolicalização de 17 | endereços Brasileiros. O pacote oferece uma maneira simples e eficiente 18 | de geolocalizar dados sem limite de número de consultas. O pacote é 19 | baseado em conjuntos de dados espaciais abertos de endereços 20 | brasileiros, utilizando como fonte principal o Cadastro Nacional de 21 | Endereços para Fins Estatísticos (CNEFE). O CNEFE é 22 | [publicado](https://www.ibge.gov.br/estatisticas/sociais/populacao/38734-cadastro-nacional-de-enderecos-para-fins-estatisticos.html) 23 | pelo Instituto Brasileiro de Geografia e Estatística (IBGE). Atualmente, 24 | o pacote está disponível apenas em R. 25 | 26 | ## Instalação 27 | 28 | A última versão estável pode ser baixada do CRAN com o comando a seguir: 29 | 30 | ``` r 31 | # from CRAN 32 | install.packages("geocodebr") 33 | ``` 34 | 35 | Caso prefira, a versão em desenvolvimento: 36 | 37 | ``` r 38 | # install.packages("remotes") 39 | remotes::install_github("ipeaGIT/geocodebr") 40 | ``` 41 | 42 | ## Utilização 43 | 44 | O {geocodebr} possui três funções principais para geolocalização de 45 | dados: 46 | 47 | 1. `geocode()` 48 | 2. `geocode_reverso()` 49 | 3. `busca_por_cep()` 50 | 51 | ### 1. Geolocalização: de endereços para coordenadas espaciais 52 | 53 | Uma que você possui uma tabela de dados (`data.frame`) com endereços no 54 | Brasil, a geolocalização desses dados pode ser feita em apenas dois 55 | passos: 56 | 57 | 1. O primeiro passo é usar a função `definir_campos()` para indicar os 58 | nomes das colunas no seu `data.frame` que correspondem a cada campo 59 | dos endereços. 60 | 61 | 2. O segundo passo é usar a função `geocode()` para encontrar as 62 | coordenadas geográficas dos endereços de input. 63 | 64 | ``` r 65 | library(geocodebr) 66 | library(sf) 67 | #> Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE 68 | 69 | # carregando uma amostra de dados 70 | input_df <- read.csv(system.file("extdata/small_sample.csv", package = "geocodebr")) 71 | 72 | # Primeiro passo: inidicar o nome das colunas com cada campo dos enderecos 73 | campos <- geocodebr::definir_campos( 74 | logradouro = "nm_logradouro", 75 | numero = "Numero", 76 | cep = "Cep", 77 | localidade = "Bairro", 78 | municipio = "nm_municipio", 79 | estado = "nm_uf" 80 | ) 81 | 82 | # Segundo passo: geolocalizar 83 | df <- geocodebr::geocode( 84 | enderecos = input_df, 85 | campos_endereco = campos, 86 | resultado_completo = FALSE, 87 | resolver_empates = FALSE, 88 | resultado_sf = FALSE, 89 | verboso = FALSE, 90 | cache = TRUE, 91 | n_cores = 1 92 | ) 93 | #> Warning: Foram encontrados 1 casos de empate. Estes casos foram marcados com valor 94 | #> `TRUE` na coluna 'empate', e podem ser inspecionados na coluna 95 | #> 'endereco_encontrado'. Alternativamente, use `resolver_empates = TRUE` para que 96 | #> o pacote lide com os empates automaticamente. Ver documentação da função. 97 | ``` 98 | 99 | Os resultados do **{geocodebr}** são classificados em seis categorias 100 | gerais de `precisao`, dependendo do nível de exatidão com que cada 101 | endereço de input foi encontrado nos dados do CNEFE. Para mais 102 | informações, consulte a documentação da função ou a [**vignette 103 | “geocode”**](https://ipeagit.github.io/geocodebr/articles/geocode.html). 104 | 105 | ### 2. Geolocalização reversa: de coordenadas espaciais para endereços 106 | 107 | A função `geocode_reverso()`, por sua vez, permite a geolocalização 108 | reversa, ou seja, a busca de endereços próximos a um conjunto de 109 | coordenadas geográficas. A função pode ser útil, por exemplo, para 110 | identificar endereços próximos a pontos de interesse, como escolas, 111 | hospitais, ou locais de acidentes. 112 | 113 | Mais detalhes na [**vignette 114 | “geocode”**](https://ipeagit.github.io/geocodebr/articles/geocode_reverso.html). 115 | 116 | ``` r 117 | # amostra de pontos espaciais 118 | pontos <- readRDS( 119 | system.file("extdata/pontos.rds", package = "geocodebr") 120 | ) 121 | 122 | pontos <- pontos[1:20,] 123 | 124 | # geocode reverso 125 | df_enderecos <- geocodebr::geocode_reverso( 126 | pontos = pontos, 127 | dist_max = 1000, 128 | verboso = FALSE, 129 | n_cores = 1 130 | ) 131 | ``` 132 | 133 | ### 3. Busca por CEPs 134 | 135 | Por fim, a função `busca_por_cep()` permite fazer consultas de CEPs para 136 | encontrar endereços associados a cada CEP e suas coordenadas espaciais. 137 | 138 | ``` r 139 | # amostra de CEPs 140 | ceps <- c("70390-025", "20071-001") 141 | 142 | df_ceps <- geocodebr::busca_por_cep( 143 | cep = ceps, 144 | resultado_sf = FALSE, 145 | verboso = FALSE 146 | ) 147 | ``` 148 | 149 | ## Projetos relacionados 150 | 151 | Existem diversos pacotes de geolocalização disponíveis, muitos dos quais 152 | podem ser utilizados em R (listados abaixo). A maioria dessas 153 | alternativas depende de softwares e conjuntos de dados comerciais, 154 | geralmente impondo limites de número de consultas gratuitas. Em 155 | contraste, as principais vantagens do **{geocodebr}** são que o pacote: 156 | (a) é completamente gratuito, permitindo consultas ilimitadas sem nenhum 157 | custo; (b) opera com alta velocidade e escalabilidade eficiente, 158 | permitindo geocodificar milhões de endereços em apenas alguns minutos, 159 | sem a necessidade de infraestrutura computacional avançada ou de alto 160 | desempenho. 161 | 162 | - [{arcgisgeocode}](https://cran.r-project.org/package=arcgisgeocode) 163 | and [{arcgeocoder}](https://cran.r-project.org/package=arcgeocoder): 164 | utiliza serviço de geocode do ArcGIS 165 | - [{nominatimlite}](https://cran.r-project.org/package=nominatimlite): 166 | baseado dados do OSM 167 | - [{photon}](https://cran.r-project.org/package=photon): baseado dados 168 | do OSM 169 | - [{tidygeocoder}](https://cran.r-project.org/package=tidygeocoder): API 170 | para diversos servicos de geolocalização 171 | - [{googleway}](https://cran.r-project.org/package=googleway) and 172 | [{mapsapi}](https://cran.r-project.org/package=mapsapi): interface 173 | para API do Google Maps 174 | 175 | ## Nota IPEA 176 | 177 | Os dados originais do CNEFE são coletados pelo Instituto Brasileiro de 178 | Geografia e Estatística (IBGE). O **{geocodebr}** foi desenvolvido por 179 | uma equipe do Instituto de Pesquisa Econômica Aplicada (Ipea) 180 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## R CMD check results 2 | 3 | ── R CMD check results ───────────────────────────────────────── geocodebr 0.2.0 ──── 4 | Duration: 6m 44.3s 5 | 6 | 0 errors ✔ | 0 warnings ✔ | 0 notes ✔ 7 | 8 | - fixed error of corrupted data 9 | 10 | ## Novas funcionalidades (Major changes) 11 | 12 | - A função `geocode()` agora inclui busca com match probabilistico. [Encerra issue #34](https://github.com/ipeaGIT/geocodebr/issues/34). 13 | - Nova função `buscapor_cep()`. [Encerra issue #8](https://github.com/ipeaGIT/geocodebr/issues/8). 14 | - Nova função `geocode_reverso()`. [Encerra issue #35](https://github.com/ipeaGIT/geocodebr/issues/35). 15 | - A função `download_cnefe()` agora aceita o argumento `tabela` para baixar tabelas específicas. 16 | 17 | ## Correção de bugs ( Bug fixes) 18 | 19 | - Resolvido bug que decaracterizava colunas de classe `integer64` na tabela de input de endereços. [Encerra issue #40](https://github.com/ipeaGIT/geocodebr/issues/40). 20 | 21 | 22 | ## Notas (Minor changes) 23 | 24 | - Ajuste na solução de casos de empate mais refinada e agora detalhada na documentação da função `geocode()`. [Encerra issue #37](https://github.com/ipeaGIT/geocodebr/issues/37). O método adotado na solução de empates agora fica transparente na documentação da função `geocode()`. 25 | - Nova vignette sobre a função `geocode_reverso()` 26 | - Vignette sobre *Get Started* e da função `geocode()` reorganizadas 27 | 28 | 29 | -------------------------------------------------------------------------------- /geocodebr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | citHeader("Para citar o pacote geocodebr em publicações, use:") 2 | 3 | bibentry( 4 | bibtype = "Manual", 5 | author = c( person("Rafael H. M. Pereira"), 6 | person("Daniel Herszenhut")), 7 | title = "geocodebr: Geolocalização de Endereços Brasileiros", 8 | year = 2025, 9 | version = "v0.1.0" 10 | ) 11 | -------------------------------------------------------------------------------- /inst/extdata/large_sample.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/inst/extdata/large_sample.parquet -------------------------------------------------------------------------------- /inst/extdata/munis_bbox.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/inst/extdata/munis_bbox.rds -------------------------------------------------------------------------------- /inst/extdata/pontos.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/inst/extdata/pontos.rds -------------------------------------------------------------------------------- /inst/extdata/small_sample.csv: -------------------------------------------------------------------------------- 1 | id,nm_logradouro,Numero,Cep,Bairro,nm_municipio,code_muni,nm_uf 2 | 1,Rua Maria Lucia Pacifico,17,26042-730,Santa Rita,Nova Iguacu,3303500,RJ 3 | 2,Rua Leopoldina Tome,46,25030-050,Centenario,Duque de Caxias,3301702,RJ 4 | 3,Rua Dona Judite,0,23915-700,Caputera II,Angra dos Reis,3300100,RJ 5 | 4,Rua Alexandre Amaral,0,23098-120,Santissimo,Rio de Janeiro,3304557,RJ 6 | 5,Avenida E,300,23860-000,Praia Grande,Mangaratiba,3302601,RJ 7 | 6,Rua Princesa Isabel,263,"",Estacao Experimental,Rio Branco,1200401,AC 8 | 7,Caminho sem denominaca,2530,69980-000,Miritizal,Cruzeiro do Sul,1200203,AC 9 | 8,Rua do Limão,268,"","",Rio Branco,1200401,AC 10 | 9,Rua Geraldo Mesquita,0,69918-202,Nova Estacao,Rio Branco,1200401,AC 11 | 10,Avenida Castelo Branco,3874,69925-000,Democracia,Senador Guiomard,1200450,AC 12 | 11,Rua Lucio Marinho Crus,91,57180-000,Centro,Barra de Sao Miguel,2501708,AL 13 | 12,Conjunto Gislene Mateus,12,57160-000,Taperagua,Marechal Deodoro,2704708,AL 14 | 13,Rua Maria Lucia Pacifico,21,26042-730,"",Nova iguacu,3303500,RJ 15 | 14,Rua Princesa Isabel,262,"",Estacao Experimental,Rio Branco,1200401,AC 16 | 15,Rua Francisco de Holanda,9,57073-735,Cidade Universitaria,Maceio,2704302,AL 17 | 16,Rua Maria Lucia Pacifico,20,26042-730,"",Nova iguacu,3303500,RJ 18 | 17,Rua Lucio Marinho Crus,91,"","",Barra de Sao Miguel,2501708,AL 19 | 18,"",,"","",Rio Branco,1200401,Acre 20 | 19,Rua Rui Barbosa,109,"","",Rio Branco,1200401,Acre 21 | 20,Rua Rui Barbosa,,"","",Rio Branco,1200401,Acre 22 | 21,"",,"",Copacabana,Rio de Janeiro,3304557,Rio de Janeiro 23 | 22,"",,22280-005,Botafogo,Rio de Janeiro,3304557,RJ 24 | 23,"",,22280-005,"",Rio de Janeiro,3304557,RJ 25 | 24,Rua Leopoldina Tome,,25030-050,Centenario,Duque de Caxias,3301702,RJ 26 | 25,Rua Leopoldina Tome,46,25030-050,"",Duque de Caxias,3301702,RJ 27 | 26,Conjunto Gislene Mateus,,57160-000,"",Marechal Deodoro,2704708,Alagoas 28 | 27,Rua Maria Lucia Pacifico,,"",Santa rita,Nova Iguacu,3303500,RJ 29 | -------------------------------------------------------------------------------- /inst/extdata/states_bbox.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/inst/extdata/states_bbox.rds -------------------------------------------------------------------------------- /man/add_precision_col.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{add_precision_col} 4 | \alias{add_precision_col} 5 | \title{Add a column with info of geocode match_type} 6 | \usage{ 7 | add_precision_col(con, update_tb = NULL) 8 | } 9 | \arguments{ 10 | \item{con}{A db connection} 11 | 12 | \item{update_tb}{String. Name of a table to be updated in con} 13 | } 14 | \value{ 15 | Adds a new column to a table in con 16 | } 17 | \description{ 18 | Add a column with info of geocode match_type 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/arrow_open_dataset.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{arrow_open_dataset} 4 | \alias{arrow_open_dataset} 5 | \title{Safely use arrow to open a Parquet file} 6 | \usage{ 7 | arrow_open_dataset(filename) 8 | } 9 | \arguments{ 10 | \item{filename}{A local Parquet file} 11 | } 12 | \value{ 13 | An \code{arrow::Dataset} 14 | } 15 | \description{ 16 | This function handles some failure modes, including if the Parquet file is 17 | corrupted. 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /man/busca_por_cep.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/busca_por_cep.R 3 | \name{busca_por_cep} 4 | \alias{busca_por_cep} 5 | \title{Busca por CEP} 6 | \usage{ 7 | busca_por_cep(cep, resultado_sf = FALSE, verboso = TRUE, cache = TRUE) 8 | } 9 | \arguments{ 10 | \item{cep}{Vetor. Um CEP ou um vetor de CEPs com 8 dígitos.} 11 | 12 | \item{resultado_sf}{Lógico. Indica se o resultado deve ser um objeto espacial 13 | da classe \code{sf}. Por padrão, é \code{FALSE}, e o resultado é um \code{data.frame}.} 14 | 15 | \item{verboso}{Um valor lógico. Indica se barras de progresso e mensagens 16 | devem ser exibidas durante o download dos dados do CNEFE e a geocodificação 17 | dos endereços. O padrão é \code{TRUE}.} 18 | 19 | \item{cache}{Um valor lógico. Indica se os dados do CNEFE devem ser salvos ou 20 | lidos do cache, reduzindo o tempo de processamento em chamadas futuras. O 21 | padrão é \code{TRUE}. Quando \code{FALSE}, os dados do CNEFE são baixados para um 22 | diretório temporário.} 23 | } 24 | \value{ 25 | Retorna um \code{data.frame} com os CEPs de input e os endereços presentes 26 | naquele CEP com suas coordenadas geográficas de latitude (\code{lat}) e 27 | longitude (\code{lon}). Alternativamente, o resultado pode ser um objeto \code{sf}. 28 | } 29 | \description{ 30 | Busca endereços e suas coordenadas geográficas a partir de um CEP. As 31 | coordenadas de output utilizam o sistema de coordenadas geográficas SIRGAS 32 | 2000, EPSG 4674. 33 | } 34 | \examples{ 35 | \dontshow{if (identical(tolower(Sys.getenv("NOT_CRAN")), "true")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 36 | library(geocodebr) 37 | 38 | # amostra de CEPs 39 | ceps <- c("70390-025", "20071-001", "99999-999") 40 | 41 | df <- geocodebr::busca_por_cep( 42 | cep = ceps, 43 | verboso = FALSE 44 | ) 45 | 46 | df 47 | \dontshow{\}) # examplesIf} 48 | } 49 | -------------------------------------------------------------------------------- /man/cache_message.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{cache_message} 4 | \alias{cache_message} 5 | \title{Message when caching file} 6 | \usage{ 7 | cache_message( 8 | local_file = parent.frame()$local_file, 9 | cache = parent.frame()$cache 10 | ) 11 | } 12 | \arguments{ 13 | \item{local_file}{The address of a file passed from the download_file function.} 14 | 15 | \item{cache}{Logical. Whether the cached data should be used.} 16 | } 17 | \value{ 18 | A message 19 | } 20 | \description{ 21 | Message when caching file 22 | } 23 | \keyword{internal} 24 | -------------------------------------------------------------------------------- /man/create_index.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{create_index} 4 | \alias{create_index} 5 | \title{create index} 6 | \usage{ 7 | create_index(con, tb, cols, operation, overwrite = TRUE) 8 | } 9 | \description{ 10 | create index 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/definir_campos.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/definir_campos.R 3 | \name{definir_campos} 4 | \alias{definir_campos} 5 | \title{Especifica as colunas que descrevem os campos dos endereços} 6 | \usage{ 7 | definir_campos( 8 | estado, 9 | municipio, 10 | logradouro = NULL, 11 | numero = NULL, 12 | cep = NULL, 13 | localidade = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{estado}{Uma string. O nome da coluna que representa o estado do 18 | endereço. Campo obrigatório. Na tabela de endereços, essa coluna pode 19 | conter os nomes dos estados por extenso, ou a abrevição oficial dos estados 20 | com duas letras, e.g. "AM", "SP", "DF", "RJ".} 21 | 22 | \item{municipio}{Uma string. O nome da coluna que representa o município do 23 | endereço. Campo obrigatório. Na tabela de endereços, essa coluna pode 24 | conter o nome dos municípios, ou o seu código IBGE de 7 dígitos.} 25 | 26 | \item{logradouro}{Uma string. O nome da coluna que representa o \emph{logradouro} 27 | (endereço da rua) do endereço. Pode ser \code{NULL} se o campo não estiver 28 | especificado na tabela de endereços. Na tabela de endereços, essa coluna 29 | deve incluir o \emph{tipo} do lograoduro, indicando se trata-se de uma "Rua" ou 30 | "Avenida" etc, por exemplo "Avenida Presidente Getúlio Vargas". Além disso, 31 | essa coluna \emph{não} deve incluir o \code{numero} do endereço, pois o número deve 32 | ser indicado numa coluna separada.} 33 | 34 | \item{numero}{Uma string. O nome da coluna que representa o número do endereço. 35 | Pode ser \code{NULL} se o campo não estiver especificado na tabela de endereços. 36 | Na tabela de endereços, valores como \code{0} ou caracteres não numerciso como 37 | \code{"S/N"} ou \code{"10a"} são considerados como \code{NA}.} 38 | 39 | \item{cep}{Uma string. O nome da coluna que representa o \emph{CEP} (Código de 40 | Endereçamento Postal) do endereço. Pode ser \code{NULL} se o campo não estiver 41 | especificado na tabela de endereços.} 42 | 43 | \item{localidade}{Uma string. O nome da coluna que representa a localidade 44 | (equivalente ao 'bairro' em áreas urbanas) do endereço. Pode ser \code{NULL} se 45 | esse campo não estiver presente na tabela de endereços.} 46 | } 47 | \value{ 48 | Um vetor de caracteres no qual os nomes são os campos do endereço e os 49 | valores são as colunas que os representam na tabela de endereços. 50 | } 51 | \description{ 52 | Cria um vetor de caracteres especificando as colunas que representam cada 53 | campo do endereço na tabela de endereços. Os campos \code{estado} e \code{municipio} 54 | são obrigatórios. 55 | } 56 | \examples{ 57 | definir_campos( 58 | logradouro = "Nome_logradouro", 59 | numero = "Numero", 60 | cep = "CEP", 61 | localidade = "Bairro", 62 | municipio = "Cidade", 63 | estado = "UF" 64 | ) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /man/definir_pasta_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{definir_pasta_cache} 4 | \alias{definir_pasta_cache} 5 | \title{Define um diretório de cache para o geocodebr} 6 | \usage{ 7 | definir_pasta_cache(path) 8 | } 9 | \arguments{ 10 | \item{path}{Uma string. O caminho para o diretório usado para armazenar os 11 | dados em cache. Se \code{NULL}, o pacote usará um diretório versionado salvo 12 | dentro do diretório retornado por \code{\link[tools:userdir]{tools::R_user_dir()}}.} 13 | } 14 | \value{ 15 | Retorna de forma invisível o caminho do diretório de cache. 16 | } 17 | \description{ 18 | Define um diretório de cache para os dados do geocodebr. Essa configuração 19 | é persistente entre sessões do R. 20 | } 21 | \examples{ 22 | definir_pasta_cache(tempdir()) 23 | 24 | # retoma pasta padrão do pacote 25 | definir_pasta_cache( path = NULL) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /man/deletar_pasta_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{deletar_pasta_cache} 4 | \alias{deletar_pasta_cache} 5 | \title{Deletar pasta de cache do geocodebr} 6 | \usage{ 7 | deletar_pasta_cache() 8 | } 9 | \value{ 10 | Retorna de forma invisível o caminho do diretório de cache. 11 | } 12 | \description{ 13 | Deleta todos arquivos da pasta do cache. 14 | } 15 | \examples{ 16 | \dontshow{if (identical(TRUE, FALSE)) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 17 | deletar_pasta_cache() 18 | \dontshow{\}) # examplesIf} 19 | } 20 | -------------------------------------------------------------------------------- /man/download_cnefe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/download_cnefe.R 3 | \name{download_cnefe} 4 | \alias{download_cnefe} 5 | \title{Faz download dos dados do CNEFE} 6 | \usage{ 7 | download_cnefe(tabela = "todas", verboso = TRUE, cache = TRUE) 8 | } 9 | \arguments{ 10 | \item{tabela}{Nome da tabela para ser baixada. Por padrão, baixa \code{"todas"}.} 11 | 12 | \item{verboso}{Um valor lógico. Indica se barras de progresso e mensagens 13 | devem ser exibidas durante o download dos dados do CNEFE e a geocodificação 14 | dos endereços. O padrão é \code{TRUE}.} 15 | 16 | \item{cache}{Um valor lógico. Indica se os dados do CNEFE devem ser salvos ou 17 | lidos do cache, reduzindo o tempo de processamento em chamadas futuras. O 18 | padrão é \code{TRUE}. Quando \code{FALSE}, os dados do CNEFE são baixados para um 19 | diretório temporário.} 20 | } 21 | \value{ 22 | Retorna o caminho para o diretório onde os dados foram salvos. 23 | } 24 | \description{ 25 | Faz o download de uma versão pre-processada e enriquecida do CNEFE (Cadastro 26 | Nacional de Endereços para Fins Estatísticos) que foi criada para o uso deste 27 | pacote. 28 | } 29 | \examples{ 30 | \dontshow{if (identical(tolower(Sys.getenv("NOT_CRAN")), "true")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 31 | download_cnefe(verboso = FALSE) 32 | \dontshow{\}) # examplesIf} 33 | } 34 | -------------------------------------------------------------------------------- /man/figures/colors.txt: -------------------------------------------------------------------------------- 1 | 3 Chao #fdefd5 2 | 4 Ruas #fddbb8 3 | 9 Ruas #fddbb8 4 | 8 Borda #2b3853 5 | 5 nome e pin #ffd9b6 6 | 7 | 2 sombra prédio destaque #54aa9d 8 | 7 sunny prédio destaque #69beab 9 | + Teto prédios destaque #81cab9 10 | 11 | 6 sunny prédios normais #fab081 12 | Sombra prédios normais #f69a69 13 | + Teto prédios normais #fac196 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /man/figures/ipea_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/man/figures/ipea_logo.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/man/figures/logo.png -------------------------------------------------------------------------------- /man/figures/logo_gpt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipeaGIT/geocodebr/c14b761340500eece5990fa416e7e0fca98c2f09/man/figures/logo_gpt.png -------------------------------------------------------------------------------- /man/geocode_reverso.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geocode_reverso.R 3 | \name{geocode_reverso} 4 | \alias{geocode_reverso} 5 | \title{Geocode reverso de coordenadas espaciais no Brasil} 6 | \usage{ 7 | geocode_reverso( 8 | pontos, 9 | dist_max = 1000, 10 | verboso = TRUE, 11 | cache = TRUE, 12 | n_cores = 1 13 | ) 14 | } 15 | \arguments{ 16 | \item{pontos}{Uma tabela de dados com classe espacial \verb{sf data frame} no 17 | sistema de coordenadas geográficas SIRGAS 2000, EPSG 4674.} 18 | 19 | \item{dist_max}{Integer. Distancia máxima aceitável (em metros) entre os 20 | pontos de input e o endereço Por padrão, a distância é de 1000 metros.} 21 | 22 | \item{verboso}{Um valor lógico. Indica se barras de progresso e mensagens 23 | devem ser exibidas durante o download dos dados do CNEFE e a geocodificação 24 | dos endereços. O padrão é \code{TRUE}.} 25 | 26 | \item{cache}{Um valor lógico. Indica se os dados do CNEFE devem ser salvos ou 27 | lidos do cache, reduzindo o tempo de processamento em chamadas futuras. O 28 | padrão é \code{TRUE}. Quando \code{FALSE}, os dados do CNEFE são baixados para um 29 | diretório temporário.} 30 | 31 | \item{n_cores}{Um número. O número de núcleos de CPU a serem utilizados no 32 | processamento dos dados. O padrão é 1.} 33 | } 34 | \value{ 35 | Retorna o \verb{sf data.frame} de input adicionado das colunas do endereço 36 | encontrado. O output inclui uma coluna "distancia_metros" que indica 37 | a distância entre o ponto de input e o endereço mais próximo 38 | encontrado. 39 | } 40 | \description{ 41 | Geocode reverso de coordenadas geográficas para endereços. A função recebe um 42 | \verb{sf data frame} com pontos e retorna o endereço mais próximo dando uma 43 | distância máxima de busca. 44 | } 45 | \examples{ 46 | \dontshow{if (identical(tolower(Sys.getenv("NOT_CRAN")), "true")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} 47 | library(geocodebr) 48 | library(sf) 49 | 50 | # ler amostra de dados 51 | pontos <- readRDS( 52 | system.file("extdata/pontos.rds", package = "geocodebr") 53 | ) 54 | 55 | pontos <- pontos[1:50,] 56 | 57 | # geocode reverso 58 | df_enderecos <- geocodebr::geocode_reverso( 59 | pontos = pontos, 60 | dist_max = 1000, 61 | verboso = TRUE, 62 | n_cores = 1 63 | ) 64 | \dontshow{\}) # examplesIf} 65 | } 66 | -------------------------------------------------------------------------------- /man/geocodebr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geocodebr-package.R 3 | \docType{package} 4 | \name{geocodebr} 5 | \alias{geocodebr} 6 | \alias{geocodebr-package} 7 | \title{Package: geocodebr: Geolocalização De Endereços Brasileiros (Geocoding 8 | Brazilian Addresses)} 9 | \description{ 10 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 11 | 12 | Método simples e eficiente de geolocalizar dados no Brasil. O pacote é baseado em conjuntos de dados espaciais abertos de endereços brasileiros, utilizando como fonte principal o Cadastro Nacional de Endereços para Fins Estatísticos (CNEFE). O CNEFE é publicado pelo Instituto Brasileiro de Geografia e Estatística (IBGE), órgão oficial de estatísticas e geografia do Brasil. (A simple and efficient method for geolocating data in Brazil. The package is based on open spatial datasets of Brazilian addresses, primarily using the Cadastro Nacional de Endereços para Fins Estatísticos (CNEFE), published by the Instituto Brasileiro de Geografia e Estatística (IBGE), Brazil's official statistics and geography agency.) 13 | } 14 | \seealso{ 15 | Useful links: 16 | \itemize{ 17 | \item \url{https://github.com/ipeaGIT/geocodebr} 18 | \item \url{https://ipeagit.github.io/geocodebr/} 19 | \item Report bugs at \url{https://github.com/ipeaGIT/geocodebr/issues} 20 | } 21 | 22 | } 23 | \author{ 24 | \strong{Maintainer}: Rafael H. M. Pereira \email{rafa.pereira.br@gmail.com} (\href{https://orcid.org/0000-0003-2125-7465}{ORCID}) 25 | 26 | Authors: 27 | \itemize{ 28 | \item Daniel Herszenhut \email{dhersz@gmail.com} (\href{https://orcid.org/0000-0001-8066-1105}{ORCID}) 29 | } 30 | 31 | Other contributors: 32 | \itemize{ 33 | \item Arthur Bazolli \email{baz.arthur@gmail.com} [contributor] 34 | \item Ipea - Instituto de Pesquisa Econômica Aplicada [copyright holder, funder] 35 | } 36 | 37 | } 38 | \keyword{internal} 39 | -------------------------------------------------------------------------------- /man/listar_dados_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{listar_dados_cache} 4 | \alias{listar_dados_cache} 5 | \title{Listar dados em cache} 6 | \usage{ 7 | listar_dados_cache(print_tree = FALSE) 8 | } 9 | \arguments{ 10 | \item{print_tree}{Um valor lógico. Indica se o conteúdo da pasta de cache 11 | deve ser exibido em um formato de árvore. O padrão é \code{FALSE}.} 12 | } 13 | \value{ 14 | O caminho para os arquivos em cache 15 | } 16 | \description{ 17 | Lista os dados salvos localmente na pasta de cache 18 | } 19 | \examples{ 20 | listar_dados_cache() 21 | 22 | listar_dados_cache(print_tree = TRUE) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /man/listar_pasta_cache.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cache.R 3 | \name{listar_pasta_cache} 4 | \alias{listar_pasta_cache} 5 | \title{Obtém a pasta de cache usado no geocodebr} 6 | \usage{ 7 | listar_pasta_cache() 8 | } 9 | \value{ 10 | O caminho da pasta de cache. 11 | } 12 | \description{ 13 | Obtém o caminho da pasta utilizada para armazenar em cache os dados do 14 | geocodebr. Útil para inspecionar a pasta configurada com \code{\link[=definir_pasta_cache]{definir_pasta_cache()}} 15 | em uma sessão anterior do R. Retorna a pasta de cache padrão caso nenhuma 16 | pasta personalizado tenha sido configurada anteriormente. 17 | } 18 | \examples{ 19 | listar_pasta_cache() 20 | 21 | } 22 | -------------------------------------------------------------------------------- /man/roxygen/templates/cache.R: -------------------------------------------------------------------------------- 1 | #' @param cache Um valor lógico. Indica se os dados do CNEFE devem ser salvos ou 2 | #' lidos do cache, reduzindo o tempo de processamento em chamadas futuras. O 3 | #' padrão é `TRUE`. Quando `FALSE`, os dados do CNEFE são baixados para um 4 | #' diretório temporário. 5 | -------------------------------------------------------------------------------- /man/roxygen/templates/empates_section.R: -------------------------------------------------------------------------------- 1 | #' @details Lidando com casos de empate: 2 | #' 3 | #' No processo de geolocalização de dados, é possível que para alguns endereços 4 | #' de input sejam encontrados diferentes coordenadas possíveis (e.g. duas ruas 5 | #' diferentes com o mesmo nome, mas em bairros distintos em uma mesma cidade). 6 | #' Esses casos são trados como empate'. Quando a função `geocode()` recebe o 7 | #' o parâmetro `resolver_empates = TRUE`, os casos de empate são resolvidos 8 | #' automaticamente pela função. A solução destes empates é feita da seguinte 9 | #' maneira: 10 | #' 11 | #' 1) Quando se encontra diferente coordenadas possíveis para um endereço de 12 | #' input, nós assumimos que essas coordendas pertencem provavelmente a endereços 13 | #' diferentes se (a) estas coordenadas estão a mais de 1Km entre si, ou (b) estão 14 | #' associadas a um logradouro 'ambíguo', i.e. que costumam se repetir em muitos 15 | #' bairros (e.g. "RUA A", "RUA QUATRO", "RUA 10", etc). Nestes casos, a solução 16 | #' de desempate é retornar o ponto com maior número de estabelecimentos no CNEFE, 17 | #' valor indicado na coluna `"contagem_cnefe"`. 18 | #' 19 | #' 2) Quando as coordenadas possivelmente associadas a um endereço estão a menos 20 | #' de 1Km entre si e não se trata de um logradouro 'ambíguo', nós assumimos que 21 | #' os pontos pertencem provavelmente ao mesmo logradouro (e.g. diferentes CEPs 22 | #' ao longo de uma mesma rua). Nestes casos, a solução de desempate é retornar 23 | #' um ponto que resulta da média das coordenadas dos pontos possíveis ponderada 24 | #' pelo valor de `"contagem_cnefe"`. Nesse caso, a coluna de output 25 | #' `"endereco_encontrado"` recebe valor do ponto com maior `"contagem_cnefe"`. 26 | #' 27 | -------------------------------------------------------------------------------- /man/roxygen/templates/n_cores.R: -------------------------------------------------------------------------------- 1 | #' @param n_cores Um número. O número de núcleos de CPU a serem utilizados no 2 | #' processamento dos dados. O padrão é 1. 3 | -------------------------------------------------------------------------------- /man/roxygen/templates/precision_section.R: -------------------------------------------------------------------------------- 1 | #' @details Precisão dos resultados: 2 | #' 3 | #' Os resultados do **{geocodebr}** são classificados em seis amplas categorias de `precisao`: 4 | #' 5 | #' 1. "numero" 6 | #' 2. "numero_aproximado" 7 | #' 3. "logradouro" 8 | #' 4. "cep" 9 | #' 5. "localidade" 10 | #' 6. "municipio" 11 | #' 12 | #' Cada nível de precisão pode ser desagregado em tipos de correspondência mais 13 | #' refinados. 14 | #' 15 | #' # Tipos de resultados 16 | #' 17 | #' A coluna `tipo_resultado` fornece informações mais detalhadas sobre como 18 | #' exatamente cada endereço de entrada foi encontrado no CNEFE. Em cada 19 | #' categoria, o **{geocodebr}** calcula a média da latitude e longitude dos 20 | #' endereços incluídos no CNEFE que correspondem ao endereço de entrada, com 21 | #' base em combinações de diferentes campos. No caso mais rigoroso, por exemplo, 22 | #' a função encontra uma correspondência determinística para todos os campos de 23 | #' um dado endereço (`"estado"`, `"municipio"`, `"logradouro"`, `"numero"`, 24 | #' `"cep"`, `"localidade"`). Pense, por exemplo, em um prédio com vários 25 | #' apartamentos que correspondem ao mesmo endereço de rua e número. Nesse caso, 26 | #' as coordenadas dos apartamentos podem diferir ligeiramente, e o 27 | #' **{geocodebr}** calcula a média dessas coordenadas. Em um caso menos rigoroso, 28 | #' no qual apenas os campos (`"estado"`, `"municipio"`, `"logradouro"`, 29 | #' `"localidade"`) são encontrados, o **{geocodebr}** calcula as coordenadas 30 | #' médias de todos os endereços no CNEFE ao longo daquela rua e que se encontram 31 | #' na mesma localidade/bairro. Assim, as coordenadas de resultado tendem a ser o 32 | #' ponto médio do trecho daquela rua que passa dentro daquela localidade/bairro. 33 | #' 34 | #' A coluna `tipo_resultado` fornece informações mais detalhadas sobre os campos de 35 | #' endereço utilizados no cálculo das coordenadas de cada endereço de entrada. Cada 36 | #' categoria é nomeada a partir de um código de quatro caracteres: 37 | #' 38 | #' - o primeiro caracter, sempre `d` ou `p`, determina se a correspondência foi 39 | #' feita de forma determinística (`d`) ou probabilística (`p`); 40 | #' - o segundo faz menção à categoria de `precisao` na qual o resultado foi 41 | #' classificado (`n` para `"numero"`, `a` para `"numero_aproximado"`, `r` para 42 | #' `"logradouro"`, `c` para `"cep"`, `b` para `"localidade"` e `m` para `"municipio"`); 43 | #' - o terceiro e o quarto caracteres designam a classificação de cada categoria 44 | #' dentro de seu grupo - via de regra, quanto menor o número formado por esses 45 | #' caracteres, mais precisa são as coordenadas calculadas. 46 | #' 47 | #' As categorias de `tipo_resultado` são listadas abaixo, junto às categorias de 48 | #' `precisao` a qual elas estão associadas: 49 | #' 50 | #' - precisao `"numero"` 51 | #' - `dn01` - logradouro, numero, cep e localidade 52 | #' - `dn02` - logradouro, numero e cep 53 | #' - `dn03` - logradouro, numero e localidade 54 | #' - `dn04` - logradouro e numero 55 | #' - `pn01` - logradouro, numero, cep e localidade 56 | #' - `pn02` - logradouro, numero e cep 57 | #' - `pn03` - logradouro, numero e localidade 58 | #' - `pn04` - logradouro e numero 59 | #' 60 | #' - precisao `"numero_aproximado"` 61 | #' - `da01` - logradouro, numero, cep e localidade 62 | #' - `da02` - logradouro, numero e cep 63 | #' - `da03` - logradouro, numero e localidade 64 | #' - `da04` - logradouro e numero 65 | #' - `pa01` - logradouro, numero, cep e localidade 66 | #' - `pa02` - logradouro, numero e cep 67 | #' - `pa03` - logradouro, numero e localidade 68 | #' - `pa04` - logradouro e numero 69 | #' 70 | #' - precisao `"logradouro"` (quando o número de entrada está faltando 'S/N') 71 | #' - `dl01` - logradouro, cep e localidade 72 | #' - `dl02` - logradouro e cep 73 | #' - `dl03` - logradouro e localidade 74 | #' - `dl04` - logradouro 75 | #' - `pl01` - logradouro, cep e localidade 76 | #' - `pl02` - logradouro e cep 77 | #' - `pl03` - logradouro e localidade 78 | #' - `pl04` - logradouro 79 | #' 80 | #' - precisao `"cep"` 81 | #' - `dc01` - municipio, cep, localidade 82 | #' - `dc02` - municipio, cep 83 | #' 84 | #' - precisao `"localidade"` 85 | #' - `db01` - municipio, localidade 86 | #' 87 | #' - precisao `"municipio"` 88 | #' - `dm01` - municipio 89 | #' 90 | #' Endereços não encontrados são retornados com latitude, longitude, precisão e 91 | #' tipo de resultado `NA`. 92 | #' 93 | #' # Busca probabilitisca 94 | #' 95 | #' Os tipos de resultado com busca probabilitisca usam como base o algoritmo de 96 | #' semelhança de Jaro para comparar as strings de 'logradouro' dos dados de 97 | #' input e da base de endereços do geocodebr. O pacote considera como match o 98 | #' logradouro da base de endereços que apresenta a maior semelhança de 99 | #' Jaro condicionado a uma semelhança mínima de `0.85`, e desde que também haja 100 | #' match determinístico em ao menos um dos campos "cep" e "localidade". 101 | #' 102 | -------------------------------------------------------------------------------- /man/roxygen/templates/verboso.R: -------------------------------------------------------------------------------- 1 | #' @param verboso Um valor lógico. Indica se barras de progresso e mensagens 2 | #' devem ser exibidas durante o download dos dados do CNEFE e a geocodificação 3 | #' dos endereços. O padrão é `TRUE`. 4 | -------------------------------------------------------------------------------- /man/update_input_db.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{update_input_db} 4 | \alias{update_input_db} 5 | \title{Update input_padrao_db to remove observations previously matched} 6 | \usage{ 7 | update_input_db(con, update_tb = "input_padrao_db", reference_tb) 8 | } 9 | \arguments{ 10 | \item{con}{A db connection} 11 | 12 | \item{update_tb}{String. Name of a table to be updated in con} 13 | 14 | \item{reference_tb}{A table written in con used as reference} 15 | } 16 | \value{ 17 | Drops observations from input_padrao_db 18 | } 19 | \description{ 20 | Update input_padrao_db to remove observations previously matched 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /pkgdown/_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://ipeagit.github.io/geocodebr/ 2 | 3 | template: 4 | bootstrap: 5 5 | light-switch: true 6 | 7 | development: 8 | mode: auto 9 | 10 | reference: 11 | - title: "Geolocalização" 12 | - contents: 13 | - geocode 14 | - geocode_reverso 15 | - busca_por_cep 16 | - title: "Gestão de dados em cache" 17 | - contents: 18 | - listar_pasta_cache 19 | - listar_dados_cache 20 | - definir_pasta_cache 21 | - deletar_pasta_cache 22 | - title: "Funções auxiliares" 23 | - contents: 24 | - definir_campos 25 | - download_cnefe 26 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | #ifdef RCPP_USE_GLOBAL_ROSTREAM 9 | Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); 10 | Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); 11 | #endif 12 | 13 | // rcpp_distance_haversine 14 | Rcpp::NumericVector rcpp_distance_haversine(Rcpp::NumericVector latFrom, Rcpp::NumericVector lonFrom, Rcpp::NumericVector latTo, Rcpp::NumericVector lonTo, double tolerance); 15 | RcppExport SEXP _geocodebr_rcpp_distance_haversine(SEXP latFromSEXP, SEXP lonFromSEXP, SEXP latToSEXP, SEXP lonToSEXP, SEXP toleranceSEXP) { 16 | BEGIN_RCPP 17 | Rcpp::RObject rcpp_result_gen; 18 | Rcpp::RNGScope rcpp_rngScope_gen; 19 | Rcpp::traits::input_parameter< Rcpp::NumericVector >::type latFrom(latFromSEXP); 20 | Rcpp::traits::input_parameter< Rcpp::NumericVector >::type lonFrom(lonFromSEXP); 21 | Rcpp::traits::input_parameter< Rcpp::NumericVector >::type latTo(latToSEXP); 22 | Rcpp::traits::input_parameter< Rcpp::NumericVector >::type lonTo(lonToSEXP); 23 | Rcpp::traits::input_parameter< double >::type tolerance(toleranceSEXP); 24 | rcpp_result_gen = Rcpp::wrap(rcpp_distance_haversine(latFrom, lonFrom, latTo, lonTo, tolerance)); 25 | return rcpp_result_gen; 26 | END_RCPP 27 | } 28 | 29 | static const R_CallMethodDef CallEntries[] = { 30 | {"_geocodebr_rcpp_distance_haversine", (DL_FUNC) &_geocodebr_rcpp_distance_haversine, 5}, 31 | {NULL, NULL, 0} 32 | }; 33 | 34 | RcppExport void R_init_geocodebr(DllInfo *dll) { 35 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 36 | R_useDynamicSymbols(dll, FALSE); 37 | } 38 | -------------------------------------------------------------------------------- /src/distance_calcs.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | using namespace Rcpp; 4 | 5 | double inverseHaversine(double d){ 6 | return 2 * atan2(sqrt(d), sqrt(1 - d)) * 6378137.0; 7 | } 8 | 9 | double distanceHaversine(double latf, double lonf, double latt, double lont, 10 | double tolerance){ 11 | double d; 12 | double dlat = latt - latf; 13 | double dlon = lont - lonf; 14 | 15 | d = (sin(dlat * 0.5) * sin(dlat * 0.5)) + (cos(latf) * cos(latt)) * (sin(dlon * 0.5) * sin(dlon * 0.5)); 16 | if(d > 1 && d <= tolerance){ 17 | d = 1; 18 | } 19 | return inverseHaversine(d); 20 | } 21 | 22 | double toRadians(double deg){ 23 | return deg * 0.01745329251; // PI / 180; 24 | } 25 | 26 | // [[Rcpp::export]] 27 | Rcpp::NumericVector rcpp_distance_haversine(Rcpp::NumericVector latFrom, Rcpp::NumericVector lonFrom, 28 | Rcpp::NumericVector latTo, Rcpp::NumericVector lonTo, 29 | double tolerance) { 30 | 31 | int n = latFrom.size(); 32 | NumericVector distance(n); 33 | 34 | double latf; 35 | double latt; 36 | double lonf; 37 | double lont; 38 | double dist = 0; 39 | 40 | distance[0] = 0; 41 | 42 | for(int i = 0; i + 1 < n; i++){ 43 | 44 | latf = toRadians(latFrom[i]); 45 | lonf = toRadians(lonFrom[i]); 46 | latt = toRadians(latTo[i]); 47 | lont = toRadians(lonTo[i]); 48 | dist = distanceHaversine(latf, lonf, latt, lont, tolerance); 49 | 50 | // Cast the computed double distance to an integer 51 | distance[i + 1] = static_cast(dist); 52 | } 53 | return distance; 54 | } 55 | -------------------------------------------------------------------------------- /tests/tests_rafa/arrow_distinct.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(arrow) 3 | library(geocodebr) 4 | 5 | head(cad) 6 | 7 | cad$id <- 1:nrow(cad) 8 | 9 | fields_cad <- geocodebr::definir_campos( 10 | logradouro = 'logradouro', 11 | numero = 'numero', 12 | cep = 'cep', 13 | localidade = 'bairro', 14 | municipio = 'code_muni', 15 | estado = 'abbrev_state' 16 | ) 17 | 18 | input_padrao <- enderecobr::padronizar_enderecos( 19 | cad, 20 | campos_do_endereco = enderecobr::correspondencia_campos( 21 | logradouro = fields_cad[["logradouro"]], 22 | numero = fields_cad[["numero"]], 23 | cep = fields_cad[["cep"]], 24 | bairro = fields_cad[["localidade"]], 25 | municipio = fields_cad[["municipio"]], 26 | estado = fields_cad[["estado"]] 27 | ), 28 | formato_estados = "sigla", 29 | formato_numeros = 'integer' 30 | ) 31 | 32 | names(input_padrao) 33 | 34 | arrow::write_parquet(input_padrao, 'input_padrao.parquet') 35 | 36 | # unique_logradouros <- arrow::open_dataset('input_padrao.parquet') |> 37 | # dplyr::select(dplyr::all_of(key_cols)) |> # unique_cols 38 | # dplyr::distinct() |> 39 | # dplyr::compute() 40 | 41 | 42 | input_padrao <- arrow::read_parquet('input_padrao.parquet') 43 | 44 | input_states <- unique(input_padrao$estado_padr) 45 | input_municipio <- unique(input_padrao$municipio_padr) 46 | 47 | 48 | 49 | path_to_parquet <- geocodebr::listar_dados_cache()[7] 50 | 51 | key_cols <- c("estado", "municipio", "logradouro", "numero", "cep" ) 52 | 53 | 54 | filtered_cnefe2 <- arrow::open_dataset(path_to_parquet) |> 55 | dplyr::filter(estado %in% input_states) |> 56 | dplyr::filter(municipio %in% input_municipio) |> 57 | dplyr::compute() 58 | 59 | 60 | # unique_logradouros <- filtered_cnefe2 |> 61 | unique_logradouros <- arrow::open_dataset(path_to_parquet) |> 62 | dplyr::select(dplyr::all_of(key_cols)) |> 63 | dplyr::distinct() |> 64 | dplyr::compute() 65 | -------------------------------------------------------------------------------- /tests/tests_rafa/benchmark_LIKE.R: -------------------------------------------------------------------------------- 1 | #' instalar extensoes do duckdb 2 | #' - spatial - acho q nao vale a pena por agora 3 | #' 4 | #' #' (non-deterministic search) 5 | #' - fts - Adds support for Full-Text Search Indexes / "https://medium.com/@havus.it/enhancing-database-search-full-text-search-fts-in-mysql-1bb548f4b9ba" 6 | #' 7 | #' 8 | #' 9 | #' adicionar dados de POI da Meta /overture 10 | #' adicionar dados de enderecos Meta /overture 11 | #' # NEXT STEPS 12 | #' - (ok) interpolar numeros na mesma rua 13 | #' - (next) join probabilistico com fts_main_documents.match_bm25 14 | #' - (next) calcular nivel de erro na agregacao do cnefe 15 | #' - optimize disk and parallel operations in duckdb 16 | #' - casos de rodovias 17 | #' - interpolar numeros separando impares e pares 18 | #' - CASES NOT FOUND ? AND THEIR EFFECT ON THE PROGRESS BAR 19 | 20 | 21 | 22 | #' take-away 23 | #' 1) incluir LIKE no campo d elogradouro melhor MUITO performance, encontrando 24 | #' muito mais casos em cases de match 1, 2, 3 e 4 25 | #' o melhor mesmo seria usar fts 26 | #' 2) isso tem pequeno efeito de diminuir performance do dani, e 0 efeito no rafa 27 | #' 28 | #' 3) no rafa aida tem um residudo de que alguns casos em que as coordenadas nao 29 | #' foram agregadas, entao tem alguns 'id's que se repetem no output 30 | #' - a razao eh pq a agregacao sai diferente para logradouros diferentes mas 31 | #' com o mesmo padrao LIKE. Ex. "RUA AVELINO CAVALCANTE" e "TRAVESSA AVELINO CAVALCANTE" 32 | #' 33 | #' exemplos 34 | #' id == 1637 caso de diferentes ruas no mesmo condominio 35 | #' "RUA DOIS VILA RICA" e "RUA XXVI QUADRA E VILA RICA" 36 | #' id == 1339 (esse se resolve pq sao bairros diferentes) 37 | 38 | 39 | devtools::load_all('.') 40 | library(dplyr) 41 | # library(geocodebr) 42 | # library(enderecobr) 43 | # library(data.table) 44 | # library(arrow) 45 | # library(duckdb) 46 | 47 | 48 | # open input data 49 | data_path <- system.file("extdata/large_sample.parquet", package = "geocodebr") 50 | input_df <- arrow::read_parquet(data_path) 51 | 52 | 53 | # enderecos = input_df 54 | # n_cores = 7 55 | # ncores <- 7 56 | # verboso = T 57 | # cache = TRUE 58 | # resultado_completo = T 59 | # resultado_sf = F 60 | # campos_endereco <- geocodebr::definir_campos( 61 | # logradouro = 'logradouro', 62 | # numero = 'numero', 63 | # cep = 'cep', 64 | # localidade = 'bairro', 65 | # municipio = 'municipio', 66 | # estado = 'uf') 67 | # resolver_empates = F 68 | 69 | 70 | # benchmark different approaches ------------------------------------------------------------------ 71 | ncores <- 7 72 | 73 | # input_df <- input_df[c(1,84, 284), ] 74 | # input_df <- input_df[id %in% dfgeo$id[dfgeo$tipo_resultado=='ei03'] ] 75 | 76 | 77 | campos <- geocodebr::definir_campos( 78 | logradouro = 'logradouro', 79 | numero = 'numero', 80 | cep = 'cep', 81 | localidade = 'bairro', 82 | municipio = 'municipio', 83 | estado = 'uf' 84 | ) 85 | 86 | # test probabilistic 87 | # input_df <- input_df[c(7, 32, 34, 71, 173, 1348)] # pn02 pi02 pn03 pi03 pr01 pr02 88 | # temp_df <- filter(input_df,id %in% c(1371) ) 89 | 90 | 91 | bench::mark( iterations = 1, 92 | temp_dfgeo2 <- geocodebr::geocode( 93 | enderecos = input_df, 94 | campos_endereco = campos, 95 | n_cores = ncores, 96 | resultado_completo = T, 97 | verboso = T, 98 | resultado_sf = F, 99 | resolver_empates = F 100 | ) 101 | ) 102 | # sequencia de matches 103 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory time gc 104 | # 2nd best 25.7s 25.7s 0.0389 67.1MB 0.350 1 9 25.7s ;;787 empates 105 | # ideal 23.8s 23.8s 0.0420 38.1MB 0.378 1 9 23.8s ;;724 106 | 107 | 108 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory 109 | # 110 | # current 1.01m 1.01m 0.0165 81.3MB 0.182 1 11 1.01m
111 | # ender_arrw 59.6s 59.6s 0.0168 81.2MB 0.201 1 12 59.6s
112 | # 40.2s 40.2s 0.0249 83MB 0.323 1 13 40.2s
113 | # 30.3s 30.3s 0.0330 71.8MB 0.363 1 11 30.3s
715 empates 114 | # 26.2s 26.2s 0.0382 70.3MB 0.343 1 9 26.2s
722 115 | # 24.5s 24.5s 0.0409 70.3MB 0.368 1 9 24.5s
722 116 | # 24.1s 24.1s 0.0414 63.8MB 0.373 1 9 24.1s
704 117 | # prob befo det 24.4s 24.4s 0.0411 39.3MB 0.411 1 10 24.4s
723 118 | # prob after det 24.9s 24.9s 0.0401 67MB 0.401 1 10 24.9s
810 119 | # match prob 120 | # filter 25.7s 25.7s 0.0389 63.8MB 0.350 1 9 25.7s
121 | # distinct 27s 27s 0.0371 91.1MB 0.334 1 9 27s
122 | 123 | # 20K prob numero pn 124 | # atual: 46.69s / 706 empates 125 | # old: 34.91s / 783 126 | # 20250318 40.21s / 698 empates 127 | 128 | # 1.56m com arrow distinct 129 | # 1.47m com parquet no pn 130 | # 1.90m com parquet no pn e pa 131 | # 1.6 com write arrwo table >>>>>>>>>>>> implementar com certeza 132 | # 1.3m e arrow distinc 133 | # 1.32m e arrow distinc e outuop_arrw 134 | # 1.06m e arrow distinc e outuop_arrw e sendQueryArrow (na tomada) 135 | # 1.06m isso + tudo com sendQueryArrow (na tomada) 136 | 137 | 138 | 139 | empates <- subset(dfgeo, empate==T) 140 | a <- table(empates$id) |> as.data.frame() 141 | table(empates$tipo_resultado) 142 | 143 | case <- subset(empates, id ==9477) 144 | case <- subset(empates, endereco_encontrado %like% 'BLOCO') 145 | mapview::mapview(case) 146 | 147 | 148 | round(table(dfgeo$precisao) / nrow(dfgeo) *100, 1) 149 | round(table(dfgeo2$precisao) / nrow(dfgeo2) *100, 1) 150 | 151 | # tempo: 152 | # com 32.75s 855 empates 153 | # sem 13.7s 655 empates 154 | 155 | # precisao: 156 | # cep localidade logradouro municipio numero numero_aproximado 157 | # com 2.5 0.3 14.8 0.6 45.8 36.0 158 | # sem 31.4 2.3 7.2 0.6 33.3 26.2 159 | 160 | temp <- left_join( select(dfgeo, id, tipo_resultado), select(dfgeo2, id, tipo_resultado), by = 'id' ) 161 | t <- table(temp$tipo_resultado.x, temp$tipo_resultado.y) |> as.data.frame() 162 | t <- filter(t, Freq>0) 163 | View(t) 164 | 165 | 166 | 167 | 168 | 169 | # 20K FRESH 170 | # Unit: seconds 171 | # expr min lq mean median uq max neval 172 | # rafa_drop 10.10379 10.25397 10.35726 10.39609 10.41682 10.61564 5 173 | # rafa_drop_db 10.33163 10.41716 10.53599 10.57100 10.67138 10.68880 5 174 | # rafa_keep 11.12560 11.17642 11.40483 11.30231 11.56706 11.85277 5 175 | # rafa_keep_db 10.99093 11.18329 11.26758 11.18585 11.40816 11.56966 5 176 | # dani_df 10.99375 11.04987 11.47305 11.16092 11.43530 12.72541 5 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | # 20 K 185 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory time 186 | # 187 | # 1 rafa_drop 10.4s 10.5s 0.0952 53MB 0.171 5 9 52.5s 188 | # 2 rafa_drop_db 10.6s 10.7s 0.0935 27.5MB 0.168 5 9 53.46s 189 | # 3 rafa_keep 11.5s 11.7s 0.0859 27.7MB 0.155 5 9 58.23s 190 | # 4 rafa_keep_db 11.3s 11.6s 0.0867 27.6MB 0.139 5 8 57.69s 191 | # 5 dani_df 11.5s 11.9s 0.0823 24.9MB 0.148 5 9 1.01m 192 | 193 | 194 | 195 | 196 | 197 | devtools::load_all('.') 198 | library(tictoc) 199 | library(dplyr) 200 | library(data.table) 201 | library(ipeadatalake) 202 | library(mapview) 203 | library(sfheaders) 204 | library(sf) 205 | options(scipen = 999) 206 | mapview::mapviewOptions(platform = 'leafgl') 207 | set.seed(42) 208 | 209 | 210 | 211 | 212 | 213 | geocodebr::get_cache_dir() |> 214 | geocodebr:::arrow_open_dataset() |> 215 | filter(estado=="PR") |> 216 | filter(municipio == "CURITIBA") |> 217 | dplyr::compute() |> 218 | filter(logradouro_sem_numero %like% "DESEMBARGADOR HUGO SIMAS") |> 219 | dplyr::collect() 220 | 221 | 222 | cnf <- ipeadatalake::read_cnefe(year = 2022) |> 223 | # filter(code_state=="41") |> 224 | dplyr::filter(code_muni == 4106902) |> 225 | dplyr::collect() 226 | 227 | 228 | d <- cnf |> 229 | filter(nom_seglogr %like% "HUGO SIMAS") 230 | 231 | 'DESEMBARGADOR' 232 | 233 | 234 | 235 | 236 | 237 | 238 | # small sample data ------------------------------------------------------------------ 239 | devtools::load_all('.') 240 | library(dplyr) 241 | 242 | # open input data 243 | data_path <- system.file("extdata/small_sample.csv", package = "geocodebr") 244 | input_df <- read.csv(data_path) 245 | 246 | campos <- geocodebr::definir_campos( 247 | logradouro = "nm_logradouro", 248 | numero = "Numero", 249 | cep = "Cep", 250 | localidade = "Bairro", 251 | municipio = "nm_municipio", 252 | estado = "nm_uf" 253 | ) 254 | 255 | # enderecos = input_df 256 | # campos_endereco = campos 257 | # n_cores = 7 258 | # verboso = T 259 | # cache=T 260 | # resultado_completo=T 261 | # resolver_empates = FALSE 262 | # resultado_sf = FALSE 263 | 264 | dfgeo <- geocodebr::geocode( 265 | enderecos = input_df, 266 | campos_endereco = campos, 267 | n_cores = 7, 268 | resultado_completo = T, 269 | resolver_empates = T, 270 | verboso = T 271 | ) 272 | 273 | 274 | identical(df_rafaF$id, input_df$id) 275 | 276 | 277 | table(df_rafa_loop$precision) / nrow(df_rafa_loop)*100 278 | 279 | 280 | unique(df_rafa$match_type) |> length() 281 | 282 | table(df_rafa$match_type) 283 | 284 | 285 | -------------------------------------------------------------------------------- /tests/tests_rafa/calculate_precision.R: -------------------------------------------------------------------------------- 1 | devtools::load_all(".") 2 | library(data.table) 3 | library(dplyr) 4 | library(sf) 5 | library(sfheaders) 6 | library(arrow) 7 | library(mapview) 8 | sf::sf_use_s2(FALSE) 9 | mapview::mapviewOptions(platform = 'leafgl') 10 | 11 | tudo <- geocodebr::listar_dados_cache() 12 | tudo <- tudo[7] 13 | 14 | dt <- arrow::open_dataset( tudo ) |> 15 | dplyr::filter(estado == 'RJ') |> 16 | dplyr::filter(municipio == "RIO DE JANEIRO") |> 17 | dplyr::filter(cep %in% c( "22440-033")) |> # 22440-035 18 | # dplyr::filter(cep %in% c("22620-110", "20521-470")) |> 19 | # dplyr::filter(localidade %in% c("LEBLON")) |> 20 | dplyr::collect() 21 | 22 | 23 | # dt <- arrow::open_dataset( tudo ) |> 24 | # dplyr::filter(estado =='DF') |> 25 | # dplyr::filter(cep =='70355-030') |> 26 | # dplyr::collect() 27 | # 28 | 29 | dt_sf <- sfheaders::sf_point( 30 | obj = dt, 31 | x = 'lon', 32 | y = 'lat', 33 | keep = TRUE 34 | ) 35 | 36 | sf::st_crs(dt_sf) <- 4674 37 | 38 | mapview::mapview(dt_sf, zcol='cep') 39 | 40 | 41 | # calculate precision as the area in m2 ---------------------------------------- 42 | 43 | ## ellipsoid ---------------------------------------------- 44 | 45 | get_ellipsoid_area <- function(lat_vec, lon_vec){ 46 | 47 | # lat_vec <- dt$lat 48 | # lon_vec <- dt$lon 49 | 50 | range_lon <- max(lon_vec) - min(lon_vec) 51 | range_lat <- max(lat_vec) - min(lat_vec) 52 | 53 | range_lon <- range_lon / 2 54 | range_lat <- range_lat / 2 55 | 56 | # convert to meters 57 | lon_meters <- 111320 * range_lon * cos(mean(lat_vec)) 58 | lat_meters <- 111320 * range_lat 59 | 60 | area <- pi * lon_meters * lat_meters 61 | abs(area) 62 | } 63 | 64 | 65 | ## concave of points ---------------------------------------------- 66 | 67 | get_concave_area <- function(lat_vec, lon_vec){ 68 | 69 | # lat_vec <- dt$lat 70 | # lon_vec <- dt$lon 71 | 72 | # points buffer of 5.84 meters based on the best gps precision of cnefe 73 | # https://biblioteca.ibge.gov.br/visualizacao/livros/liv102063.pdf 74 | radious_meters <- 5.84 75 | radious_degree <- radious_meters/111320 76 | 77 | n_points <- length(lon_vec) 78 | single_point_area <- pi * radious_meters^2 79 | 80 | if ( n_points == 1) { 81 | return(single_point_area) 82 | } 83 | 84 | points <- geos::geos_make_point( 85 | x = lon_vec, 86 | y = lat_vec, 87 | crs = 4674 88 | ) 89 | temp_sf <- sf::st_as_sf(points) 90 | 91 | 92 | buff <- sf::st_buffer(x = temp_sf, dist = radious_degree) 93 | buff <- sf::st_union(buff) 94 | # plot(buff) 95 | 96 | # back to points 97 | temp_points <- sfheaders::sfc_cast(buff, "POINT") 98 | # plot(temp_points) 99 | 100 | poly <- concaveman::concaveman(points = sf::st_as_sf(temp_points), concavity = 2) 101 | # plot(poly) 102 | 103 | # mapview(poly) + temp_sf 104 | 105 | area_m2 <- sf::st_area(poly) 106 | area_m2 <- as.numeric(area_m2) 107 | 108 | # mapview::mapview(poly) + temp_sf 109 | 110 | return(area_m2) 111 | } 112 | 113 | 114 | 115 | ## concave of geos ---------------------------------------------- 116 | 117 | get_concave_area_geos <- function(lat_vec, lon_vec){ 118 | 119 | # lat_vec <- dt$lat 120 | # lon_vec <- dt$lon 121 | 122 | # points buffer of 5.84 meters based on the best gps precision of cnefe 123 | # https://biblioteca.ibge.gov.br/visualizacao/livros/liv102063.pdf 124 | radious_meters <- 5.84 125 | radious_degree <- radious_meters/111320 126 | 127 | n_points <- length(lon_vec) 128 | single_point_area <- pi * radious_meters^2 129 | 130 | if ( n_points == 1) { 131 | return(single_point_area) 132 | } 133 | 134 | points <- geos::geos_make_point( 135 | x = lon_vec, 136 | y = lat_vec, 137 | crs = 4674 138 | ) 139 | 140 | # # para agregacoes com muitos enderecos, pegar amostra aletaroria de 20% 141 | # if ( n_points > 200) { 142 | # sample_rows <- sample(1:length(points), size = round(0.2 * length(points))) 143 | # points <- points[sample_rows] 144 | # } 145 | 146 | buff <- geos::geos_buffer( 147 | geom = points, 148 | distance = radious_degree 149 | ) 150 | 151 | temp_points <- geos::geos_unique_points(buff) 152 | temp_points <- geos::geos_make_collection(temp_points) 153 | poly <- geos::geos_concave_hull(temp_points, ratio = .5) 154 | poly <- st_as_sf(poly) 155 | # plot(poly) 156 | 157 | # mapview(poly) + temp_sf 158 | 159 | # get area 160 | area_m2 <- sf::st_area(poly) 161 | area_m2 <- as.numeric(area_m2) 162 | return(area_m2) 163 | } 164 | 165 | 166 | # mapview(temp_sf) + poly 167 | 168 | # teste ------------------------------------------------------------------- 169 | 170 | bench::system_time({ 171 | result <- dt[, .(lat = mean(lat), 172 | lon = mean(lon), 173 | area_m2_concave = get_concave_area(lat, lon), 174 | area_m2_concave_geos = get_concave_area_geos(lat, lon) 175 | #, area_m2_ellipsoid = get_ellipsoid_area(lat, lon) 176 | ), by = cep] 177 | }) 178 | View(result) 179 | 180 | data.table::setDT(result) 181 | result[, diff := area_m2_concave - area_m2_concave_geos] 182 | summary(result$diff) 183 | 184 | fconcave <- function(dt){ 185 | dt[, .(lat = mean(lat), 186 | lon = mean(lon), 187 | area_m2_concave = get_concave_area(lat, lon) 188 | ), by = cep][] 189 | } 190 | 191 | fconcave_geos <- function(dt){ 192 | dt[, .(lat = mean(lat), 193 | lon = mean(lon), 194 | area_m2_concave_geos = get_concave_area_geos(lat, lon) 195 | ), by = cep][] 196 | } 197 | 198 | bench::mark( 199 | fconcave(dt), 200 | fconcave_geos(dt), 201 | iterations = 10, 202 | check = FALSE 203 | ) 204 | 205 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result 206 | # 1 fconcave(dt) 2.55s 2.55s 0.392 8.44MB 0.392 1 1 2.55s 207 | # 2 fconcave_geo… 2.68s 2.68s 0.373 4.53MB 0.373 1 1 2.68s 208 | 209 | library(collapse) 210 | 211 | bench::mark( 212 | fconcave(dt), 213 | fconcave_geos(dt), 214 | 215 | dt |> 216 | fgroup_by(cep) |> 217 | fsummarise( 218 | lat = fmean(lat), 219 | lon = fmean(lon), 220 | area_m2_concave = get_concave_area(lat, lon) 221 | ), 222 | iterations = 10, 223 | check = FALSE 224 | ) 225 | 226 | 227 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result 228 | # 1 fconcave(dt) 2.61s 2.84s 0.350 4.05MB 0.629 10 18 28.6s 229 | # 2 fconcave_geo… 2.42s 2.54s 0.385 1.82MB 0.424 10 11 26s 230 | # 3 fsummarise(f… 2.67s 2.88s 0.332 4.04MB 0.597 10 18 30.1s 231 | -------------------------------------------------------------------------------- /tests/tests_rafa/generate_sample_data.R: -------------------------------------------------------------------------------- 1 | devtools::load_all('.') 2 | library(tictoc) 3 | library(dplyr) 4 | library(data.table) 5 | library(ipeadatalake) 6 | set.seed(42) 7 | 8 | sample_size <- 10000 9 | 10 | data_path <- system.file("extdata/small_sample.csv", package = "geocodebr") 11 | input_df <- read.csv(data_path) 12 | 13 | # select and reorder columns 14 | input_df <- input_df |> 15 | select( 16 | id = id, 17 | logradouro = nm_logradouro, 18 | numero = Numero, 19 | bairro = Bairro, 20 | cep = Cep, 21 | municipio = nm_municipio, 22 | uf = nm_uf 23 | ) 24 | 25 | head(input_df) 26 | 27 | # rais -------------------------------------------------------------------- 28 | 29 | rais <- ipeadatalake::ler_rais( 30 | ano = 2019, 31 | tipo = 'estabelecimento', 32 | as_data_frame = T, 33 | colunas = c("id_estab", "logradouro", 34 | "bairro", "codemun", "uf", "cep")) |> 35 | filter(uf %in% c(12, 27, 33)) |> # only states of Acre, Alagoas and RJ 36 | compute() |> 37 | dplyr::slice_sample(n = sample_size) |> # sample 50K 38 | filter(uf != "IG") |> 39 | filter(uf != "") |> 40 | collect() 41 | 42 | data.table::setDT(rais) 43 | 44 | # create column number 45 | rais[, numero := gsub("[^0-9]", "", logradouro)] 46 | 47 | # remove numbers from logradouro 48 | rais[, logradouro := gsub("\\d+", "", logradouro)] 49 | rais[, logradouro := gsub(",", "", logradouro)] 50 | 51 | 52 | # select and reorder columns 53 | rais <- rais |> 54 | select( 55 | id = id_estab, 56 | logradouro = logradouro, 57 | numero = numero, 58 | bairro = bairro, 59 | cep = cep, 60 | municipio = codemun, 61 | uf = uf 62 | ) 63 | 64 | head(rais) 65 | 66 | 67 | 68 | 69 | 70 | 71 | # cad unico -------------------------------------------------------------------- 72 | 73 | cad <- ipeadatalake::ler_cadunico( 74 | data = 201912, 75 | tipo = 'familia', 76 | as_data_frame = F, 77 | colunas = c("co_familiar_fam", "co_uf", "cd_ibge_cadastro", 78 | "no_localidade_fam", "no_tip_logradouro_fam", 79 | "no_tit_logradouro_fam", "no_logradouro_fam", 80 | "nu_logradouro_fam", "ds_complemento_fam", 81 | "ds_complemento_adic_fam", 82 | "nu_cep_logradouro_fam", "co_unidade_territorial_fam", 83 | "no_unidade_territorial_fam", "co_local_domic_fam") 84 | ) 85 | 86 | # a <- tail(cad, n = 100) |> collect() 87 | 88 | # compose address fields 89 | cad <- cad |> 90 | filter(co_uf %in% c(12, 27, 33)) |> # only states of Acre, Alagoas and RJ 91 | compute() |> 92 | dplyr::slice_sample(n = sample_size) |> # sample 20K 93 | mutate(no_tip_logradouro_fam = ifelse(is.na(no_tip_logradouro_fam), '', no_tip_logradouro_fam), 94 | no_tit_logradouro_fam = ifelse(is.na(no_tit_logradouro_fam), '', no_tit_logradouro_fam), 95 | no_logradouro_fam = ifelse(is.na(no_logradouro_fam), '', no_logradouro_fam) 96 | ) |> 97 | mutate(abbrev_state = co_uf, 98 | code_muni = cd_ibge_cadastro, 99 | logradouro = paste(no_tip_logradouro_fam, no_tit_logradouro_fam, no_logradouro_fam), 100 | numero = nu_logradouro_fam, 101 | cep = nu_cep_logradouro_fam, 102 | bairro = no_localidade_fam) |> 103 | select(co_familiar_fam, 104 | abbrev_state, 105 | code_muni, 106 | logradouro, 107 | numero, 108 | cep, 109 | bairro) |> 110 | dplyr::collect() 111 | 112 | 113 | 114 | cad <- cad |> 115 | select( 116 | id = co_familiar_fam, 117 | logradouro = logradouro, 118 | numero = numero, 119 | bairro = bairro, 120 | cep = cep, 121 | municipio = code_muni, 122 | uf = abbrev_state 123 | ) 124 | 125 | 126 | 127 | df <- rbind(input_df, cad, rais) 128 | 129 | setDT(df) 130 | df[, id := 1:nrow(df)] 131 | head(df) 132 | 133 | arrow::write_parquet(df, './inst/extdata/large_sample.parquet') 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /tests/tests_rafa/geocoding_en.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Geocoding with geocodebr (ENG)" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Geocoding with geocodebr} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | ``` 22 | 23 | # Geocoding: from addresses to spatial coordinates 24 | 25 | Once you have a table (`data.frame`) with addresses, geolocating the data with **{geocodebr}** can be done in two simple steps: 26 | 27 | 1. The first step is to use the `listar_campos()` function to declare the names of the columns in your input `data.frame` that correspond to each field of the addresses. 28 | 29 | ```{r, eval=TRUE} 30 | library(geocodebr) 31 | 32 | # read input sample data 33 | input_df <- read.csv(system.file("extdata/small_sample.csv", package = "geocodebr")) 34 | 35 | # 1st step: indicate the columns describing the address fields 36 | fields <- geocodebr::listar_campos( 37 | logradouro = "nm_logradouro", 38 | numero = "Numero", 39 | cep = "Cep", 40 | bairro = "Bairro", 41 | municipio = "nm_municipio", 42 | estado = "nm_uf" 43 | ) 44 | ``` 45 | 46 | 2. The second step is to use the `geocode()` function to find the geographic coordinates of input addresses. 47 | 48 | ```{r, eval=TRUE} 49 | # 2nd step: geocode 50 | df <- geocodebr::geocode( 51 | addresses_table = input_df, 52 | address_fields = fields, 53 | n_cores = 1, 54 | progress = FALSE 55 | ) 56 | 57 | head(df) 58 | ``` 59 | 60 | obs. Note that the first time the user runs this function, {geocodebr} will download a few files and store them locally. This way, the data only needs to be downloaded once. More info about data caching below. 61 | 62 | The output coordinates use the official geodetic reference system used in Brazil: SIRGAS2000, CRS(4674). The results of {geocodebr} are classified into six broad `precision` categories depending on how exactly each input address was matched with CNEFE data. The accuracy of the results are indicated in two columns of the output: `precision` and `match_type`. More information below. 63 | 64 | 65 | # Precision categories: 66 | 67 | The results of {geocodebr} are classified into six broad `precision` categories: 68 | 69 | - "numero" 70 | - "numero_interpolado" 71 | - "rua" 72 | - "cep" 73 | - "bairro" 74 | - "municipio" 75 | - `NA` (not found) 76 | 77 | Each precision level can be disaggregated into more refined match types. 78 | 79 | ## Match Type 80 | 81 | The column `match_type` provides more refined information on how exactly each input address was matched with CNEFE. In every category, {geocodebr} takes the average latitude and longitude of the addresses included in CNEFE that match the input address based on combinations of different fields. In the strictest case, for example, the function finds a deterministic match for all of the fields of a given address (`"estado"`, `"municipio"`, `"logradouro"`, `"numero"`, `"cep"`, `"localidade"`). Think for example of a building with several apartments that match the same street address and number. In such case, the coordinates of the apartments will differ very slightly, and {geocodebr} takes the average 82 | of those coordinates. In a less rigorous example, in which only the fields (`"estado"`, `"municipio"`, `"logradouro"`, `"localidade"`) are matched, {geocodebr} calculates the average coordinates of all the addresses in CNEFE along that street and which fall within the same neighborhood. 83 | 84 | The complete list of precision levels, their corresponding match type categories and the fields considered in each category are described below: 85 | 86 | - precision: **"numero"** 87 | - match_type: 88 | - en01: logradouro, numero, cep e bairro 89 | - en02: logradouro, numero e cep 90 | - en03: logradouro, numero e bairro 91 | - en04: logradouro e numero 92 | - pn01: logradouro, numero, cep e bairro 93 | - pn02: logradouro, numero e cep 94 | - pn03: logradouro, numero e bairro 95 | - pn04: logradouro e numero 96 | 97 | - precision: **"numero_interpolado"** 98 | - match_type: 99 | - ei01: logradouro, numero, cep e bairro 100 | - ei02: logradouro, numero e cep 101 | - ei03: logradouro, numero e bairro 102 | - ei04: logradouro e numero 103 | - pi01: logradouro, numero, cep e bairro 104 | - pi02: logradouro, numero e cep 105 | - pi03: logradouro, numero e bairro 106 | - pi04: logradouro e numero 107 | 108 | - precision: **"rua"** (when input number is missing 'S/N') 109 | - match_type: 110 | - er01: logradouro, cep e bairro 111 | - er02: logradouro e cep 112 | - er03: logradouro e bairro 113 | - er04: logradouro 114 | - pr01: logradouro, cep e bairro 115 | - pr02: logradouro e cep 116 | - pr03: logradouro e bairro 117 | - pr04: logradouro 118 | 119 | - precision: **"cep"** 120 | - match_type: 121 | - ec01: municipio, cep, localidade 122 | - ec02: municipio, cep 123 | 124 | - precision: **"bairro"** 125 | - match_type: 126 | - eb01: municipio, localidade 127 | 128 | - precision: **"municipio"** 129 | - match_type: 130 | - em01: municipio 131 | 132 | ***Note:*** Match types starting with 'p' use probabilistic matching of the logradouro field, while types starting with 'e' use deterministic matching only. **Match types with probabilistic matching are not implemented in {geocodebr} yet**. 133 | 134 | 135 | 136 | 137 | # Data cache 138 | 139 | The first time the user runs the `geocode()` function, {geocodebr} will download a few reference files and store them locally. This way, the data only needs to be downloaded once. Mind you that these files require approximately 4GB of space in your local drive. 140 | 141 | The package includes the following functions to help users manage cached files: 142 | 143 | - `get_cache_dir()`: returns the path to where the cached data is stored. By default, files are cached in the package directory. 144 | - `set_cache_dir()`: set a custom directory to be used. This configuration is persistent across different R sessions. 145 | - `list_cached_data()`: list all files currently cached 146 | - `clean_cache_dir()`: delete all files of the cache directory used by {geocodebr} 147 | 148 | -------------------------------------------------------------------------------- /tests/tests_rafa/geocoding_pt.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Geolocalização com geocodebr" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Geolocalização com geocodebr} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | ``` 22 | 23 | # Geocodificação: de endereços para coordenadas espaciais 24 | 25 | Uma vez que você tenha uma tabela (`data.frame`) com endereços, a geolocalização dos dados com **{geocodebr}** pode ser feita em dois passos simples: 26 | 27 | 1. O primeiro passo é utilizar a função `definir_campos()` para declarar os nomes das colunas no seu `data.frame` que correspondem a cada campo dos endereços. 28 | 29 | 30 | ```{r, eval=TRUE} 31 | library(geocodebr) 32 | 33 | # leitura de dados de input 34 | input_df <- read.csv(system.file("extdata/small_sample.csv", package = "geocodebr")) 35 | 36 | # 1o passo: indicar nome das colunas correspondento aos campos de endereço 37 | fields <- geocodebr::definir_campos( 38 | logradouro = "nm_logradouro", 39 | numero = "Numero", 40 | cep = "Cep", 41 | localidade = "Bairro", 42 | municipio = "nm_municipio", 43 | estado = "nm_uf" 44 | ) 45 | ``` 46 | 47 | 2. O segundo passo é utilizar a função `geocode()` para encontrar as coordenadas geográficas dos endereços de entrada. 48 | 49 | 50 | ```{r, eval=TRUE} 51 | # 2o passo: geolocalização 52 | df <- geocodebr::geocode( 53 | enderecos = input_df, 54 | campos_endereco = fields, 55 | resultado_completo = FALSE, 56 | verboso = TRUE, 57 | cache = TRUE, 58 | n_cores = 1 59 | ) 60 | 61 | head(df) 62 | ``` 63 | 64 | obs. Note que na primeira vez que o usuário usa essa fnução, {geocodebr} irá baixar alguns arquivos de referência e armaneza-los localmente. Assim, esses dados só precisam ser baixados uma única vez. Mais informações sobr o cache dos dados abaixo. 65 | 66 | 67 | As coordendas espaciais do output usam sistema de referência ofical do Brasil: SIRGAS2000, CRS(4674). Os resultados do {geocodebr} são classificados em seis amplas categorias de precisão, dependendo de quão exatamente cada endereço de entrada foi correspondido com os dados do CNEFE. O grau de precisão é indicado em duas colunas da tabela de output: `precisao` e `tipo_resultado`. Mais informações abaixo. 68 | 69 | 70 | # Categorias de Precisão: `precisao` 71 | 72 | Os resultados do **{geocodebr}** são classificados em seis amplas categorias de `precisao`: 73 | 74 | - "numero" 75 | - "numero_aproximado" 76 | - "logradouro" 77 | - "cep" 78 | - "localidade" 79 | - "municipio" 80 | - `NA` (não encontrado) 81 | 82 | Cada nível de precisão pode ser desagregado em tipos de correspondência mais refinados. 83 | 84 | ## Tipo de Correspondência: `tipo_resultado` 85 | 86 | A coluna `tipo_resultado` fornece informações mais detalhadas sobre como exatamente cada endereço de entrada foi encontrado no CNEFE. Em cada categoria, o **{geocodebr}** calcula a média da latitude e longitude dos endereços incluídos no CNEFE que correspondem ao endereço de entrada, com base em combinações de diferentes campos. No caso mais rigoroso, por exemplo, a função encontra uma correspondência determinística para todos os campos de um dado endereço (`"estado"`, `"municipio"`, `"logradouro"`, `"numero"`, `"cep"`, `"localidade"`). Pense, por exemplo, em um prédio com vários apartamentos que correspondem ao mesmo endereço de rua e número. Nesse caso, as coordenadas dos apartamentos podem diferir ligeiramente, e o **{geocodebr}** calcula a média dessas coordenadas. Em um caso menos rigoroso, no qual apenas os campos (`"estado"`, `"municipio"`, `"logradouro"`, `"localidade"`) são encontrados, o **{geocodebr}** calcula as coordenadas médias de todos os endereços no CNEFE ao longo daquela rua e que se encontram na mesma localidade/bairro. Assim, as coordenadas de resultado tendem a ser o ponto médio do trecho daquela rua que passa dentro daquela localidade/bairro. 87 | 88 | A lista completa dos níveis de precisão (`precisao`), suas categorias de tipo de correspondência (`tipo_resultado`) e os campos de endereço considerados em cada categoria estão descritos abaixo: 89 | 90 | - precisao: **"numero"** 91 | - tipo_resultado: 92 | - en01: logradouro, numero, cep e localidade 93 | - en02: logradouro, numero e cep 94 | - en03: logradouro, numero e localidade 95 | - en04: logradouro e numero 96 | - pn01: logradouro, numero, cep e localidade 97 | - pn02: logradouro, numero e cep 98 | - pn03: logradouro, numero e localidade 99 | - pn04: logradouro e numero 100 | 101 | - precisao: **"numero_aproximado"** 102 | - tipo_resultado: 103 | - ei01: logradouro, numero, cep e localidade 104 | - ei02: logradouro, numero e cep 105 | - ei03: logradouro, numero e localidade 106 | - ei04: logradouro e numero 107 | - pi01: logradouro, numero, cep e localidade 108 | - pi02: logradouro, numero e cep 109 | - pi03: logradouro, numero e localidade 110 | - pi04: logradouro e numero 111 | 112 | - precisao: **"logradouro"** (quando o número de entrada está faltando 'S/N') 113 | - tipo_resultado: 114 | - er01: logradouro, cep e localidade 115 | - er02: logradouro e cep 116 | - er03: logradouro e localidade 117 | - er04: logradouro 118 | - pr01: logradouro, cep e localidade 119 | - pr02: logradouro e cep 120 | - pr03: logradouro e localidade 121 | - pr04: logradouro 122 | 123 | - precisao: **"cep"** 124 | - tipo_resultado: 125 | - ec01: municipio, cep, localidade 126 | - ec02: municipio, cep 127 | 128 | - precisao: **"localidade"** 129 | - tipo_resultado: 130 | - eb01: municipio, localidade 131 | 132 | - precisao: **"municipio"** 133 | - tipo_resultado: 134 | - em01: municipio 135 | 136 | ***Nota:*** As categorias de `tipo_resultado` que começam com 'p' utilizam correspondência probabilística do campo logradouro, enquanto os tipos que começam com 'e' utilizam apenas correspondência determinística. **As categorias de `tipo_resultado` que usam correspondência probabilística ainda não estão implementados no pacote geocodebr**. 137 | 138 | 139 | # Cache de Dados 140 | 141 | Na primeira vez que o usuário executar a função `geocode()`, o {geocodebr} irá baixar alguns arquivos de referência e armazená-los localmente. Dessa forma, os dados precisam ser baixados apenas uma vez. Vale lembrar que esses arquivos requerem aproximadamente 4GB de espaço no seu disco local. 142 | 143 | O pacote inclui as seguintes funções para ajudar os usuários a gerenciar os arquivos em cache: 144 | 145 | - `listar_pasta_cache()`: retorna o caminho onde os dados em cache estão armazenados. Por padrão, os arquivos são armazenados no diretório do pacote. 146 | - `definir_pasta_cache()`: define um diretório personalizado para ser utilizado. Essa configuração é persistente entre diferentes sessões do R. 147 | - `listar_dados_cache()`: lista todos os arquivos atualmente armazenados em cache. 148 | - `deletar_pasta_cache()`: exclui todos os arquivos do diretório de cache utilizado pelo **{geocodebr}**. 149 | -------------------------------------------------------------------------------- /tests/tests_rafa/issue_50.R: -------------------------------------------------------------------------------- 1 | library(readxl) 2 | library(dplyr) 3 | devtools::load_all('.') 4 | 5 | 6 | path <- 'C:/Users/rafap/Downloads/teste_cc_enderecos.xlsx' 7 | # 'C:/Users/r1701707/Downloads/teste_cc_probabilistico_resultado.xlsx' 8 | enderecosbrasil <- readxl::read_xlsx(path) 9 | 10 | 11 | enderecosbrasil$CEP[1] <- NA 12 | 13 | enderecosbrasil <- enderecosbrasil[8,] 14 | 15 | df <- structure(list(IBGE = 330455, UF = "RJ", MUNICIPIO = "Rio de Janeiro", 16 | Endereco = "RUA DO RIO, 08 JACAREZINHO CEP: 20785-180", 17 | Logradouro = "RUA DO RIO", Numero = 8, Bairro = "JACAREZINHO", 18 | CEP = "20785-180", Observacao = "NA"), row.names = c(NA, 19 | -1L), class = c("tbl_df", "tbl", "data.frame")) 20 | 21 | 22 | # Primeiro passo: inidicar o nome das colunas com cada campo dos enderecos 23 | campos_1 <- geocodebr::definir_campos( 24 | logradouro = "Logradouro", 25 | numero = "Numero", 26 | cep = "CEP", 27 | localidade = "Bairro", 28 | municipio = "MUNICIPIO", 29 | estado = "UF" 30 | ) 31 | 32 | enderecosbrasil <- dplyr::select(enderecosbrasil, Logradouro, Numero, CEP, Bairro, MUNICIPIO, UF) 33 | 34 | # Segundo passo: geolocalizar 35 | out_completo <- geocodebr::geocode( 36 | enderecos = enderecosbrasil, 37 | campos_endereco = campos_1, 38 | resultado_completo = TRUE, 39 | resolver_empates = F, 40 | resultado_sf = FALSE, 41 | verboso = T, 42 | cache = TRUE, 43 | n_cores = 1 44 | ) 45 | 46 | View(out_completo) 47 | 48 | 49 | # Segundo passo: geolocalizar 50 | out_simles2 <- geocodebr::geocode( 51 | enderecos = enderecosbrasil, 52 | campos_endereco = campos_1, 53 | resultado_completo = FALSE, 54 | resolver_empates = F, 55 | resultado_sf = FALSE, 56 | verboso = T, 57 | cache = TRUE, 58 | n_cores = 1 59 | ) 60 | 61 | View(out_simles2) 62 | 63 | # logradouro_encontrado mesmo quando resultado_completo = FALSE 64 | -------------------------------------------------------------------------------- /tests/tests_rafa/meta.R: -------------------------------------------------------------------------------- 1 | library(arrow) 2 | # install_arrow() 3 | library(sf) 4 | library(dplyr) 5 | library(geobr) 6 | library(duckdb) 7 | 8 | 9 | 10 | # install extension 11 | 12 | con <- duckdb::dbConnect(duckdb::duckdb(), dbdir=":memory:") # run on memory 13 | DBI::dbExecute(con, "FORCE INSTALL httpfs") 14 | DBI::dbExecute(con, "LOAD httpfs") 15 | 16 | 17 | ext <- DBI::dbGetQuery(con, "FROM duckdb_extensions()") 18 | 19 | 20 | 21 | 22 | muni <- geobr::lookup_muni(name_muni = 'Guarulhos') 23 | muni <- geobr::read_municipality(code_muni = muni$code_muni) 24 | 25 | bb <- sf::st_bbox(muni) 26 | 27 | # https://cran.r-project.org/web/packages/overturemapsr/index.html 28 | 29 | # https://walker-data.com/posts/overture-buildings/ 30 | # https://data.humdata.org/organization/meta 31 | 32 | buildings <- open_dataset('s3://overturemaps-us-west-2/release/2024-05-16-beta.0/theme=buildings?region=us-west-2') 33 | 34 | nrow(buildings) 35 | 36 | 37 | df <- arrow::open_dataset('s3://overturemaps-us-west-2/release/2024-09-18.0') 38 | names(df) 39 | 40 | 41 | library(overturemapsr) 42 | 43 | t <- overturemapsr::get_all_overture_types() 44 | 45 | d <- overturemapsr::dataset_path(overture_type = 'locality') 46 | 47 | df <- overturemapsr::record_batch_reader(overture_type = 'place', bbox = bb) 48 | 49 | df$bbox <- NULL 50 | df$sources <- NULL 51 | df$names <- NULL 52 | sapply(df, class) 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/tests_rafa/munis_bbox.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(dplyr) 3 | 4 | # Load the state polygons 5 | df <- geobr::read_municipality(year = 2022) 6 | 7 | # Calculate bounding boxes of states 8 | bounding_boxes <- df |> 9 | st_as_sf() |> # Ensure df is an sf object 10 | rowwise() |> # Process each polygon individually 11 | mutate( 12 | xmin = st_bbox(geom)["xmin"], # Extract xmin from the bounding box 13 | ymin = st_bbox(geom)["ymin"], # Extract ymin from the bounding box 14 | xmax = st_bbox(geom)["xmax"], # Extract xmax from the bounding box 15 | ymax = st_bbox(geom)["ymax"] # Extract ymax from the bounding box 16 | ) |> 17 | ungroup() |> # Unrowwise after rowwise operations 18 | select(code_muni, xmin, ymin, xmax, ymax) |> # Select desired columns 19 | st_drop_geometry() 20 | 21 | # View the resulting bounding box data.frame 22 | head(bounding_boxes) 23 | 24 | data.table::fwrite(bounding_boxes, './inst/extdata/munis_bbox.csv') 25 | 26 | 27 | head(input_table) 28 | 29 | candidate_states <- 30 | subset(x = bounding_boxes, 31 | (xmin < bbox_lon_min | xmax > bbox_lon_max) & 32 | (ymin < bbox_lat_min | ymax > bbox_lat_max) 33 | ) 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/tests_rafa/reverse_geocode_tests.R: -------------------------------------------------------------------------------- 1 | devtools::load_all('.') 2 | library(dplyr) 3 | 4 | 5 | # input data 6 | 7 | pontos <- readRDS( 8 | system.file("extdata/pontos.rds", package = "geocodebr") 9 | ) 10 | 11 | pontos <- pontos[1:500,] 12 | 13 | # ok reverse_geocode_arrow 14 | # ok reverse_geocode_hybrid 15 | # ok reverse_geocode_join 16 | # ok reverse_geocode_filter 17 | reverse_geocode_filter_loop 18 | 19 | # reverse geocode 20 | bench::system_time( 21 | out <- reverse_geocode_filter_loop( 22 | coordenadas = pontos, 23 | dist_max = 1000, 24 | verboso = TRUE, 25 | cache = T, 26 | n_cores = 1 27 | ) 28 | ) 29 | View(out) 30 | 31 | 32 | # ttt <- data.frame(id=1, lat=-15.814192047159876, lon=-47.90534614672923) 33 | # reverse_geocode(df = ttt) 34 | 35 | # take aways 36 | # ok reverse_geocode_filter # mais rapdido e eficiente, mas sem progress bar 37 | # ok reverse_geocode_join # igual o _filter, mas usa join 38 | # ok reverse_geocode_hybrid # com progress bar mas um pouco mais lento e bem mais memoria 39 | # ok reverse_geocode_arrow # tempo igual a _hybrid, mas usa bem mais memoria 40 | # ok filterloop # disparado o mais lento, com progress e memoria media 41 | 42 | # essa funcao pode fica muito mais rapida / eficiente se usarmos a biblioteca de 43 | # dados espaciais do duckdb 44 | 45 | b5 <- bench::mark( 46 | duck_filter4 = reverse_geocode_filter(coordenadas = pontos, dist_max = 5000, n_cores = 4), 47 | duck_filter_loop4 = reverse_geocode_filter_loop(coordenadas = pontos, dist_max = 5000, n_cores = 4), 48 | # duck_join4 = reverse_geocode_join(coordenadas = pontos, dist_max = 1000, n_cores = 4), 49 | # arrow4 = reverse_geocode_arrow(coordenadas = pontos, dist_max = 5000, n_cores = 4), 50 | hybrid4 = reverse_geocode_hybrid(coordenadas = pontos, dist_max = 5000, n_cores = 4), 51 | iterations = 5, 52 | check = F 53 | ) 54 | b5 55 | 56 | # # 500 pontos 57 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory 58 | # 59 | # 1 duck_filter4 1.54m 1.62m 0.0101 221.5MB 0.0423 5 21 8.28m 60 | # 2 duck_filter_loop4 5.35m 6.88m 0.00255 14.5MB 0.00357 5 7 32.7m 61 | # 3 hybrid4 2.41m 2.47m 0.00663 34.5MB 0.302 5 228 12.56m 62 | 63 | # # 1000 pontos 64 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory 65 | # 66 | # 1 duck_filt… 2.97m 2.97m 0.00560 11.3MB 0 1 0 2.97m 67 | # 2 duck_join4 3.03m 3.03m 0.00550 11.5MB 0 1 0 3.03m 68 | # 3 arrow4 4.27m 4.27m 0.00391 240.1MB 0.316 1 81 4.27m 69 | # 4 hybrid4 4.24m 4.24m 0.00393 122.4MB 0.110 1 28 4.24m 70 | # 4 filterloop 10.7m 11.27m 0.00146 19.8MB 0.00195 3 4 34.19m 71 | 72 | 73 | 74 | # parelizacao nao esta fazendo diferenca nem p/ original_duck_dt1 nem p/ farrow 75 | # pode ateh prejudicar no caso de original_duck_dt1 76 | 77 | 78 | m1 <- microbenchmark::microbenchmark( 79 | duck_filter4 = reverse_geocode_filter(coordenadas = pontos, dist_max = 1000, n_cores = 4), 80 | duck_join4 = reverse_geocode_join(coordenadas = pontos, dist_max = 1000, n_cores = 4), 81 | arrow4 = reverse_geocode_arrow(coordenadas = pontos, dist_max = 1000, n_cores = 4), 82 | hybrid4 = reverse_geocode_hybrid(coordenadas = pontos, dist_max = 1000, n_cores = 4), 83 | times = 5 84 | ) 85 | m1 86 | # # 1000 pontos 87 | # Unit: seconds 88 | # expr min lq mean median uq max neval 89 | # duck_filter4 164.2226 184.9813 196.7560 185.3038 223.7968 225.4755 5 90 | # duck_join4 168.5803 181.8956 197.7216 188.9110 222.6354 226.5857 5 91 | # arrow4 258.2942 265.0396 269.4309 269.8658 272.9294 281.0256 5 92 | # hybrid4 257.4353 258.4068 260.0735 258.6678 261.7325 264.1252 5 93 | 94 | 95 | #' add id to input 96 | #' create output table 97 | #' reduce cnefe global scope 98 | #' register on duckdb 99 | #' overall search with 100 metros 100 | #' atualiza input 101 | #' overall search with 500 metros 102 | #' atualiza input 103 | #' overall search with 1000 metros 104 | 105 | 106 | # for (threshol in c(100, 500, 1000)){ 107 | # 108 | # # find cases nearby 109 | # query_join_cases_nearby <- glue::glue( 110 | # "insert TABLE cases_nearby AS 111 | # SELECT * 112 | # FROM coordenadas_db 113 | # LEFT JOIN filtered_cnefe_coords 114 | # ON coordenadas_db.lat_min < filtered_cnefe_coords.lat 115 | # AND coordenadas_db.lat_max > filtered_cnefe_coords.lat 116 | # AND coordenadas_db.lon_min < filtered_cnefe_coords.lon 117 | # AND coordenadas_db.lon_max > filtered_cnefe_coords.lon" 118 | # ) 119 | # 120 | # 121 | # 122 | # # update input table to remove cases found 123 | # 124 | # 125 | # 126 | # } 127 | 128 | 129 | 130 | # gerate sample points for reverse geocode ------------------------------------- 131 | 132 | library(geobr) 133 | library(sf) 134 | library(ggplot2) 135 | 136 | br <- geobr::read_state(code_state = 'MG') 137 | br <- geobr::read_urban_concentrations() |> 138 | filter(abbrev_state %in% c('ES', 'AP')) 139 | 140 | set.seed(42) 141 | n_size <- 1000 142 | coordenadas <- sf::st_sample(br, size = n_size) 143 | 144 | coordenadas <- st_as_sf(coordenadas) 145 | coordenadas$id <- 1:n_size 146 | coordenadas <- sf::st_set_geometry(coordenadas, 'geometry') 147 | 148 | coordenadas <- coordenadas |> dplyr::select(id, geometry) 149 | head(coordenadas) 150 | 151 | 152 | ggplot() + 153 | geom_sf(data=br) + 154 | geom_sf(data=coordenadas) 155 | 156 | 157 | saveRDS(coordenadas, './inst/extdata/pontos.rds') 158 | 159 | 160 | 161 | 162 | 163 | # gerate states bbox ----------------------------------------------------------- 164 | 165 | states <- geobr::read_state(simplified = FALSE) 166 | 167 | bbox_states2 <- states |> 168 | group_by(abbrev_state) |> 169 | mutate(xmin = sf::st_bbox(geom)[1] |> round(7), 170 | ymin = sf::st_bbox(geom)[2] |> round(7), 171 | xmax = sf::st_bbox(geom)[3] |> round(7), 172 | ymax = sf::st_bbox(geom)[4] |> round(7) 173 | ) |> 174 | sf::st_drop_geometry() |> 175 | select(abbrev_state, xmin, ymin, xmax, ymax) 176 | 177 | data.table::setDT(bbox_states2) 178 | bbox_states2$xmin |> nchar() 179 | 180 | saveRDS(bbox_states2, './inst/extdata/states_bbox.rds') 181 | 182 | 183 | devtools::load_all('.') 184 | library(dplyr) 185 | 186 | #' incluir parametro 187 | #' @output_level = c('address', 'locality', 'municipality', 'state') 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | pontos <- readRDS( 200 | system.file("extdata/pontos.rds", package = "geocodebr") 201 | ) 202 | 203 | bench::mark( 204 | # duck_filter1 = reverse_geocode_filter(coordenadas = pontos, dist_max = 2000, n_cores = 1), 205 | # duck_filter8 = reverse_geocode_filter(coordenadas = pontos, dist_max = 2000, n_cores = 8), 206 | # duck_join1 = reverse_geocode_join(coordenadas = pontos, dist_max = 2000, n_cores = 1), 207 | # duck_join8 = reverse_geocode_join(coordenadas = pontos, dist_max = 2000, n_cores = 8), 208 | hybrid1 = reverse_geocode_hybrid(coordenadas = pontos, dist_max = 2000, n_cores = 1), 209 | hybrid8 = reverse_geocode_hybrid(coordenadas = pontos, dist_max = 2000, n_cores = 8), 210 | iterations = 5, 211 | check = F 212 | ) 213 | 214 | # 1000 pontos 215 | # expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time result memory 216 | # 217 | # 1 duck_filter1 3.19m 3.31m 0.00490 75MB 0.0108 5 11 17m 218 | # 2 duck_filter8 2.93m 3.04m 0.00516 51MB 0.00723 5 7 16.1m 219 | # 220 | # 1 duck_join1 2.93m 3.54m 0.00475 76.2MB 0.00854 5 9 17.6m 221 | # 2 duck_join8 3.62m 4.05m 0.00407 51.2MB 0.00651 5 8 20.5m 222 | # 223 | # 1 hybrid1 5.13m 5.9m 0.00277 88.3MB 0.262 5 473 30.1m 224 | # 2 hybrid8 5.09m 5.19m 0.00321 66MB 0.307 5 478 25.9m 225 | -------------------------------------------------------------------------------- /tests/tests_rafa/sankey_plot.R: -------------------------------------------------------------------------------- 1 | library(ggalluvial) 2 | 3 | temp <- temp_dfgeo |> select(id, tipo_resultado, precisao) |> unique() 4 | # 37.9s 5 | ### viable sequence of match types for really large datasets 6 | all_possible_match_types <- c( 7 | "dn01", "da01", 8 | "dn02", "da02", 9 | "dn03", "da03", 10 | "dn04", "da04", 11 | "pn01", "pa01", "pn02", "pa02", "pn03", "pa03", #"pn04", "pa04", # too costly 12 | "dl01", 13 | "dl02", 14 | "dl03", 15 | "dl04", # pl04", # too costly 16 | "pl01", "pl02", "pl03", 17 | "dc01", "dc02", "db01", "dm01" 18 | ) 19 | 20 | 21 | 22 | temp2 <- temp_dfgeo2 |> select(id, tipo_resultado2 =tipo_resultado, precisao2 = precisao) |> unique() 23 | # 30s 24 | all_possible_match_types <- c( 25 | "dn01", "da01", 26 | "dn02", "da02", 27 | "dn03", "da03", 28 | "dn04", "da04", 29 | "pn01", "pa01", "pn02", "pa02", "pn03", "pa03", #"pn04", "pa04", # too costly 30 | "dl01", "pl01", 31 | "dl02", "pl02", 32 | "dl03", "pl03", 33 | "dl04", # pl04", # too costly 34 | "dc01", "dc02", "db01", "dm01" 35 | ) 36 | 37 | 38 | df <- left_join(temp, temp2) 39 | 40 | 41 | table(df$precisao,df$precisao2 ) 42 | 43 | table(df$precisao ) 44 | 45 | table(df$precisao2 ) 46 | 47 | data.table::setDT(df)[, Freq := 1] 48 | 49 | df_agreg <- df[, .(Freq = .N), by = .(tipo_resultado, tipo_resultado2, precisao, precisao2)] 50 | df_agreg <- df_agreg[tipo_resultado != tipo_resultado2] 51 | df_agreg <- df_agreg[precisao != precisao2] 52 | 53 | library(ggplot2) 54 | library(ggalluvial) 55 | library(ggplotly) 56 | 57 | 58 | gg <- ggplot(df_agreg, 59 | aes(y = Freq, axis1 = tipo_resultado, axis2 = tipo_resultado2)) + 60 | geom_alluvium(aes(fill = tipo_resultado2), width = 1/12) + 61 | geom_stratum(width = 1/12, fill = "white", color = "grey") + 62 | geom_label(stat = "stratum", aes(label = after_stat(stratum)), size=2) + 63 | scale_x_discrete(limits = c("antes", "depois"), expand = c(.05, .05)) + 64 | # scale_fill_brewer(type = "qual", palette = "Set1") + 65 | scale_fill_viridis_d() 66 | 67 | gg 68 | # plotly::ggplotly(gg) 69 | 70 | ggsave(gg, filename = 'ggaluvia.png', width = 18, height = 12, units='cm') 71 | 72 | 73 | 74 | # pn01 da04 75 | # 76 | # dfall <- left_join(dfgeo, dfgeo2, by='id') |> 77 | # filter(tipo_resultado.x=='pn01' & 78 | # tipo_resultado.y=='da04') 79 | # 80 | # dfall$id 81 | 82 | filter(dfgeo,id %in% c(1371) ) 83 | filter(dfgeo2,id %in% c(1371) ) 84 | #' por que id '463' nao foi encontrado na cat da01 ? e sim no da02 85 | #' em tese, nao deveria ter nenhuma transicao de p para d 86 | #' outro exemplo: de pa01 para da03 87 | #' - ora, se foi pa01, encontrou bairro e cep 88 | #' - se depois achou com da03, entao achou com logradouro determ, e soh o bairro mas nao o cep 89 | #' 90 | #' outro caso pn01 e depois vira da04 91 | #' pn03 e depois vira da04 92 | 93 | 94 | 95 | 96 | 97 | ############## sankey plot ---------------------------------------- 98 | library(ggplot2) 99 | library(ggsankey) 100 | library(dplyr) 101 | library(data.table) 102 | 103 | system.time(danid <- dani()) # 60.10 104 | system.time(rafad <- rafa()) # 39.54 105 | 106 | 107 | df <- left_join(select(danid, c('id', 'match_type')), 108 | select(rafad, c('id', 'match_type')), by='id') 109 | 110 | data.table::setDT(df) 111 | data.table::setnames( 112 | df, 113 | old = c('match_type.x', 'match_type.y'), 114 | new = c('case_dani', 'case_rafa') ) 115 | 116 | 117 | transition_mtrx <- round(table(df$case_dani, df$case_rafa) / nrow(df)*100, 1) 118 | 119 | 120 | df[, case_dani := as.integer(gsub('case_', '', case_dani)) ] 121 | df_count <- df[, .(count = round(.N / nrow(df)*100, 2)), by= .(case_dani, case_rafa)] 122 | 123 | # df_long <- data.table::melt(data = df, id.vars='id') 124 | # head(df_long) 125 | 126 | # df_sankey <- ggsankey::make_long(df, case_dani, case_rafa) 127 | df_sankey <- ggsankey::make_long(df_count, case_dani, case_rafa, value = count) 128 | df_sankey$value <- round(df_sankey$value / nrow(df)*100, 2) 129 | head(df_sankey) 130 | 131 | #cats <- c(1:4, 44, 5:12) 132 | cats <- c(12:5, 44, 4:1) 133 | df_sankey$node <- factor(x = df_sankey$node, 134 | levels = cats, 135 | ordered = T) 136 | 137 | df_sankey$next_node <- factor(x = df_sankey$next_node, 138 | levels = cats, 139 | ordered = T) 140 | 141 | fig <- ggplot(data = df_sankey, 142 | aes(x = x, 143 | next_x = next_x, 144 | node = node, 145 | next_node = next_node, 146 | fill = factor(node) 147 | , label = value 148 | )) + 149 | geom_sankey() + 150 | theme_sankey(base_size = 16) + geom_sankey_label() 151 | 152 | fig 153 | plotly::ggplotly(fig) 154 | 155 | 156 | library(plotly) 157 | 158 | fig <- plot_ly( 159 | type = "sankey", 160 | orientation = "h", 161 | 162 | node = list( 163 | label = c("A1", "A2", "B1", "B2", "C1", "C2"), 164 | color = c("blue", "blue", "blue", "blue", "blue", "blue"), 165 | pad = 15, 166 | thickness = 20, 167 | line = list( 168 | color = "black", 169 | width = 0.5 170 | ) 171 | ), 172 | 173 | link = list( 174 | source = c(0,1,0,2,3,3), 175 | target = c(2,3,3,4,4,5), 176 | value = c(8,4,2,8,4,2) 177 | ) 178 | ) 179 | fig <- fig %>% layout( 180 | title = "Basic Sankey Diagram", 181 | font = list( 182 | size = 10 183 | ) 184 | ) 185 | 186 | fig 187 | 188 | 189 | 190 | 191 | 192 | df_count <- df[, .(count = round(.N / nrow(df)*100, 2)), by= .(case_dani, case_rafa)] 193 | 194 | df_sankey <- ggsankey::make_long(df, case_dani, case_rafa) 195 | 196 | df_sankey <- left_join(df_sankey, df_count, 197 | by=c('node'='case_dani', 'next_node' = 'case_rafa')) 198 | 199 | 200 | head(df_sankey) 201 | 202 | #cats <- c(1:4, 44, 5:12) 203 | cats <- c(12:5, 44, 4:1) 204 | df_sankey$node <- factor(x = df_sankey$node, 205 | levels = cats, 206 | ordered = T) 207 | 208 | df_sankey$next_node <- factor(x = df_sankey$next_node, 209 | levels = cats, 210 | ordered = T) 211 | data.table::setDT(df_sankey)[, count2 := ifelse(is.na(count), lead(count), count)] 212 | head(df_sankey) 213 | 214 | fig <- ggplot(data = df_sankey, 215 | aes(x = x, 216 | next_x = next_x, 217 | node = node, 218 | next_node = next_node, 219 | fill = factor(node) 220 | , label = count2 221 | )) + 222 | geom_sankey() + 223 | theme_sankey(base_size = 16) + geom_sankey_label() 224 | 225 | fig 226 | plotly::ggplotly(fig) 227 | -------------------------------------------------------------------------------- /tests/tests_rafa/serch_nearby_addresses.R: -------------------------------------------------------------------------------- 1 | 2 | # Find cases nearby 3 | 4 | serch_nearby_addresses <- function(con, dist){ 5 | 6 | # update coordinates range 7 | margin_lat <- round(dist / 111320, digits = 8) 8 | # AND lon_max = lon + ({dist} * COS( lat * 0.017453 )) 9 | 10 | query_update_coords_range <- glue::glue( 11 | "UPDATE input_table_db 12 | SET lat_min = lat - {margin_lat}, 13 | lat_max = lat + {margin_lat}, 14 | lon_min = lon - (({dist} / 111320) * COS(lat)), 15 | lon_max = lon + (({dist} / 111320) * COS(lat));" 16 | ) 17 | 18 | DBI::dbExecute(con, query_update_coords_range) 19 | # a <- DBI::dbReadTable(con, 'input_table_db') 20 | 21 | # spatial search 22 | query_filter_cases_nearby <- glue::glue( 23 | "INSERT INTO output_db (tempidgeocodebr, lat_cnefe, lon_cnefe, endereco_completo, 24 | estado, municipio, logradouro, numero, cep, localidade) 25 | SELECT 26 | input_table_db.tempidgeocodebr, 27 | filtered_cnefe.lat AS lat_cnefe, 28 | filtered_cnefe.lon AS lon_cnefe, 29 | filtered_cnefe.endereco_completo, 30 | filtered_cnefe.estado, 31 | filtered_cnefe.municipio, 32 | filtered_cnefe.logradouro, 33 | filtered_cnefe.numero, 34 | filtered_cnefe.cep, 35 | filtered_cnefe.localidade 36 | FROM 37 | input_table_db, filtered_cnefe 38 | WHERE 39 | filtered_cnefe.lat BETWEEN input_table_db.lat_min AND input_table_db.lat_max 40 | AND filtered_cnefe.lon BETWEEN input_table_db.lon_min AND input_table_db.lon_max 41 | AND filtered_cnefe.lon IS NOT NULL;" 42 | ) 43 | 44 | # FROM input_table_db 45 | # LEFT JOIN filtered_cnefe 46 | # ON filtered_cnefe.lon BETWEEN input_table_db.lon_min AND input_table_db.lon_max 47 | # AND filtered_cnefe.lat BETWEEN input_table_db.lat_min AND input_table_db.lat_max 48 | # WHERE filtered_cnefe.lon IS NOT NULL;" 49 | 50 | DBI::dbExecute(con, query_filter_cases_nearby) 51 | # b <- DBI::dbReadTable(con, 'output_db') 52 | 53 | # a <- DBI::dbGetQuery(con, query_filter_cases_nearby) 54 | # data.table::setDT(a) 55 | # a[, distancia_metros := dt_haversine(lat,lon , lat_cnefe, lon_cnefe)] 56 | # summary(a$distancia_metros) 57 | 58 | 59 | # UPDATE input_padrao_db: Remove observations found in previous step 60 | temp_n <- update_input_db( 61 | con, 62 | update_tb = 'input_table_db', 63 | reference_tb = 'output_db' 64 | ) 65 | 66 | return(temp_n) 67 | } 68 | -------------------------------------------------------------------------------- /tests/tests_rafa/states_bbox.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(dplyr) 3 | 4 | # Load the state polygons 5 | df <- geobr::read_state() 6 | 7 | # Calculate bounding boxes of states 8 | bounding_boxes <- df |> 9 | st_as_sf() |> # Ensure df is an sf object 10 | rowwise() |> # Process each polygon individually 11 | mutate( 12 | xmin = st_bbox(geom)["xmin"], # Extract xmin from the bounding box 13 | ymin = st_bbox(geom)["ymin"], # Extract ymin from the bounding box 14 | xmax = st_bbox(geom)["xmax"], # Extract xmax from the bounding box 15 | ymax = st_bbox(geom)["ymax"] # Extract ymax from the bounding box 16 | ) |> 17 | ungroup() |> # Unrowwise after rowwise operations 18 | select(abbrev_state, xmin, ymin, xmax, ymax) |> # Select desired columns 19 | st_drop_geometry() 20 | 21 | # View the resulting bounding box data.frame 22 | bounding_boxes 23 | 24 | data.table::fwrite(bounding_boxes, './inst/extdata/states_bbox.csv') 25 | 26 | 27 | head(input_table) 28 | 29 | candidate_states <- 30 | subset(x = bounding_boxes, 31 | (xmin < bbox_lon_min | xmax > bbox_lon_max) & 32 | (ymin < bbox_lat_min | ymax > bbox_lat_max) 33 | ) 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/tests_rafa/test_rafa.R: -------------------------------------------------------------------------------- 1 | # date last modified chache 2 | library(httr2) 3 | 4 | 5 | # Send a HEAD request to get the headers only 6 | url <- 'https://sas.anac.gov.br/sas/tarifainternacional/2024/INTERNACIONAL_2024-06.csv' 7 | request <- httr2::request(url) 8 | 9 | response <- request %>% 10 | req_method("HEAD") %>% 11 | req_perform() 12 | 13 | # Check if the "Last-Modified" header is present 14 | if (!is.null(resp_header(response, "last-modified"))) { 15 | last_modified <- resp_header(response, "last-modified") 16 | print(paste("Last-Modified Date:", last_modified)) 17 | } else { 18 | print("The server did not provide a Last-Modified date.") 19 | } 20 | 21 | 22 | 23 | library(censobr) 24 | library(dplyr) 25 | library(arrow) 26 | 27 | df <- censobr::read_population(year = 2010, add_labels = 'pt') |> 28 | group_by(code_muni, V0601) |> 29 | summarise(pop = sum(V0010)) |> 30 | collect() |> 31 | tidyr::pivot_wider(id_cols = code_muni, 32 | names_from = V0601, 33 | values_from = pop) 34 | head(df) 35 | #> code_muni Masculino Feminino 36 | #> 37 | #> 1 1100015 12656. 11736. 38 | #> 2 1100023 45543. 44810. 39 | #> 3 1100031 3266. 3047 40 | #> 4 1100049 39124. 39450. 41 | #> 5 1100056 8551. 8478. 42 | #> 6 1100064 9330. 9261. 43 | 44 | 45 | 46 | 47 | 48 | # NEXT CHANGES --------------------------- 49 | # 50 | # #> using cache_dir and data_release as global variables 51 | # https://stackoverflow.com/questions/12598242/global-variables-in-packages-in-r 52 | # 53 | # censobr_env <- new.env() 54 | # censobr_env$data_release <- 'v0.1.0' 55 | # 56 | 57 | 58 | #> cache function delete data from previous package versions 59 | 60 | # current cache 61 | pkgv <- paste0('censobr_', 'v0.1.0' ) 62 | cache_dir <- tools::R_user_dir(pkgv, which = 'cache') 63 | 64 | # determine old cache 65 | dir_above <- dirname(cache_dir) 66 | all_cache <- list.files(dir_above, pattern = 'censobr',full.names = TRUE) 67 | old_cache <- all_cache[!grepl(pkgv, all_cache)] 68 | 69 | # delete 70 | unlink(old_cache, recursive = TRUE) 71 | 72 | 73 | library(censobr) 74 | 75 | censobr_cache(delete_file = 'all') 76 | 77 | interview_manual(year = 2010) 78 | interview_manual(year = 2000) 79 | interview_manual(year = 1991) # 80 | interview_manual(year = 1980) # 81 | interview_manual(year = 1970) 82 | 83 | 84 | 85 | # github actions ------------------------ 86 | 87 | usethis::use_github_action("test-coverage") 88 | usethis::use_github_action("check-standard") 89 | usethis::use_github_action("pkgdown") 90 | 91 | # Coverage ------------------------ 92 | # usethis::use_coverage() 93 | # usethis::use_github_action("test-coverage") 94 | 95 | library(testthat) 96 | library(covr) 97 | Sys.setenv(NOT_CRAN = "true") 98 | 99 | 100 | 101 | # each function separately 102 | t1 <- covr::function_coverage(fun=geocode, test_file("tests/testthat/test-geocode.R")) 103 | t1 <- covr::function_coverage(fun=definir_campos, test_file("tests/testthat/test-definir_campos.R")) 104 | t1 <- covr::function_coverage(fun=download_cnefe, test_file("tests/testthat/test-download_cnefe.R")) 105 | t1 <- covr::function_coverage(fun=listar_dados_cache, test_file("tests/testthat/test_cache.R")) 106 | t1 <- covr::function_coverage(fun=busca_por_cep, test_file("tests/testthat/test-busca_por_cep.R")) 107 | t1 <- covr::function_coverage(fun=geocodebr_message, test_file("tests/testthat/test-message.R")) 108 | 109 | t1 110 | 111 | 112 | 113 | # nocov start 114 | 115 | # nocov end 116 | 117 | # the whole package 118 | Sys.setenv(NOT_CRAN = "true") 119 | cov <- covr::package_coverage(path = ".", type = "tests", clean = FALSE) 120 | cov 121 | 122 | rep <- covr::report(t1) 123 | 124 | x <- as.data.frame(cov) 125 | covr::codecov( coverage = cov, token ='aaaaa' ) 126 | 127 | 128 | 129 | 130 | 131 | 132 | # checks spelling ---------------- 133 | library(spelling) 134 | devtools::spell_check(pkg = ".", vignettes = TRUE, use_wordlist = TRUE) 135 | 136 | 137 | ### Check URL's ---------------- 138 | 139 | urlchecker::url_update() 140 | 141 | 142 | 143 | 144 | 145 | # CMD Check -------------------------------- 146 | # Check package errors 147 | 148 | # linux ubuntu-clang for CRAN 149 | rhub::rhub_check(platforms = 'ubuntu-clang') 150 | 151 | # run only the tests 152 | Sys.setenv(NOT_CRAN = "true") 153 | testthat::test_local() 154 | 155 | # LOCAL 156 | Sys.setenv(NOT_CRAN = "true") 157 | devtools::check(pkg = ".", cran = FALSE, env_vars = c(NOT_CRAN = "true")) 158 | 159 | # detecta problema de cpu < 2 160 | devtools::check(remote = TRUE, manual = TRUE) 161 | 162 | devtools::check(remote = TRUE, manual = TRUE, env_vars = c(NOT_CRAN = "false")) 163 | 164 | 165 | # CRAN 166 | Sys.setenv(NOT_CRAN = "false") 167 | devtools::check(pkg = ".", cran = TRUE, env_vars = c(NOT_CRAN = "false")) 168 | 169 | 170 | # extrachecks ----------------- 171 | #' https://github.com/JosiahParry/extrachecks 172 | #' remotes::install_github("JosiahParry/extrachecks") 173 | 174 | library(extrachecks) 175 | extrachecks::extrachecks() 176 | 177 | 178 | # submit to CRAN ----------------- 179 | usethis::use_cran_comments() 180 | 181 | 182 | devtools::submit_cran() 183 | 184 | 185 | # build binary ----------------- 186 | system("R CMD build . --resave-data") # build tar.gz 187 | 188 | 189 | 190 | 191 | ### 192 | library(pkgdown) 193 | library(usethis) 194 | # usethis::use_pkgdown_github_pages() # only once 195 | ## coverage 196 | usethis::use_coverage() 197 | usethis::use_github_action("test-coverage") 198 | 199 | pkgdown::build_site() 200 | # 201 | # 202 | # ### cache 203 | # tigris 204 | # https://github.com/walkerke/tigris/blob/0f0d7992e0208b4c55a9fe8ac6c52f9e438a3b0c/R/helpers.R#L78 205 | # 206 | # https://github.com/walkerke/tigris/blob/0f0d7992e0208b4c55a9fe8ac6c52f9e438a3b0c/R/helpers.R#L78 207 | # 208 | # tidycensus 209 | # https://github.com/walkerke/tidycensus/blob/master/R/search_variables.R 210 | 211 | 212 | 213 | library(geobr) 214 | library(censobr) 215 | library(dplyr) 216 | library(ggplot2) 217 | 218 | fort_df <- geobr::lookup_muni(name_muni = 'Sao Paulo') 219 | fort_code <- fort_df$code_muni 220 | fort_wa <- read_weighting_area(code_weighting = fort_code, 221 | year = 2010, 222 | simplified = FALSE) 223 | 224 | 225 | 226 | ggplot() + 227 | geom_sf(data=fort_wa) 228 | 229 | 230 | # download household data 231 | hs <- read_households(year = 2010, 232 | showProgress = FALSE) 233 | 234 | 235 | rent <- hs |> 236 | mutate( V0011 = as.character(V0011)) |> 237 | filter(V0011 %in% fort_wa$code_weighting) |> 238 | collect() |> 239 | group_by(V0011) |> # (a) 240 | summarize(avgrent=weighted.mean(x=V2011, w=V0010, na.rm=TRUE)) |> # (b) 241 | collect() # (c) 242 | 243 | head(rent) 244 | 245 | 246 | for_sf <- left_join(fort_wa, rent, by = c('code_weighting'='V0011')) 247 | 248 | 249 | ggplot() + 250 | geom_sf(data=for_sf, aes(fill = avgrent), color=NA) 251 | 252 | 253 | 254 | 255 | 256 | 257 | # had CPU time 3 times elapsed time ---- 258 | # https://stackoverflow.com/questions/77323811/r-package-to-cran-had-cpu-time-5-times-elapsed-time 259 | 260 | # Flavor: r-devel-linux-x86_64-debian-gcc 261 | # Check: tests, Result: NOTE 262 | # Running 'testthat.R' [161s/53s] 263 | # Running R code in 'testthat.R' had CPU time 3 times elapsed time 264 | 265 | library(testthat) 266 | Sys.setenv(NOT_CRAN = "true") 267 | 268 | files = list.files("tests/testthat", "test-", full.names = TRUE) 269 | 270 | for (file in files[3]) { 271 | 272 | time = system.time(test_file(file)) 273 | ratio = time[1] / time[3] 274 | if (ratio > 2) { 275 | print(time) 276 | stopf("Test file %s had CPU time %f times elapsed time", file, ratio) 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /tests/tests_rafa/teste_geocodebr_1km.csv: -------------------------------------------------------------------------------- 1 | "NR_ZONA";"NM_LOCAL_VOTACAO";"DS_ENDERECO";"NM_BAIRRO";"NR_LATITUDE";"NR_LONGITUDE";"ggmap_lat";"ggmap_long";"LOGRADOURO";"NUMERO";"NR_CEP";"nm_municipio";"nm_uf";"lat";"lon";"tipo_resultado";"precisao";"distancia" 2 | "2";"COLÉGIO EQUIPE";"RUA SÃO VICENTE DE PAULA, 374";"SANTA CECILIA";"-23.5377813";"-46.6560177";"-23.537703472790675";"-46.65625962263844";"RUA SÃO VICENTE DE PAULA";"374";"01229010";"São Paulo";"SP";-23,616118;-46,592245;"ei04";"numero_aproximado";10867.84811856 3 | "247";"E.E. JOSÉ DE SAN MARTIN";"RUA DELTA, 79/A";"JARDIM NAIR";"-23.491203";"-46.455675";"-23.491188222846038";"-46.455442520271774";"RUA DELTA";NA;"08071060";"São Paulo";"SP";-23,518868;-46,486519;"er02";"logradouro";4412.21609580501 4 | "325";"EMEF. AMADEU MENDES";"RUA TOMAS LOPES FERREIRA, 110";"PARQUE SAO DOMINGOS";"-23.4997808";"-46.7382424";"-23.499833120828104";"-46.73792604899828";"RUA TOMAS LOPES FERREIRA";"110";"05125090";"São Paulo";"SP";-23,489362;-46,749044;"eb01";"localidade";1623.12028374795 5 | "346";"ESCOLA ESTADUAL ALBERTO TORRES";"AVENIDA VITAL BRASIL, 1260";"BUTANTA";"-23.5685674";"-46.7158643";"-23.56824401738893";"-46.715842894407054";"AVENIDA VITAL BRASIL";"1260";"05503000";"São Paulo";"SP";-23,571997;-46,706508;"ei01";"numero_aproximado";1039.64798625029 6 | "353";"EE AQUILINO RIBEIRO";"RUA ONOFRE LEITE MEIRELES, 1";"JARDIM SÃO PAULO (ZONA LESTE)";"-23.5625806";"-46.4059439";"-23.552698448616606";"-46.40880906675706";"RUA ONOFRE LEITE MEIRELES";"1";"08461620";"São Paulo";"SP";-23,562495;-46,405774;"ec02";"cep";1128.20447808882 7 | "381";"EE PROF. MARIO ARMINANTE";"RUA JOSÉ ROSCHEL RODRIGUES, 146";"RECANTO CAMPO BELO";"-23.7918";"-46.732";"-23.828470379886166";"-46.72406981166038";"RUA JOSÉ ROSCHEL RODRIGUES";"146";"04880130";"São Paulo";"SP";-23,790742;-46,732832;"ei01";"numero_aproximado";4272.88060147635 8 | "381";"EE AYRTON SENNA DA SILVA";"RUA IPÊ ROXO, 112";"COLONIA (ZONA SUL)";"-23.86103754";"-46.70676204";"-23.86115697017362";"-46.70717530403464";"RUA IPÊ ROXO";"112";"04896260";"São Paulo";"SP";-23,506251;-46,404497;"en04";"numero";49977.3824603582 9 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(geocodebr) 11 | library(sf) 12 | 13 | test_check("geocodebr") 14 | 15 | Sys.setenv(OMP_THREAD_LIMIT = 2) 16 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/cache.md: -------------------------------------------------------------------------------- 1 | # messages are formatted correctly 2 | 3 | Code 4 | definir_pasta_cache(path = NULL) 5 | Message 6 | i Definido como pasta de cache ''. 7 | 8 | --- 9 | 10 | Code 11 | definir_pasta_cache("aaa") 12 | Message 13 | i Definido como pasta de cache 'aaa'. 14 | 15 | # behaves correctly 16 | 17 | Code 18 | listar_dados_cache(print_tree = TRUE) 19 | Output 20 | 21 | +-- hello.parquet 22 | \-- oie.parquet 23 | 24 | # deletar_pasta_cache behaves correctly 25 | 26 | Code 27 | res <- deletar_pasta_cache() 28 | Message 29 | v Deletada a pasta de cache que se encontrava em ''. 30 | 31 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/definir_campos.md: -------------------------------------------------------------------------------- 1 | # errors when all fields are NULL 2 | 3 | Code 4 | tester() 5 | Condition 6 | Error in `definir_campos()`: 7 | ! Pelo menos um campo não pode ser nulo `NULL`. 8 | 9 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/download_cnefe.md: -------------------------------------------------------------------------------- 1 | # errors if could not download one or more files 2 | 3 | Code 4 | tester(cache = FALSE) 5 | Condition 6 | Error in `download_cnefe()`: 7 | ! Could not download one or more CNEFE data files. 8 | i Please try again later. 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/error.md: -------------------------------------------------------------------------------- 1 | # erro funciona corretamente 2 | 3 | Code 4 | parent_function() 5 | Condition 6 | Error in `parent_function()`: 7 | ! test 8 | * info 9 | 10 | -------------------------------------------------------------------------------- /tests/testthat/_snaps/message.md: -------------------------------------------------------------------------------- 1 | # message_works_correctly 2 | 3 | Code 4 | parent_function() 5 | Message 6 | * info 7 | 8 | -------------------------------------------------------------------------------- /tests/testthat/test-busca_por_cep.R: -------------------------------------------------------------------------------- 1 | # skip tests because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("arrow") 5 | 6 | 7 | ceps_valid <- c("70390-025", "20071-001", "99999-999") 8 | ceps_not_valid <- c("99999-999") 9 | 10 | 11 | tester <- function(cep, 12 | resultado_sf = FALSE, 13 | verboso = TRUE, 14 | cache = TRUE) { 15 | busca_por_cep( 16 | cep, 17 | resultado_sf, 18 | verboso, 19 | cache 20 | ) 21 | } 22 | 23 | test_that("expected output", { 24 | 25 | # expected results 26 | output <- tester(cep = ceps_valid) 27 | testthat::expect_true(nrow(output) == 5) 28 | 29 | # expected class 30 | testthat::expect_s3_class(output, 'data.frame') 31 | 32 | # output in sf format 33 | sf_output <- tester(cep = ceps_valid, resultado_sf = TRUE) 34 | testthat::expect_true(is(sf_output , 'sf')) 35 | }) 36 | 37 | 38 | 39 | test_that("errors with incorrect input", { 40 | expect_error(tester(unclass(ceps_not_valid))) 41 | 42 | expect_error(tester(cep = 1)) 43 | expect_error(tester(cep = 'banana')) 44 | expect_error(tester(cep = ceps_not_valid)) 45 | 46 | expect_error(tester(resultado_completo = 1)) 47 | expect_error(tester(resultado_completo = NA)) 48 | expect_error(tester(resultado_completo = c(TRUE, TRUE))) 49 | 50 | expect_error(tester(resultado_sf = 1)) 51 | expect_error(tester(resultado_sf = NA)) 52 | expect_error(tester(resultado_sf = c(TRUE, TRUE))) 53 | 54 | expect_error(tester(verboso = 1)) 55 | expect_error(tester(verboso = NA)) 56 | expect_error(tester(verboso = c(TRUE, TRUE))) 57 | 58 | expect_error(tester(cache = 1)) 59 | expect_error(tester(cache = NA)) 60 | expect_error(tester(cache = c(TRUE, TRUE))) 61 | }) 62 | 63 | -------------------------------------------------------------------------------- /tests/testthat/test-cache.R: -------------------------------------------------------------------------------- 1 | # skip tests because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("arrow") 5 | 6 | cache_config_file <- geocodebr:::listar_arquivo_config() 7 | default_cache_dir <- geocodebr:::listar_pasta_cache_padrao() 8 | 9 | # definir_pasta_cache ----------------------------------------------------------- 10 | 11 | tester <- function(path = NULL) definir_pasta_cache(path) 12 | 13 | test_that("errors with incorrect input", { 14 | expect_error(tester(1)) 15 | expect_error(tester(c("aaa", "bbb"))) 16 | expect_error(tester(path)) 17 | 18 | }) 19 | 20 | test_that("behaves correctly", { 21 | # if the cache config file exists, we save its current content just to make 22 | # sure our tests don't disturb any workflows we have. if it doesn't, we delete 23 | # the file we created during the test 24 | 25 | if (fs::file_exists(cache_config_file)) { 26 | config_file_content <- readLines(cache_config_file) 27 | on.exit(writeLines(config_file_content, cache_config_file), add = TRUE) 28 | } else { 29 | on.exit(fs::file_delete(cache_config_file), add = TRUE) 30 | } 31 | 32 | # by default uses a versioned dir inside the default R cache dir 33 | 34 | fn_result <- suppressMessages(definir_pasta_cache(path = NULL)) 35 | expect_type(fn_result, "character") 36 | expect_identical(fn_result, as.character(default_cache_dir)) 37 | expect_identical(readLines(cache_config_file), unclass(default_cache_dir)) 38 | 39 | fn_result <- suppressMessages(definir_pasta_cache("aaa")) 40 | expect_type(fn_result, "character") 41 | expect_identical(fn_result, "aaa") 42 | expect_identical(readLines(cache_config_file), "aaa") 43 | }) 44 | 45 | test_that("messages are formatted correctly", { 46 | if (fs::file_exists(cache_config_file)) { 47 | config_file_content <- readLines(cache_config_file) 48 | on.exit(writeLines(config_file_content, cache_config_file), add = TRUE) 49 | } else { 50 | on.exit(fs::file_delete(cache_config_file), add = TRUE) 51 | } 52 | 53 | expect_snapshot( 54 | definir_pasta_cache(path = NULL), 55 | transform = function(x) sub(default_cache_dir, "", x), 56 | cnd_class = TRUE 57 | ) 58 | 59 | expect_snapshot(definir_pasta_cache("aaa"), cnd_class = TRUE) 60 | }) 61 | 62 | # listar_pasta_cache ----------------------------------------------------------- 63 | 64 | test_that("behaves correctly", { 65 | # if the cache config file exists, we save its current content just to make 66 | # sure our tests don't disturb any workflows we have. if it doesn't, we delete 67 | # the file we created during the test 68 | 69 | if (fs::file_exists(cache_config_file)) { 70 | config_file_content <- readLines(cache_config_file) 71 | on.exit(writeLines(config_file_content, cache_config_file), add = TRUE) 72 | } else { 73 | on.exit(fs::file_delete(cache_config_file), add = TRUE) 74 | } 75 | 76 | # if the cache config file exists, return its content. otherwise, returns the 77 | # default cache dir 78 | 79 | if (fs::file_exists(cache_config_file)) fs::file_delete(cache_config_file) 80 | expect_identical(listar_pasta_cache(), as.character(default_cache_dir)) 81 | 82 | writeLines("aaa", cache_config_file) 83 | expect_identical(listar_pasta_cache(), "aaa") 84 | }) 85 | 86 | # listar_dados_cache -------------------------------------------------------- 87 | 88 | test_that("errors with incorrect input", { 89 | expect_error(listar_dados_cache(1)) 90 | expect_error(listar_dados_cache(NA)) 91 | expect_error(listar_dados_cache(c(TRUE, TRUE))) 92 | }) 93 | 94 | test_that("behaves correctly", { 95 | # if the cache config file exists, we save its current content just to make 96 | # sure our tests don't disturb any workflows we have. if it doesn't, we delete 97 | # the file we created during the test 98 | 99 | if (fs::file_exists(cache_config_file)) { 100 | config_file_content <- readLines(cache_config_file) 101 | on.exit(writeLines(config_file_content, cache_config_file), add = TRUE) 102 | } else { 103 | on.exit(fs::file_delete(cache_config_file), add = TRUE) 104 | } 105 | 106 | # we set the cache dir to a temporary directory to not mess with any cached 107 | # data we may already have 108 | 109 | tmpdir <- tempfile() 110 | fs::dir_create(tmpdir) 111 | 112 | suppressMessages(definir_pasta_cache(tmpdir)) 113 | 114 | expect_identical(listar_dados_cache(), character(0)) 115 | 116 | # previously, we used download_cnefe(progress = FALSE) here to download cnefe 117 | # data before listing the content. however, this takes a long time, and 118 | # afterall we only need to make sure that the function lists whatever files we 119 | # have in the directory. so we create empty temp files to test if the function 120 | # is working 121 | 122 | file.create(fs::path(tmpdir, c("oie.parquet", "hello.parquet"))) 123 | 124 | cnefe_files <- listar_dados_cache() 125 | expect_identical(basename(cnefe_files), c("hello.parquet", "oie.parquet")) 126 | 127 | # expect a tree-like message and invisible value when print_tree=TRUE 128 | 129 | expect_snapshot( 130 | listar_dados_cache(print_tree = TRUE), 131 | transform = function(x) sub(listar_pasta_cache(), "", x) 132 | ) 133 | }) 134 | 135 | # deletar_pasta_cache --------------------------------------------------------- 136 | 137 | test_that("deletar_pasta_cache behaves correctly", { 138 | # if the cache config file exists, we save its current content just to make 139 | # sure our tests don't disturb any workflows we have. if it doesn't, we delete 140 | # the file we created during the test 141 | 142 | if (fs::file_exists(cache_config_file)) { 143 | config_file_content <- readLines(cache_config_file) 144 | on.exit(writeLines(config_file_content, cache_config_file), add = TRUE) 145 | } else { 146 | on.exit(fs::file_delete(cache_config_file), add = TRUE) 147 | } 148 | 149 | # we set the cache dir to a temporary directory to not mess with any cached 150 | # data we may already have 151 | 152 | tmpdir <- tempfile() 153 | fs::dir_create(tmpdir) 154 | 155 | suppressMessages(definir_pasta_cache(tmpdir)) 156 | 157 | file.create(fs::path(tmpdir, "oie.parquet")) 158 | expect_identical(basename(listar_dados_cache()), "oie.parquet") 159 | 160 | expect_snapshot( 161 | res <- deletar_pasta_cache(), 162 | cnd_class = TRUE, 163 | transform = function(x) sub(listar_pasta_cache(), "", x) 164 | ) 165 | 166 | expect_identical(res, as.character(fs::path_norm(tmpdir))) 167 | expect_false(dir.exists(res)) 168 | }) 169 | -------------------------------------------------------------------------------- /tests/testthat/test-definir_campos.R: -------------------------------------------------------------------------------- 1 | tester <- function(logradouro = NULL, 2 | numero = NULL, 3 | cep = NULL, 4 | localidade = NULL, 5 | municipio = NULL, 6 | estado = NULL) { 7 | definir_campos( 8 | logradouro, 9 | numero, 10 | cep, 11 | localidade, 12 | municipio, 13 | estado 14 | ) 15 | } 16 | 17 | test_that("definir_campos expected behavior", { 18 | 19 | testthat::expect_vector( 20 | test <- tester( 21 | logradouro = 'nm_logradouro', 22 | numero = 'Numero', 23 | cep = 'Cep', 24 | localidade = 'Bairro', 25 | municipio = 'nm_municipio', 26 | estado = 'nm_uf') 27 | ) 28 | 29 | testthat::expect_true( 30 | all(names(test) == c("logradouro","numero", "cep", 31 | "localidade", "municipio", "estado")) 32 | ) 33 | 34 | 35 | }) 36 | 37 | test_that("errors with incorrect input", { 38 | expect_error(tester(logradouro = 1)) 39 | expect_error(tester(logradouro = c("aaa", "bbb"))) 40 | 41 | expect_error(tester(numero = 1)) 42 | expect_error(tester(numero = c("aaa", "bbb"))) 43 | 44 | expect_error(tester(cep = 1)) 45 | expect_error(tester(cep = c("aaa", "bbb"))) 46 | 47 | expect_error(tester(localidade = 1)) 48 | expect_error(tester(localidade = c("aaa", "bbb"))) 49 | 50 | expect_error(tester(municipio = 1)) 51 | expect_error(tester(municipio = c("aaa", "bbb"))) 52 | 53 | expect_error(tester(estado = 1)) 54 | expect_error(tester(estado = c("aaa", "bbb"))) 55 | }) 56 | 57 | test_that("errors when all fields are NULL", { 58 | expect_error(tester(), class = "geocodebr_error_null_address_fields") 59 | 60 | expect_snapshot(tester(), error = TRUE, cnd_class = TRUE) 61 | }) 62 | 63 | # test_that("returns a character vector", { 64 | # expect_identical( 65 | # tester( 66 | # logradouro = "Nome_logradouro", 67 | # numero = "Numero", 68 | # cep = "CEP", 69 | # localidade = "Bairro", 70 | # municipio = "Cidade", 71 | # estado = "UF" 72 | # ), 73 | # c( 74 | # logradouro = "Nome_logradouro", 75 | # numero = "Numero", 76 | # cep = "CEP", 77 | # localidade = "Bairro", 78 | # municipio = "Cidade", 79 | # estado = "UF" 80 | # ) 81 | # ) 82 | # 83 | # expect_identical( 84 | # tester(logradouro = "oi", numero = "ola"), 85 | # c(logradouro = "oi", numero = "ola") 86 | # ) 87 | # }) 88 | -------------------------------------------------------------------------------- /tests/testthat/test-download_cnefe.R: -------------------------------------------------------------------------------- 1 | # skip tests because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("arrow") 5 | 6 | 7 | tester <- function(tabela = "todas", verboso = TRUE, cache = TRUE) { 8 | download_cnefe(tabela, verboso, cache) 9 | } 10 | 11 | test_that("errors with incorrect input", { 12 | expect_error(tester(tabela = 'banana')) 13 | expect_error(tester(tabela = 1)) 14 | expect_error(tester(tabela = NA)) 15 | expect_error(tester(tabela = c(TRUE, TRUE))) 16 | 17 | expect_error(tester(verboso = 1)) 18 | expect_error(tester(verboso = NA)) 19 | expect_error(tester(verboso = c(TRUE, TRUE))) 20 | 21 | expect_error(tester(cache = 1)) 22 | expect_error(tester(cache = NA)) 23 | expect_error(tester(cache = c(TRUE, TRUE))) 24 | }) 25 | 26 | test_that("returns the path to the directory where the files were saved", { 27 | result <- tester() 28 | expect_identical(result, file.path(listar_pasta_cache())) 29 | 30 | result <- tester(tabela = "municipio_cep") 31 | expect_identical(result, file.path(listar_pasta_cache())) 32 | 33 | }) 34 | 35 | test_that("cache usage is controlled by the cache argument", { 36 | result <- tester(cache = TRUE) 37 | expect_identical(result, file.path(listar_pasta_cache())) 38 | 39 | # using a mocked binding for perform_requests_in_parallel here just to save us 40 | # some time. as long as none of its elements is a failed request, the funtion 41 | # will make download_files return the path to the files that would be 42 | # downloaded, which is basically what we want to test here 43 | 44 | local_mocked_bindings( 45 | perform_requests_in_parallel = function(...) TRUE 46 | ) 47 | 48 | result <- tester(cache = FALSE) 49 | expect_true( 50 | grepl(file.path(fs::path_norm(tempdir()), "standardized_cnefe"), result) 51 | ) 52 | }) 53 | 54 | test_that("errors if could not download one or more files", { 55 | local_mocked_bindings( 56 | perform_requests_in_parallel = function(...) { 57 | httr2::req_perform_parallel( 58 | list(httr2::request("FAILURE")), 59 | on_error = "continue" 60 | ) 61 | } 62 | ) 63 | 64 | expect_error( 65 | tester(cache = FALSE), 66 | class = "geocodebr_error_cnefe_download_failed" 67 | ) 68 | 69 | expect_snapshot(tester(cache = FALSE), error = TRUE, cnd_class = TRUE) 70 | }) 71 | -------------------------------------------------------------------------------- /tests/testthat/test-error.R: -------------------------------------------------------------------------------- 1 | parent_function <- function() error_test() 2 | 3 | error_test <- function() { 4 | geocodebr_error(c("test", "*" = "info"), call = rlang::caller_env()) 5 | } 6 | 7 | test_that("erro funciona corretamente", { 8 | expect_error(parent_function(), class = "geocodebr_error_test") 9 | expect_error(parent_function(), class = "geocodebr_error") 10 | 11 | expect_snapshot(parent_function(), error = TRUE, cnd_class = TRUE) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-geocode.R: -------------------------------------------------------------------------------- 1 | # skip tests because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("arrow") 5 | 6 | 7 | data_path <- system.file("extdata/small_sample.csv", package = "geocodebr") 8 | input_df <- read.csv(data_path) 9 | 10 | campos <- definir_campos( 11 | logradouro = "nm_logradouro", 12 | numero = "Numero", 13 | cep = "Cep", 14 | localidade = "Bairro", 15 | municipio = "nm_municipio", 16 | estado = "nm_uf" 17 | ) 18 | 19 | tester <- function(enderecos = input_df, 20 | campos_endereco = campos, 21 | resultado_completo = FALSE, 22 | resolver_empates = FALSE, 23 | resultado_sf = FALSE, 24 | verboso = FALSE, 25 | cache = TRUE, 26 | n_cores = 1) { 27 | geocode( 28 | enderecos, 29 | campos_endereco, 30 | resultado_completo, 31 | resolver_empates, 32 | resultado_sf, 33 | verboso, 34 | cache, 35 | n_cores 36 | ) 37 | } 38 | 39 | test_that("expected output", { 40 | testthat::expect_warning(std_output <- tester()) 41 | 42 | # find expected match cases 43 | match_types_found <- unique(std_output$tipo_resultado) 44 | testthat::expect_true(length(match_types_found) == 17) 45 | 46 | # full results 47 | testthat::expect_warning(full_output <- tester(resultado_completo = TRUE)) 48 | testthat::expect_true('endereco_encontrado' %in% names(full_output)) 49 | 50 | # output in sf format 51 | testthat::expect_warning(sf_output <- tester(resultado_sf = TRUE)) 52 | testthat::expect_true(is(sf_output , 'sf')) 53 | }) 54 | 55 | 56 | test_that("test empates", { 57 | 58 | # com empates 59 | testthat::expect_warning( std_output <- tester(resolver_empates = FALSE) ) 60 | testthat::expect_true(nrow(std_output) > nrow(input_df)) 61 | 62 | # resolvendo empates 63 | testthat::expect_message( std_output <- tester(verboso = TRUE, resolver_empates = TRUE) ) 64 | testthat::expect_true(nrow(std_output) == nrow(input_df)) 65 | 66 | # output ordenado como input 67 | testthat::expect_true( all(std_output$id == 1:nrow(input_df)) ) 68 | 69 | }) 70 | 71 | test_that("test no messages", { 72 | 73 | testthat::expect_no_message( 74 | testthat::expect_warning( 75 | std_output <- tester(verboso = FALSE, 76 | resolver_empates = FALSE) 77 | )) 78 | 79 | testthat::expect_no_message( std_output <- tester(verboso = FALSE, 80 | resolver_empates = TRUE) 81 | ) 82 | }) 83 | 84 | 85 | test_that("errors with incorrect input", { 86 | expect_error(tester(unclass(input_df))) 87 | 88 | expect_error(tester(campos_endereco = 1)) 89 | expect_error(tester(campos_endereco = c(hehe = "nm_logradouro"))) 90 | expect_error(tester(campos_endereco = c(logradouro = "hehe"))) 91 | 92 | expect_error(tester(resultado_completo = 1)) 93 | expect_error(tester(resultado_completo = NA)) 94 | expect_error(tester(resultado_completo = c(TRUE, TRUE))) 95 | 96 | expect_error(tester(resolver_empates = 1)) 97 | expect_error(tester(resolver_empates = NA)) 98 | expect_error(tester(resolver_empates = c(TRUE, TRUE))) 99 | 100 | expect_error(tester(resultado_sf = 1)) 101 | expect_error(tester(resultado_sf = NA)) 102 | expect_error(tester(resultado_sf = c(TRUE, TRUE))) 103 | 104 | expect_error(tester(n_cores = "a")) 105 | expect_error(tester(n_cores = 0)) 106 | expect_error(tester(n_cores = Inf)) 107 | 108 | expect_error(tester(verboso = 1)) 109 | expect_error(tester(verboso = NA)) 110 | expect_error(tester(verboso = c(TRUE, TRUE))) 111 | 112 | expect_error(tester(cache = 1)) 113 | expect_error(tester(cache = NA)) 114 | expect_error(tester(cache = c(TRUE, TRUE))) 115 | }) 116 | 117 | -------------------------------------------------------------------------------- /tests/testthat/test-geocode_reverso.R: -------------------------------------------------------------------------------- 1 | # skip tests because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("arrow") 5 | 6 | 7 | # amostra de pontos espaciais 8 | points <- readRDS( 9 | system.file("extdata/pontos.rds", package = "geocodebr") 10 | ) 11 | 12 | points <- points[1:10,] 13 | 14 | 15 | tester <- function(pontos = points, 16 | dist_max = 1000, 17 | verboso = FALSE, 18 | cache = TRUE, 19 | n_cores = 1) { 20 | geocode_reverso( 21 | pontos = pontos, 22 | dist_max = dist_max, 23 | verboso = verboso, 24 | cache = cache, 25 | n_cores =n_cores 26 | ) 27 | } 28 | 29 | test_that("expected output", { 30 | 31 | # radio de busca de 1 Km 32 | testthat::expect_no_failure(std_output <- tester()) 33 | testthat::expect_true(nrow(std_output) == 1) 34 | 35 | # radio de busca de 5 Km 36 | testthat::expect_no_failure(std_output_5K <- tester(dist_max = 5000)) 37 | testthat::expect_true(nrow(std_output_5K) == 7) 38 | 39 | # output in sf format 40 | testthat::expect_true(is(std_output , 'sf')) 41 | }) 42 | 43 | 44 | 45 | 46 | 47 | test_that("errors with incorrect input", { 48 | 49 | # input nao eh sf 50 | testthat::expect_error(tester(unclass(points))) 51 | 52 | # input tem geometry diferente de POINT 53 | testthat::expect_error( tester(pontos = sf::st_cast(points, "LINESTRING")) ) 54 | 55 | # input na projecao espacial errada 56 | testthat::expect_error(tester(sf::st_transform(points, 4326))) 57 | 58 | # input fora do bbox do Brazil 59 | p <- sf::st_sfc(sf::st_point(c(53.12682, 25.61657))) 60 | p <- sf::st_sf(p) 61 | sf::st_crs(p) <- 4674 62 | testthat::expect_error(tester(p)) 63 | 64 | 65 | 66 | testthat::expect_error(tester(dist_max = 'A')) 67 | testthat::expect_error(tester(dist_max = NA)) 68 | testthat::expect_error(tester(dist_max = TRUE)) 69 | 70 | testthat::expect_error(tester(n_cores = "a")) 71 | testthat::expect_error(tester(n_cores = 0)) 72 | testthat::expect_error(tester(n_cores = Inf)) 73 | 74 | testthat::expect_error(tester(verboso = 1)) 75 | testthat::expect_error(tester(verboso = NA)) 76 | testthat::expect_error(tester(verboso = c(TRUE, TRUE))) 77 | 78 | testthat::expect_error(tester(cache = 1)) 79 | testthat::expect_error(tester(cache = NA)) 80 | testthat::expect_error(tester(cache = c(TRUE, TRUE))) 81 | }) 82 | 83 | -------------------------------------------------------------------------------- /tests/testthat/test-message.R: -------------------------------------------------------------------------------- 1 | parent_function <- function() message_test() 2 | 3 | message_test <- function() geocodebr_message(c("*" = "info")) 4 | 5 | test_that("message_works_correctly", { 6 | expect_message(parent_function(), class = "geocodebr_message_test") 7 | expect_message(parent_function(), class = "geocodebr_message") 8 | 9 | expect_snapshot(parent_function(), cnd_class = TRUE) 10 | 11 | expect_message(message_standardizing_addresses()) 12 | expect_message(message_baixando_cnefe()) 13 | expect_message(message_looking_for_matches()) 14 | expect_message(message_preparando_output()) 15 | }) 16 | 17 | 18 | # error 19 | test_that("message_does_NOT_work_correctly", { 20 | expect_error(message_test("banana")) 21 | }) 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /vignettes/geocode.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Geocode" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Geocode} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | # CRAN OMP THREAD LIMIT to avoid CRAN NOTE 22 | Sys.setenv(OMP_THREAD_LIMIT = 2) 23 | ``` 24 | 25 | ## Geolocalização: de endereços para coordenadas espaciais 26 | 27 | A principal função do pacote {geocodebr} é a `geocode()`, que recebe uma tabela 28 | (`data.frame`) de endereços como entrada e retorna a mesma tabela geolocalizada 29 | como saída. Para demonstrar essa função, utilizamos no exemplo abaixo pequeno 30 | conjunto de dados que contém endereços com problemas comuns, como informações 31 | ausentes e campos digitados incorretamente. 32 | 33 | A geolocalização desses dados com **{geocodebr}** pode ser feita em apenas dois 34 | passos: 35 | 36 | 1. O primeiro passo é usar a função `definir_campos()` para indicar os nomes das 37 | colunas no seu `data.frame` que correspondem a cada campo dos endereços. No 38 | exemplo abaixo, nós indicamos que coluna que contém a informação de logradouro se 39 | chama `"nm_logradouro"`, que a coluna de número se chama `"Numero"`, etc. 40 | 41 | obs. Note que as colunas indicando o `"estado"` e `"município"` são obrigatórias. 42 | 43 | ```{r} 44 | library(geocodebr) 45 | 46 | # leitura de amostra de dados 47 | ends <- read.csv(system.file("extdata/small_sample.csv", package = "geocodebr")) 48 | 49 | # definição dos campos de endereço 50 | campos <- definir_campos( 51 | estado = "nm_uf", 52 | municipio = "nm_municipio", 53 | logradouro = "nm_logradouro", 54 | numero = "Numero", 55 | cep = "Cep", 56 | localidade = "Bairro" 57 | ) 58 | ``` 59 | 60 | 61 | 2. O segundo passo é usar a função `geocode()` para encontrar as coordenadas 62 | geográficas dos dados de input. 63 | 64 | **Nota:** A função `geocode()` requer que os dados do CNEFE estejam armazenados 65 | localmente. A primeita vez que a função é executada, ela baixa os dados do CNEFE 66 | e salva em um cache local na sua máquina. No total, esses dados somam cerca de 67 | 3 GB, o que pode fazer com que a primeira execução da função demore. Esses dados, 68 | no entanto, são salvos de forma persistente, logo eles são baixados uma única vez. 69 | Mais informações sobre o cache de dados [aqui](https://ipeagit.github.io/geocodebr/articles/geocodebr.html#cache-de-dados). 70 | 71 | ```{r} 72 | # geolicalização 73 | ends_geo <- geocode( 74 | enderecos = ends, 75 | campos_endereco = campos, 76 | resultado_completo = FALSE, 77 | resolver_empates = TRUE, 78 | resultado_sf = FALSE, 79 | verboso = FALSE 80 | ) 81 | 82 | head(ends_geo) 83 | ``` 84 | 85 | 86 | Por padrão, a tabela de *output* é igual à tabela de input do usuário acrescida de colunas com a latitude e longitude encontradas, bem como de colunas indicando o nível de precisão dos resultados e o endereço encontrado. Quando `resultado_completo = TRUE`, o output é acrescido de algumas colunas extras. 87 | 88 | Cabe também destacar aqui outros dois argumentos da função `geocode()`: 89 | 90 | - `resolver_empates`: serve para indicar se o usuário quer que a função resolva automaticamente casos de empate, i.e. casos que o endereço de input do usuário 91 | pode se referir a diferentes localidades na cidade (e.g. logradouros diferentes 92 | com mesmo nome mas em bairros distintos). Quando `TRUE`, a função resolve os 93 | empates selecioando os endereços com maior número de visitas do CNEFE. Quando 94 | `FALSE`, a função retorna todos os resultados indicando os casos empatados na 95 | coluna 'empate' para que o usuário possa inspecionar cada caso coluna 'endereco_encontrado'. 96 | - `resultado_sf`: quando `TRUE`, o output é retornado como um objeto espacial de classe `sf` simple feature. 97 | 98 | As coordendas espaciais do resultado usam o sistema de referência SIRGAS2000 99 | (EPSG 4674.), padrão adotado pelo IBGE em todo o Brasil. Cada par de coordenadas encontrado pode ser classificado conforme o seu grau de precisão (coluna 100 | `precisao`) e os campos do endereço utilizados para encontrá-lo (`tipo_resultado`). 101 | A seção a seguir apresenta mais informações sobre essas colunas. 102 | 103 | 104 | ### Grau de precisão dos resultados 105 | 106 | As coordenadas incluídas no resultado da `geocode()` são calculadas a partir da 107 | média das coordenadas dos endereços do CNEFE que correspondem a cada um dos 108 | endereços de *input*. A correspondência entre os endereços de entrada e os do 109 | CNEFE pode ser feita com base em diferentes combinações de campos, impactando, 110 | assim, na precisão do resultado retornado. 111 | 112 | No caso mais rigoroso, a função encontra uma correspondência determinística para 113 | cada um dos campos do endereço (estado, município, logradouro, número, CEP e 114 | localidade). Pense, por exemplo, em um prédio com vários apartamentos, cuja 115 | única variação no endereço se dá a nível de apartamento: o resultado, nesse 116 | caso, é a média das coordenadas dos apartamentos, que podem diferir 117 | ligeiramente. 118 | 119 | Em um caso menos rigoroso, no qual são encontradas correspondências apenas para 120 | os campos de estado, município, logradouro e localidade, a função calcula as 121 | coordenadas médias de todos os endereços do CNEFE que se encontram na mesma rua 122 | e na mesma localidade. O resultado, portanto, é agregado a nível de rua, 123 | tendendo para a extremidade do logradouro com maior concentração de endereços. 124 | 125 | A coluna `precisao` se refere ao nível de agregação das coordenadas do CNEFE 126 | utilizadas pela `geocode()`. A função sempre retorna o resultado de maior 127 | precisão possível - ou seja, ela só vai procurar endereços com precisão 128 | `"numero_aproximado"` (ver a seguir) caso não tenha encontrado correspondência 129 | de precisão `"numero"`. As coordenadas calculadas podem ser classificadas em 130 | seis diferentes categorias de precisão: 131 | 132 | 1. `"numero"` - calculadas a partir de endereços que compartilham o mesmo 133 | logradouro e número; 134 | 2. `"numero_aproximado"` - calculadas a partir de endereços que compartilham o 135 | mesmo logradouro, mas número de *input* não encontra correspondência exata no 136 | CNEFE e sua localização é calculada a partir de uma interpolação espacial; 137 | 3. `"logradouro"` - calculadas a partir de endereços que compartilham o mesmo 138 | logradouro (número de *input* está ausente ou é S/N); 139 | 4. `"cep"` - calculadas a partir de endereços que compartilham o mesmo CEP; 140 | 5. `"localidade"` - calculadas a partir de endereços que compartilham a mesma 141 | localidade; 142 | 6. `"municipio"` - calculadas a partir de endereços que compartilham o mesmo 143 | município. 144 | 145 | A coluna `tipo_resultado` fornece informações mais detalhadas sobre os campos de 146 | endereço utilizados no cálculo das coordenadas de cada endereço de entrada. Cada 147 | categoria é nomeada a partir de um código de quatro caracteres: 148 | 149 | - o primeiro, sempre `d` ou `p`, determina se a correspondência foi feita de 150 | forma determinística (`d`) ou probabilística (`p`); 151 | - o segundo faz menção à categoria de `precisao` na qual o resultado foi 152 | classificado (`n` para `"numero"`, `a` para `"numero_aproximado"`, `l` para 153 | `"logradouro"`, `c` para `"cep"`, `b` para `"localidade"` e `m` para 154 | `"municipio"`); 155 | - o terceiro e o quarto designam a classificação de cada categoria dentro de seu 156 | grupo - via de regra, quanto menor o número formado por esses caracteres, mais 157 | precisa são as coordenadas calculadas. 158 | 159 | As categorias de `tipo_resultado` são listadas abaixo, junto às categorias de 160 | `precisao` a qual elas estão associadas: 161 | 162 | - precisao `"numero"` 163 | - `dn01` - logradouro, numero, cep e localidade 164 | - `dn02` - logradouro, numero e cep 165 | - `dn03` - logradouro, numero e localidade 166 | - `dn04` - logradouro e numero 167 | - `pn01` - logradouro, numero, cep e localidade 168 | - `pn02` - logradouro, numero e cep 169 | - `pn03` - logradouro, numero e localidade 170 | - `pn04` - logradouro e numero 171 | 172 | - precisao `"numero_aproximado"` 173 | - `da01` - logradouro, numero, cep e localidade 174 | - `da02` - logradouro, numero e cep 175 | - `da03` - logradouro, numero e localidade 176 | - `da04` - logradouro e numero 177 | - `pa01` - logradouro, numero, cep e localidade 178 | - `pa02` - logradouro, numero e cep 179 | - `pa03` - logradouro, numero e localidade 180 | - `pa04` - logradouro e numero 181 | 182 | - precisao `"logradouro"` (quando o número de entrada está faltando 'S/N') 183 | - `dl01` - logradouro, cep e localidade 184 | - `dl02` - logradouro e cep 185 | - `dl03` - logradouro e localidade 186 | - `dl04` - logradouro 187 | - `pl01` - logradouro, cep e localidade 188 | - `pl02` - logradouro e cep 189 | - `pl03` - logradouro e localidade 190 | - `pl04` - logradouro 191 | 192 | - precisao `"cep"` 193 | - `dc01` - municipio, cep, localidade 194 | - `dc02` - municipio, cep 195 | 196 | - precisao `"localidade"` 197 | - `db01` - municipio, localidade 198 | 199 | - precisao `"municipio"` 200 | - `dm01` - municipio 201 | 202 | Endereços não encontrados são retornados com latitude, longitude, precisão e tipo de resultado `NA`. 203 | -------------------------------------------------------------------------------- /vignettes/geocode_reverso.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Geocode reverso" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Geocode reverso} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | # CRAN OMP THREAD LIMIT to avoid CRAN NOTE 22 | Sys.setenv(OMP_THREAD_LIMIT = 2) 23 | ``` 24 | 25 | # Geolocalização reversa: de coordenadas espaciais para endereços 26 | 27 | A função `geocode_reverso()` permite fazer geolocalização reversa, isto é, a partir de um conjunto de coordenadas geográficas, encontrar os endereços correspondentes ou próximos. Essa funcionalidade pode ser útil, por exemplo, para identificar endereços próximos a pontos de interesse, como escolas, hospitais, ou locais de acidentes. 28 | 29 | A função recebe como *input* um objeto espacial `sf` com geometria do tipo `POINT`. O resultado é um *data frame* com o endereço encontrado mais próximo de cada ponto de *input*, onde a coluna `"distancia_metros"` indica a distância entre coordenadas originais e os endereços encontrados. 30 | 31 | 32 | ```{r} 33 | library(geocodebr) 34 | library(sf) 35 | 36 | # amostra de pontos espaciais 37 | pontos <- readRDS( 38 | system.file("extdata/pontos.rds", package = "geocodebr") 39 | ) 40 | 41 | pontos <- pontos[1:20,] 42 | 43 | # geocode reverso 44 | df_enderecos <- geocodebr::geocode_reverso( 45 | pontos = pontos, 46 | dist_max = 1000, 47 | verboso = FALSE, 48 | n_cores = 1 49 | ) 50 | 51 | head(df_enderecos) 52 | ``` 53 | 54 | Por padrão, a função busca pelo endereço mais próximo num raio aproximado de 1000 metros. No entanto, o usuário pode ajustar esse valor usando o parâmetro `dist_max` para definir a distância máxima (em metros) de busca. Se um ponto de *input* não tiver nenhum endereço próximo dentro do raio de busca, o ponto não é incluído no *output*. 55 | 56 | **Nota:** A função `geocode_reverso()` requer que os dados do CNEFE estejam armazenados 57 | localmente. A primeita vez que a função é executada, ela baixa os dados do CNEFE 58 | e salva em um cache local na sua máquina. No total, esses dados somam cerca de 59 | 3 GB, o que pode fazer com que a primeira execução da função demore. Esses dados, 60 | no entanto, são salvos de forma persistente, logo eles são baixados uma única vez. Mais informações sobre o cache de dados [aqui](https://ipeagit.github.io/geocodebr/articles/geocodebr.html#cache-de-dados). 61 | 62 | 63 | -------------------------------------------------------------------------------- /vignettes/geocodebr.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introdução ao geocodebr" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Introdução ao geocodebr} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | # CRAN OMP THREAD LIMIT to avoid CRAN NOTE 22 | Sys.setenv(OMP_THREAD_LIMIT = 2) 23 | ``` 24 | 25 | Geolocalização refere-se ao ato de encontrar um ponto no espaço, geralmente 26 | representado por um par de coordenadas, a partir de um determinado endereço. O 27 | **geocodebr** permite geolocalizar endereços brasileiros de forma simples e 28 | eficiente e sem limite de número de consultas, a partir de dados públicos de endereços do Brasil. A principal base de referência é o Cadastro Nacional de Endereços para Fins Estatísticos (CNEFE), um conjunto de dados coletado e 29 | [publicado](https://www.ibge.gov.br/estatisticas/sociais/populacao/38734-cadastro-nacional-de-enderecos-para-fins-estatisticos.html) 30 | pelo Instituto Brasileiro de Geografia e Estatística (IBGE) que contém os 31 | endereços de mais de 110 milhões de domicílios e estabelecimentos do país. 32 | 33 | 34 | ## Instalação 35 | 36 | A versão estável do pacote pode ser baixada do CRAN com o comando a seguir: 37 | 38 | ```{r, eval = FALSE} 39 | install.packages("geocodebr") 40 | ``` 41 | 42 | Caso prefira, a versão em desenvolvimento: 43 | 44 | ```{r, eval = FALSE} 45 | # install.packages("remotes") 46 | remotes::install_github("ipeaGIT/geocodebr") 47 | ``` 48 | 49 | 50 | 51 | ## Utilização 52 | 53 | O **{geocodebr}** possui três funções principais para geolocalização de dados: 54 | 55 | 1. `geocode()` 56 | 2. `geocode_reverso()` 57 | 3. `busca_por_cep()` 58 | 59 | 60 | ### 1. Geolocalização: de endereços para coordenadas espaciais 61 | 62 | Uma vez que você possui uma tabela de dados (`data.frame`) com endereços no Brasil, a geolocalização desses dados pode ser feita em apenas dois passos: 63 | 64 | 1. O primeiro passo é usar a função `definir_campos()` para indicar os nomes das colunas no seu `data.frame` que correspondem a cada campo dos endereços. 65 | 2. O segundo passo é usar a função `geocode()` para encontrar as coordenadas geográficas dos endereços de input. 66 | 67 | ```{r} 68 | library(geocodebr) 69 | library(sf) 70 | 71 | # carregando uma amostra de dados 72 | input_df <- read.csv(system.file("extdata/small_sample.csv", package = "geocodebr")) 73 | 74 | # Primeiro passo: inidicar o nome das colunas com cada campo dos enderecos 75 | campos <- geocodebr::definir_campos( 76 | logradouro = "nm_logradouro", 77 | numero = "Numero", 78 | cep = "Cep", 79 | localidade = "Bairro", 80 | municipio = "nm_municipio", 81 | estado = "nm_uf" 82 | ) 83 | 84 | # Segundo passo: geolocalizar 85 | df <- geocodebr::geocode( 86 | enderecos = input_df, 87 | campos_endereco = campos, 88 | resultado_completo = FALSE, 89 | resolver_empates = FALSE, 90 | resultado_sf = FALSE, 91 | verboso = FALSE, 92 | cache = TRUE, 93 | n_cores = 1 94 | ) 95 | 96 | ``` 97 | 98 | **Nota:** A função `geocode()` requer que os dados do CNEFE estejam armazenados 99 | localmente. A primeita vez que a função é executada, ela baixa os dados do CNEFE 100 | e salva em um cache local na sua máquina. No total, esses dados somam cerca de 101 | 3 GB, o que pode fazer com que a primeira execução da função demore. Esses dados, 102 | no entanto, são salvos de forma persistente, logo eles são baixados uma única vez. 103 | Ver abaixo mais informações sobre o cache de dados. 104 | 105 | Os resultados do **{geocodebr}** são classificados em seis categorias gerais de `precisao`, dependendo do nível de exatidão com que cada endereço de input foi encontrado nos dados do CNEFE. Para mais informações, consulte a documentação da função ou a [**vignette "geocode"**](https://ipeagit.github.io/geocodebr/articles/geocode.html). 106 | 107 | 108 | ### 2. Geolocalização reversa: de coordenadas espaciais para endereços 109 | 110 | A função `geocode_reverso()`, por sua vez, permite a geolocalização reversa, ou seja, a busca de endereços próximos a um conjunto de coordenadas geográficas. Mais detalhes na [**vignette "geocode"**](https://ipeagit.github.io/geocodebr/articles/geocode_reverso.html). 111 | 112 | ```{r} 113 | # amostra de pontos espaciais 114 | pontos <- readRDS( 115 | system.file("extdata/pontos.rds", package = "geocodebr") 116 | ) 117 | 118 | # seleciona somente os primeiros 20 pontos 119 | pontos <- pontos[1:20,] 120 | 121 | # geocode reverso 122 | df_enderecos <- geocodebr::geocode_reverso( 123 | pontos = pontos, 124 | dist_max = 1000, 125 | verboso = FALSE, 126 | n_cores = 1 127 | ) 128 | 129 | ``` 130 | 131 | 132 | ### 3. Busca por CEPs 133 | 134 | Por fim, a função `busca_por_cep()` permite fazer consultas de CEPs para encontrar endereços associados a cada CEP. A função recebe um vetor de CEPs e retorna um `data.frame` com os endereços e as coordenadas geográficas de cada CEP. 135 | 136 | ```{r} 137 | # amostra de CEPs 138 | ceps <- c("70390-025", "20071-001") 139 | 140 | df_ceps <- geocodebr::busca_por_cep( 141 | cep = ceps, 142 | resultado_sf = FALSE, 143 | verboso = FALSE 144 | ) 145 | 146 | ``` 147 | 148 | 149 | ## Cache de dados 150 | 151 | Como comentado anteriormente, os dados do CNEFE são baixados na primeira vez que 152 | a `geocode()` é executada. Esses dados ficam salvos no *cache* do pacote e não 153 | precisam ser baixados novamente. O pacote inclui algumas funções que ajudam a 154 | gerenciar o *cache*: 155 | 156 | - `listar_pasta_cache()` - retorna o endereço do *cache* na sua máquina, onde os 157 | dados do CNEFE estão salvos; 158 | - `definir_pasta_cache()` - define uma pasta personalizada para ser usada como 159 | *cache*. Essa configuração é persistente entre diferentes sessões do R; 160 | - `listar_dados_cache()` - lista todos os arquivos armazenados no *cache*; 161 | - `deletar_pasta_cache()` - exclui a pasta de *cache*, bem como todos os 162 | arquivos que estavam armazenados dentro dela. 163 | 164 | Após rodar o código desta *vignette*, é provável que o seu *cache* esteja 165 | configurado como a seguir: 166 | 167 | ```{r} 168 | geocodebr::listar_pasta_cache() 169 | 170 | geocodebr::listar_dados_cache() 171 | ``` 172 | 173 | --------------------------------------------------------------------------------