-
Notifications
You must be signed in to change notification settings - Fork 3
Description
contexto
Quando o numero do endereço de input não está presente na base de busca (cnefe), nós fazemos uma aproximação. Atualmente, essa aproximação é feita como um média das coordenadas do cnefe poderada pela diferença entre o numero de input e os numeros presentes no cnefe. Os resultados são razoáveis.
problema
No entanto, seria importante dar um peso maior para diferenças pequenas. Por exemplo, se o numero de input é 5
e o cnefe tem um numero 8
, as coordenadas do ponto 8
deveriam ter um peso maior do que do ponto com número 100
, por exemplo. Atualmente, o peso de diferenças grandes é descontado, mas apenas de maneira linear. Seria bom colocar um expoente de decaimento para dar ainda mais peso para numeros proximos.
solucao
O codigo do pacote desta operação é todo em {duckdb} e SQL. Mas para ilustrar a problema, apresento abaixo o codigo em R mesmo. O calculo atual é feito dessta maneira.
output <- df |>
group_by(id) |>
summarize(
numero_input = first(numero_input),
lat = sum((1/abs(numero_input - numero) * lat)) / sum(1/abs(numero_input - numero)),
lon = sum((1/abs(numero_input - numero) * lon)) / sum(1/abs(numero_input - numero))
)
Minha sugestão é elevar o a difença ao cubo. Assim:
output <- df |>
group_by(id) |>
summarize(
numero_input = first(numero_input),
lat = sum((1/abs(numero_input - numero)^3 * lat)) / sum(1/abs(numero_input - numero)^3),
lon = sum((1/abs(numero_input - numero)^3 * lon)) / sum(1/abs(numero_input - numero)^3)
)
reprex
Aqui um reprex que gera um exemplo dentro da funçao check_approx()
. A função recebe um numero_input
e um expoente expp
. Quando expp = 1
, o resultado da função é exatamente o comportamento do geocodebr hoje em dia.
library(dplyr)
library(sf)
library(sfheaders)
library(arrow)
library(mapview)
tudo <- geocodebr::listar_dados_cache()
tudo <- tudo[7]
cnefe <- arrow::open_dataset( tudo ) |>
dplyr::filter(estado == 'RJ') |>
dplyr::filter(municipio == "RIO DE JANEIRO") |>
dplyr::filter(logradouro == "AVENIDA MINISTRO IVAN LINS") |>
dplyr::collect()
check_approx <- function(numero_input, expp){
input <- data.frame(
id = 1,
logradouro = 'AVENIDA MINISTRO IVAN LINS',
numero_input = numero_input,
localidade = "BARRA DA TIJUCA",
cep = '22620-110'
)
df <- left_join(input, cnefe, by = c('logradouro', 'localidade', 'cep'))
output <- df |>
group_by(id) |>
summarize(
numero_input = first(numero_input),
lat = sum((1/abs(numero_input - numero)^expp * lat)) / sum(1/abs(numero_input - numero)^expp),
lon = sum((1/abs(numero_input - numero)^expp * lon)) / sum(1/abs(numero_input - numero)^expp)
)
sf_cnefe <- sfheaders::sf_point(
obj = cnefe,
x = 'lon',
y = 'lat',
keep = TRUE
)
sf_output <- sfheaders::sf_point(
obj = output,
x = 'lon',
y = 'lat',
keep = TRUE
)
sf::st_crs(sf_cnefe) <- 4674
sf::st_crs(sf_output) <- 4674
mapp <- mapview::mapview(sf_cnefe, zcol='numero') +
mapview(sf_output, col.regions = "red")
return(mapp)
}
check_approx(numero_input = 6, expp = 1)
check_approx(numero_input = 6, expp = 3)
check_approx(numero_input = 760, expp = 1)
check_approx(numero_input = 760, expp = 3)
check_approx(numero_input = 400, expp = 1)
check_approx(numero_input = 400, expp = 3)
Os exemplos acima mostram duas coisas.
- A localização do ponto aproximado é muito mais proxima do correto quando se usa
expp = 3
, - Essa diferença observada em (1) é mais pronunciada quando o input é um numero proximo do inicio ou do fim da rua. Para um input com numero proximo do numero mediano, o
expp
praticamente nao afeta o resultado.