解释sklearn haversine输出的结果为公里数

8

我无法解释sklearn(20.2版本)中haversine实现的输出。

文档说:“请注意,haversine距离度量需要以[纬度、经度]的形式提供数据,并且输入和输出的单位均为弧度。”因此,我可以通过乘以6371(半径的大约估计距离)来转换为公里。

计算两点之间距离的功能如下:

def distance(origin, destination):
    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

distance([32.027240,-81.093190],[41.981876,-87.969982])
1263.103504537151

这是正确的距离。

使用BallTree实现:

from sklearn.neighbors import BallTree
test_points = [[32.027240,41.981876],[-81.093190,-87.969982]]
tree = BallTree(test_points,metric = 'haversine')
results = tree.query_radius(test_points,r = 10,return_distance  = True)

results[1]
array([array([0.        , 1.53274271]), array([1.53274271, 0.        ])],
      dtype=object)

同样适用于距离度量实现:

dist = DistanceMetric.get_metric('haversine')
dist.pairwise([[32.027240,41.981876],[-81.093190,-87.969982]])
array([[0.        , 1.53274271],
       [1.53274271, 0.        ]])

我还尝试过改变顺序,以防它不应该被输入为[[lat1,lat2],[lon1,lon2]],但是我也没有得到可以解释的结果。

有人知道如何使用sklearn实现获取两个坐标之间的距离(以公里为单位)吗?

2个回答

11

因此问题在于sklearn要求所有内容都是以弧度为单位,但我拥有的纬度/经度和半径分别是以度/米为单位的。在使用之前,我需要进行一些转换:

from sklearn.neighbors import BallTree
earth_radius = 6371000 # meters in earth
test_radius = 10 # meters

test_points = [[32.027240,41.981876],[-81.093190,-87.969982]]
test_points_rad = [[x[0] * np.pi / 180, x[1] * np.pi / 180] for x in test_points ]

tree = BallTree(test_points_rad, metric = 'haversine')
results = tree.query_radius(test_points, r=test_radius/earth_radius, return_distance  = True)

只是为了澄清:最终结果是以米为单位的距离,因为你定义了地球半径的单位是米,对吧? - labourday
正确 - 弧度在技术上只是一个角度,因此无论您如何定义从地球中心到外部的距离,测量结果都将是这个角度。 - flyingmeatball
查询函数的输入也应该是以弧度为单位。返回的距离应该乘以地球半径以得到以米为单位的距离。 - Shashwat
所以,我认为您只需要在最后使用以下代码乘以距离:distances, indices = tree.query_radius(test_points, r=radius/earth_radius, return_distance=True),然后,FinlDist = distances * earth_radius。 - user3665906

5

为了澄清@flyingmeatball之前的回答,有几点需要说明:

  1. 可能是由于sklearn中的更改:您需要逐行指定坐标。
  2. 将度转换为弧度的简单方法是导入maths中的radians模块。
  3. 最终得到的结果需要再次乘以地球半径才能得到以米/千米为单位的答案。

请参见以下代码示例...

from math import radians
earth_radius = 6371000 # meters in earth
test_radius = 1300000 # meters

test_points = [[32.027240,-81.093190],[41.981876,-87.969982]]
test_points_rad = np.array([[radians(x[0]), radians(x[1])] for x in test_points ])

tree = BallTree(test_points_rad, metric = 'haversine')
ind,results = tree.query_radius(test_points_rad, r=test_radius/earth_radius, 
return_distance  = True)
print(ind)
print(results * earth_radius/1000)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接