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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions