├── .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 | [](https://CRAN.R-project.org/package=geocodebr)
20 | [](https://CRAN.R-project.org/package=geocodebr)
21 | [](https://github.com/ipeaGIT/geocodebr/actions)
22 | [](https://app.codecov.io/gh/ipeaGIT/geocodebr?branch=main)
24 | [](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
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 | [](https://CRAN.R-project.org/package=geocodebr)
8 | [](https://CRAN.R-project.org/package=geocodebr)
10 | [](https://github.com/ipeaGIT/geocodebr/actions)
11 | [](https://app.codecov.io/gh/ipeaGIT/geocodebr?branch=main)
13 | [](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
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 |
--------------------------------------------------------------------------------