Skip to content

lixo, teste de reversibilidade do Geohash

Peter edited this page Nov 27, 2018 · 8 revisions

Ver também:


Se, por questões de legibilidade e organização dos dados, adotarmos o Geohash nas listagens CSV de pontos, ao invés de coordenadas usuais, importante saber qual o tamanho mínimo do Geohash para que seja reversível.

A precisão adotada na preservação digital GeoJSON foi 6 casas demais de latitude e longitude.

geohash_len sum_x sum_y avg_diffs avg_diffs_not0
9 19.687000 19.667004 0.0000107330 ?
10 5.011913 2.459694 0.0000020377 0.0000020912
13 0.088912 0.090457 0.0000000489 ?
14 0.090775 0.090080 0.0000000493 0.0000005

Rodou com n=1833326 para todos.

Uma forma aproximada de avaliar a demanda de precisão é pela conversão em base32 de todos os dígitos da LatLong: 8+8, um número com 16 dígitos decimais, por exemplo 9876543210123456, que em base32 é 8OML7KQBS60,ou seja, tem 11 dígitos. Se convertermos separadamente Lat e Long, por exemplo 98765432 em base32 é 2U62JO (6 dígitos), teremos ao todo 12 dígitos base32.

Assim, é de se esperar um Geohash com algo em torno de 10 a 12 dígitos como "de mesma precisão" que as coordenadas LatLong originais. De fato, conferindo pelo simples percentual de taxa de erros, vemos que só começa a baixar depois dos 10 dígitos de Geohash, e dá um salto de 60% para 15% quando chegamos nos 12 dígitos. Em 13 não muda muito: tem aspecto de uma curva S com inflexão no 12.

geohash_len avg_diffs n_diffs_not0 perc avg_diffs_not0
10 0.0000020377 1786453 97.4% 0.0000020912
11 0.0000003716 1111317 60.6% 0.0000006130
12 0.0000000756 267843 14.6% 0.0000005173
13 0.0000000489 174916 9.5% 0.0000005127
14 0.0000000493 176324 9.6% 0.0000005128

É de se esperar também a interferência de erros de ponto flutuante quando passamos dos 13, pois são diversas conversões acumulando erros no processo. Fiquemos portanto com os 12 dígitos de Geohash como equivalentes a coordenadas LatLong de 6 decimais.

PS: com 14 já teríamos o inverso, um excesso de acúmulos de erro de ponto flutuante, interferindo ao invés de ajudar.

AMOSTRA: exagerando nos casos de erro,

orig_x x orig_y y diff_x diff_y
-41.024779 -41.024779 -11.538081 -11.538081 0.000000 0.000000
-40.595411 -40.595411 -11.604709 -11.604708 0.000000 0.000001
-40.599088 -40.599088 -11.557004 -11.557004 0.000000 0.000000
-39.159981 -39.159980 -16.557182 -16.557182 0.000001 0.000000
-39.223874 -39.223874 -16.382529 -16.382529 0.000000 0.000000
-38.529300 -38.529300 -13.007637 -13.007636 0.000000 0.000001
-41.983470 -41.983470 -11.582078 -11.582078 0.000000 0.000000
-41.965792 -41.965792 -11.523515 -11.523515 0.000000 0.000000
-41.961747 -41.961746 -11.513828 -11.513828 0.000001 0.000000
-41.835954 -41.835954 -11.273666 -11.273666 0.000000 0.000000
-41.648883 -41.648883 -11.510430 -11.510430 0.000000 0.000000

A título de verificação, se mudamos a precisão de LatLong para 5 decimais,

geohash_len avg_diffs n_diffs_not0 perc avg_diffs_not0
9 0.0000107338 1733044 94.53% 0.0000113549
10 0.0000020370 679864 37.08% 0.0000054930
11 0.0000003749 134963 7.36% 0.0000050926
12 0.0000000836 30480 1.66% 0.0000050300
13 0.0000000563 20502 1.12% 0.0000050332
14 0.0000000570 20792 1.13% 0.0000050293

O que mostra que a análise é consistente, e a comparação com simples conversão para base32 (~10 dígitos na coordenada monolítica) continua sendo válida. Com este grau de precisão na LatLong parece não haver mais interferência dos erros de ponto flutuante: há uma a convergência mais consistente percentual para zero. O ponto flutuante passa a interferir no Geohash de 14 dígitos (13 portanto seria o mais preciso), que pode ser tomado como limite de usabilidade do Geohash na precisão default do PostGIS.

CREATE or replace VIEW vw_point_geohash_diffs AS
SELECT *, abs(orig_x-x) diff_x, abs(orig_y-y) diff_y
FROM (
SELECT orig_x, round(st_x(pt),6) x, orig_y, round(st_y(pt),6) y 
  FROM (
    SELECT osm_id, st_centroid(ST_GeomFromGeoHash( st_geohash(way,14) )) pt, 
           round(st_x(way),6) orig_x, round(st_y(way),6) orig_y
    FROM planet_osm_point -- where osm_id=5916601782
 ) t1
) t2;

-- amostra, se vw_point_geohash_diffs for materialized view
SELECT * FROM vw_point_geohash_diffs 
tablesample BERNOULLI(1);

-- estimativa de erro e precisão:
SELECT n, sum_x, sum_y, round(avg_diffs/2.0,10) as avg_diffs, n_diffs_not0, 
       round(100.0*n_diffs_not0/n,2)||'%' as perc,
       round(avg_diffs_not0/2.0,10) as avg_diffs_not0
FROM ( 
  SELECT count(*) n, sum(diff_x) sum_x, sum(diff_y)  sum_y, 
       avg(diff_x+diff_y)  avg_diffs,
       count(*) FILTER (WHERE diff_x>0 OR diff_y>0) n_diffs_not0,
       avg(diff_x+diff_y) FILTER (WHERE diff_x>0 OR diff_y>0) avg_diffs_not0
  FROM vw_point_geohash_diffs
) t;
-- ... repetir para cada st_geohash(way,R) com R={9,10,11,12,13,14}: