Distancia bien proporcionada diferente de Geopy / Haversine


8

Estoy ejecutando un análisis específico donde usamos bien para crear buffers alrededor de puntos (ubicaciones de tiendas) y luego verifico si otros puntos (ubicaciones de usuarios) están presentes dentro de ese valor de buffer. Cuando compruebo la distancia usando bien, resulta ser diferente de la distancia que obtengo de geopy. La fórmula de Haversine está de acuerdo con Geopy y un chequeo en Google Maps usando la función de medida de distancia también da aproximadamente la misma distancia

Aquí hay un ejemplo:

from shapely.geometry import Point, shape
from pyproj import Proj, transform
from geopy.distance import vincenty, great_circle

pt_store=Point(transform(Proj(init='EPSG:4326'),Proj(init='EPSG:3857'),-76.799614, 39.435307))

pt_user=Point(transform(Proj(init='EPSG:4326'),Proj(init='EPSG:3857'),-76.79989,39.43604))

vincenty((39.435307,-76.799614),(39.43604,-76.79989)).meters
great_circle((39.435307,-76.799614),(39.43604,-76.79989)).meters
pt_store.distance(pt_user)

Vincenty: 84.77847691521336
Great_circle: 84.90640111682812
Shapely: 110.02637304449682
Haversine formula ( http://www.movable-type.co.uk/scripts/latlong.html ): 84.88

¿Cuál es la correcta? Bien proporcionado u otros? Además, ¿se espera una diferencia tan grande (~ 22%)? ¿O me estoy perdiendo algo?

Respuestas:


10

Porque los principios y los algoritmos son diferentes (mire la distancia geográfica )

  1. Utilice bien la distancia euclidiana en un plano cartesiano y la distancia más corta entre dos puntos en un plano es una línea recta que contiene los dos puntos.
 import numpy as np
 print np.linalg.norm(np.array(pt_user) - np.array(pt_store))
 110.02637304449682 # meters
 from scipy.spatial import distance
 print distance.euclidean(pt_user, pt_store)
 110.02637304449682 # meters
  1. Vincenty, Great Circle y Haversine usan la distancia geodésica (en un elipsoide, Vincenty) o la distancia del gran círculo (la distancia más corta a lo largo de la superficie de una esfera) entre dos puntos. La distancia más corta en la superficie de una esfera es a lo largo del gran círculo que contiene los dos puntos.

    Por lo tanto, es normal que las distancias euclidianas Shapely, Numpy y Scipy difieran de las distancias Vincenty, Great Circle y Haversine y las diferencias entre las distancias Vincenty, Great Circles y Haversine están relacionadas con la elección de un elipsoide y muchas otras cosas.

    También puedes cambiar el elipsoide

 print vincenty((39.435307,-76.799614),(39.43604,-76.79989),ellipsoid='WGS-84')
 0.0847784769149 km
 print vincenty((39.435307,-76.799614),(39.43604,-76.79989),ellipsoid='GRS-80')
 0.0847784769128 km

O use otras bibliotecas como geodistance

 print geodistance.distanceVincenty(39.435307,-76.799614,39.43604,-76.79989, ellipsoid='WGS-84')
 (0.08477847691523362, -16.276730447136675) # distance, azimuth
 print geodistance.distanceHaversine(39.435307,-76.799614,39.43604,-76.79989)
 (0.08488248586585143, -16.214988211007256)

Puedes ver que todas las diferencias son centimétricas. Con precisión métrica, todos los valores = 85 metros.

  1. ¿Cuál es la correcta? Todo, porque depende del contexto: si trabaja con datos proyectados (plano cartesiano), usa la distancia euclidiana (Shapely, Numpy, Scipy y muchos otros), si no, uno de los otros.

    También son muchas otras distancias ( distancias espaciales de Scipy )

Nuevo

En apoyo de la respuesta de Mintx

pt_store=Point(transform(Proj(init='EPSG:4326'),Proj(init='EPSG:31370'),-76.799614, 39.435307))
pt_user=Point(transform(Proj(init='EPSG:4326'),Proj(init='EPSG:31370'),-76.79989,39.43604))
pt_store.distance(pt_user)
86.26511001003892

Buena respuesta. Solo una nota rápida sobre su punto # 3 cuando usa la proyección EPSG:3857: Shapely es la elección incorrecta aquí. Web Mercator no es conforme y no debe usarse para calcular distancias.
Mintx

3

Y aquí hay otro cálculo de distancia de GeographicLib :

from geographiclib.geodesic import Geodesic
g = Geodesic.WGS84.Inverse(39.435307, -76.799614, 39.43604, -76.79989)
print(g['s12'])  # 84.7784769689

Consideraría que este es el correcto, dentro de los 15 nanómetros.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.