अक्षांश / देशांतर के आधार पर दो बिंदुओं के बीच की दूरी प्राप्त करना


157

मैंने इस सूत्र को लागू करने की कोशिश की: http://andrew.hedges.name/experiments/haversine/ aplet उन दो बिंदुओं के लिए अच्छा करता है जिनका मैं परीक्षण कर रहा हूं:

यहाँ छवि विवरण दर्ज करें

फिर भी मेरा कोड काम नहीं कर रहा है।

from math import sin, cos, sqrt, atan2

R = 6373.0

lat1 = 52.2296756
lon1 = 21.0122287
lat2 = 52.406374
lon2 = 16.9251681

dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2))**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
distance = R * c

print "Result", distance
print "Should be", 278.546

यह वापसी की दूरी 5447.05546147 है । क्यों?

जवाबों:


206

संपादित करें: एक नोट के रूप में, अगर आपको बस दो बिंदुओं के बीच की दूरी का पता लगाने के लिए एक त्वरित और आसान तरीका चाहिए, तो मैं कड़ाई से कर्ट के जवाब में वर्णित दृष्टिकोण का उपयोग करने की दृढ़ता से अनुशंसा करता हूं, इसके बजाय हावरसाइन को फिर से लागू करने के लिए - उनके पद को देखें।

यह जवाब विशिष्ट बग ओपी में भागे जवाब देने पर केंद्रित है।


ऐसा इसलिए है क्योंकि पायथन में, सभी ट्रिगर फ़ंक्शन रेडियन का उपयोग करते हैं , डिग्री का नहीं।

आप या तो संख्याओं को मैन्युअल रूप से रेडियंस में बदल सकते हैं, या radiansगणित मॉड्यूल से फ़ंक्शन का उपयोग कर सकते हैं :

from math import sin, cos, sqrt, atan2, radians

# approximate radius of earth in km
R = 6373.0

lat1 = radians(52.2296756)
lon1 = radians(21.0122287)
lat2 = radians(52.406374)
lon2 = radians(16.9251681)

dlon = lon2 - lon1
dlat = lat2 - lat1

a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))

distance = R * c

print("Result:", distance)
print("Should be:", 278.546, "km")

दूरी अब 278.545589351किमी का सही मान लौटा रही है ।


13
यह किसी भी प्रोग्रामिंग भाषा में सच है, और अंतर कैलकुलस में भी। डिग्री का उपयोग करना अपवाद है, और केवल मानव भाषण में उपयोग किया जाता है।
ब्लूसमून

11
बुद्धिमान के लिए शब्द, इस सूत्र के लिए सभी डिग्री सकारात्मक होना चाहिए। radians(abs(52.123))चाल
रिचर्ड डन

1
क्या आप सभी डिग्री (कोण?) सकारात्मक होने के बारे में निश्चित हैं? मुझे लगता है कि यह गलत है। विचार करें कि lat1, lon1 = 10, 10 (डिग्री) और lat2, lon2 = -10, -10 (डिग्री)। डिग्री के चारों ओर एक एब्स जोड़ने से, दूरी शून्य होगी, जो गलत है। शायद आप डलॉन और / या डलाट का पूर्ण मूल्य लेना चाहते थे, लेकिन यदि आप डॉन को देखते हैं, तो dlat मान एक की गणना में है, साइन एक समान कार्य है, और कोसाइन स्क्वायर्ड एक समान कार्य है, इसलिए मैं या तो dlat या dlon का पूर्ण मूल्य लेने के लिए कोई लाभ देखें।
डेव LeCompte

238

अद्यतन: ०४/२०१:: ध्यान दें कि जियोनी संस्करण १.१३ के बाद से विन्सेंटी दूरी को घटाया गया है - आपको इसके बजाय geopy.distance.distance () का उपयोग करना चाहिए!


ऊपर दिए गए उत्तर हेवेरसिन सूत्र पर आधारित हैं , जो मानता है कि पृथ्वी एक गोला है, जिसके परिणामस्वरूप लगभग 0.5% तक की त्रुटियां होती हैं (तदनुसार help(geopy.distance))। विन्सेन्टी दूरी WGS-84 जैसे अधिक सटीक दीर्घवृत्तीय मॉडल का उपयोग करती है , और भू-भाग में लागू की जाती है । उदाहरण के लिए,

import geopy.distance

coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)

print geopy.distance.vincenty(coords_1, coords_2).km

279.352901604डिफ़ॉल्ट ellipsoid WGS-84 का उपयोग करके किलोमीटर की दूरी को प्रिंट करेगा । (आप .milesकई अन्य दूरी इकाइयों में से किसी एक को चुन सकते हैं )।


1
धन्यवाद। क्या आप न्यूपोर्ट और क्लीवलैंड के बजाय प्रश्न में दिए गए निर्देशांक के साथ अपना जवाब अपडेट कर सकते हैं। यह भविष्य के पाठकों को बेहतर समझ देगा।
ग्वारमदज़े

1
न्यूपोर्ट और क्लीवलैंड के अनियंत्रित स्थान PyPI सूची में उदाहरण के जियोपी दस्तावेज से आते हैं: pypi.python.org/pypi/geopy
जेसन परम

मुझे इसके लिए कर्ट पीक के जवाब को संशोधित करना पड़ा: कैपिटलाइज़ेशन की आवश्यकता:print geopy.distance.VincentyDistance(coords_1, coords_2).km 279.352901604
जिम

4
आपको शायद geopy.distance.distance(…)उस कोड का उपयोग करना चाहिए जो वर्तमान में सबसे अच्छा (= सबसे सटीक) दूरी सूत्र का एक उपनाम है। (फिलहाल विंसेंटी।)
14

10
जियोफाई 1.18.1 आउटपुट में geopy.distance.vincenty का उपयोग करते हुए: विंसेंटी को पदावनत किया जा रहा है और जियोफाई 2.0 में निकाला जा रहा है। उपयोग geopy.distance.geodesic(या डिफ़ॉल्ट geopy.distance.distance) के बजाय, जो अधिक सटीक और हमेशा converges है।
जुआनमाह

88

लोगों के लिए (मेरे जैसे) खोज इंजन के माध्यम से यहां आ रहे हैं और बस एक समाधान ढूंढ रहे हैं जो बॉक्स से बाहर काम करता है, मैं स्थापित करने की सलाह देता हूं mpu। के माध्यम से इसे स्थापित करें pip install mpu --userऔर इसे इस तरह से उपयोग करें कि हावरसाइन दूरी प्राप्त करें :

import mpu

# Point one
lat1 = 52.2296756
lon1 = 21.0122287

# Point two
lat2 = 52.406374
lon2 = 16.9251681

# What you were looking for
dist = mpu.haversine_distance((lat1, lon1), (lat2, lon2))
print(dist)  # gives 278.45817507541943.

एक वैकल्पिक पैकेज है gpxpy

यदि आप निर्भरता नहीं चाहते हैं, तो आप उपयोग कर सकते हैं:

import math


def distance(origin, destination):
    """
    Calculate the Haversine distance.

    Parameters
    ----------
    origin : tuple of float
        (lat, long)
    destination : tuple of float
        (lat, long)

    Returns
    -------
    distance_in_km : float

    Examples
    --------
    >>> origin = (48.1372, 11.5756)  # Munich
    >>> destination = (52.5186, 13.4083)  # Berlin
    >>> round(distance(origin, destination), 1)
    504.2
    """
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371  # km

    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
         math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
         math.sin(dlon / 2) * math.sin(dlon / 2))
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    d = radius * c

    return d


if __name__ == '__main__':
    import doctest
    doctest.testmod()

अन्य वैकल्पिक पैकेज है [haversine][1]

from haversine import haversine, Unit

lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)

haversine(lyon, paris)
>> 392.2172595594006  # in kilometers

haversine(lyon, paris, unit=Unit.MILES)
>> 243.71201856934454  # in miles

# you can also use the string abbreviation for units:
haversine(lyon, paris, unit='mi')
>> 243.71201856934454  # in miles

haversine(lyon, paris, unit=Unit.NAUTICAL_MILES)
>> 211.78037755311516  # in nautical miles

वे दो वैक्टर में सभी बिंदुओं के बीच की दूरी के लिए प्रदर्शन अनुकूलन का दावा करते हैं

from haversine import haversine_vector, Unit

lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)
new_york = (40.7033962, -74.2351462)

haversine_vector([lyon, lyon], [paris, new_york], Unit.KILOMETERS)

>> array([ 392.21725956, 6163.43638211])

क्या किसी एक बिंदु के दिए गए हिगेट को बदलने का कोई तरीका है?
योवेल कोहेन

आप बस दूरी में ऊंचाई अंतर जोड़ सकते हैं। मैं ऐसा नहीं करूंगा, हालांकि।
मार्टिन थोमा

16

मैं एक बहुत ही सरल और मजबूत समाधान पर पहुँच गया जिसका उपयोग कर geodesicरहा हूँgeopy पैकेज से क्योंकि आप अपने प्रोजेक्ट में वैसे भी इसका उपयोग करने की संभावना रखते हैं, इसलिए अतिरिक्त अतिरिक्त स्थापना की आवश्यकता नहीं है।

यहाँ मेरा समाधान है:

from geopy.distance import geodesic


origin = (30.172705, 31.526725)  # (latitude, longitude) don't confuse
dist = (30.288281, 31.732326)

print(geodesic(origin, dist).meters)  # 23576.805481751613
print(geodesic(origin, dist).kilometers)  # 23.576805481751613
print(geodesic(origin, dist).miles)  # 14.64994773134371

geopy


5
import numpy as np


def Haversine(lat1,lon1,lat2,lon2, **kwarg):
    """
    This uses the ‘haversine’ formula to calculate the great-circle distance between two points – that is, 
    the shortest distance over the earth’s surface – giving an ‘as-the-crow-flies’ distance between the points 
    (ignoring any hills they fly over, of course!).
    Haversine
    formula:    a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
    c = 2 ⋅ atan2( √a, √(1−a) )
    d = R ⋅ c
    where   φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km);
    note that angles need to be in radians to pass to trig functions!
    """
    R = 6371.0088
    lat1,lon1,lat2,lon2 = map(np.radians, [lat1,lon1,lat2,lon2])

    dlat = lat2 - lat1
    dlon = lon2 - lon1
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2) **2
    c = 2 * np.arctan2(a**0.5, (1-a)**0.5)
    d = R * c
    return round(d,4)

0

निर्देशांक यानी अक्षांश और देशांतर के आधार पर दूरी की गणना करने के कई तरीके हैं

स्थापित करें और आयात करें

from geopy import distance
from math import sin, cos, sqrt, atan2, radians
from sklearn.neighbors import DistanceMetric
import osrm
import numpy as np

निर्देशांक को परिभाषित करें

lat1, lon1, lat2, lon2, R = 20.9467,72.9520, 21.1702, 72.8311, 6373.0
coordinates_from = [lat1, lon1]
coordinates_to = [lat2, lon2]

हैवरसाइन का उपयोग करना

dlon = radians(lon2) - radians(lon1)
dlat = radians(lat2) - radians(lat1)
    
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
    
distance_haversine_formula = R * c
print('distance using haversine formula: ', distance_haversine_formula)

स्केलेर के साथ हैवराइन का उपयोग करना

dist = DistanceMetric.get_metric('haversine')
    
X = [[radians(lat1), radians(lon1)], [radians(lat2), radians(lon2)]]
distance_sklearn = R * dist.pairwise(X)
print('distance using sklearn: ', np.array(distance_sklearn).item(1))

OSRM का उपयोग करना

osrm_client = osrm.Client(host='http://router.project-osrm.org')
coordinates_osrm = [[lon1, lat1], [lon2, lat2]] # note that order is lon, lat
    
osrm_response = osrm_client.route(coordinates=coordinates_osrm, overview=osrm.overview.full)
dist_osrm = osrm_response.get('routes')[0].get('distance')/1000 # in km
print('distance using OSRM: ', dist_osrm)

भू का उपयोग करना

distance_geopy = distance.distance(coordinates_from, coordinates_to).km
print('distance using geopy: ', distance_geopy)
    
distance_geopy_great_circle = distance.great_circle(coordinates_from, coordinates_to).km 
print('distance using geopy great circle: ', distance_geopy_great_circle)

उत्पादन

distance using haversine formula:  26.07547017310917
distance using sklearn:  27.847882224769783
distance using OSRM:  33.091699999999996
distance using geopy:  27.7528030550408
distance using geopy great circle:  27.839182219511834
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.