Skip to content

Calibrando numero aproximoado #36

@rafapereirabr

Description

@rafapereirabr

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.

  1. A localização do ponto aproximado é muito mais proxima do correto quando se usa expp = 3,
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions