import math
from sklearn.neighbors import DistanceMetric
def sklearn_haversine_distance(from_, to_):
(y1, x1), (y2, x2) = map(math.radians, from_), map(math.radians, to_)
distance = DistanceMetric.get_metric('haversine').pairwise
return distance([[y1, x1], [y2, x2]])[1, 0]*6378.137
def haversine_distance(from_, to_):
(y1, x1), (y2, x2) = map(math.radians, from_), map(math.radians, to_)
dx, dy = x2 - x1, y2 - y1
s, c = math.sin, math.cos
dist = math.asin(math.sqrt(
s(dy/2)**2+c(y1)*c(y2)*s(dx/2)**2
))
r = 6378.137
return dist*2*r
def lambert_andoyer_distance(from_, to_):
(y1, x1), (y2, x2) = map(math.radians, from_), map(math.radians, to_)
a = 6378.140
b = 6356.755
f = 1 - b / a
s, c = math.sin, math.cos
pa = math.atan(b / a * math.tan(y1))
pb = math.atan(b / a * math.tan(y2))
xx = math.acos(s(pa) * s(pb) + c(pa) * c(pb) * c(x1 - x2))
c1 = (s(xx) - xx) * (s(pa) + s(pb)) ** 2 / c(xx / 2) ** 2
c2 = (s(xx) + xx) * (s(pa) - s(pb)) ** 2 / s(xx / 2) ** 2
dr = f / 8 * (c1 - c2)
return a * (xx + dr)
import pandas as pd
d = {
'札幌': (43.064301, 141.346869),
'東京': (35.689608, 139.692080),
'福岡': (33.606316, 130.418108),
'シドニー': (-33.856960, 151.215109),
'ワシントン': (38.897668, -77.036680),
'ロンドン': (51.501157, -0.142491),
}
df = pd.DataFrame.from_dict(d, orient = "index", columns=['lat', 'lng'])
|
lat |
lng |
札幌 |
43.0643 |
141.347 |
東京 |
35.6896 |
139.692 |
福岡 |
33.6063 |
130.418 |
シドニー |
-33.857 |
151.215 |
ワシントン |
38.8977 |
-77.0367 |
ロンドン |
51.5012 |
-0.142491 |
from itertools import combinations, product
answer_df = pd.DataFrame(combinations(df.index, 2), columns=['from', 'to'])
answer_df['distance'] = [831, 1417, 8577, 10140, 8889, 881, 7792, 10928, 9583, 7778, 11494, 9417, 15709, 16990, 5913]
for func in [sklearn_haversine_distance, haversine_distance, lambert_andoyer_distance]:
name = func.__name__.replace('_distance', '')
def apply_func(x):
ret = func(df.loc[x['from']], df.loc[x['to']])
return ret, (ret-x['distance'])/x['distance']*100
answer_df[[name, f'error_{name}']] = answer_df.apply(apply_func, axis=1, result_type='expand')
answer_df.round(2)
|
from |
to |
distance |
sklearn_haversine |
error_sklearn_haversine |
haversine |
error_haversine |
lambert_andoyer |
error_lambert_andoyer |
0 |
札幌 |
東京 |
831 |
833.15 |
0.26 |
833.15 |
0.26 |
831.03 |
0 |
1 |
札幌 |
福岡 |
1417 |
1418.5 |
0.11 |
1418.5 |
0.11 |
1417.1 |
0.01 |
2 |
札幌 |
シドニー |
8577 |
8621.55 |
0.52 |
8621.55 |
0.52 |
8576.73 |
-0 |
3 |
札幌 |
ワシントン |
10140 |
10126.8 |
-0.13 |
10126.8 |
-0.13 |
10139.9 |
-0 |
4 |
札幌 |
ロンドン |
8889 |
8874 |
-0.17 |
8874 |
-0.17 |
8888.94 |
-0 |
5 |
東京 |
福岡 |
881 |
879.99 |
-0.11 |
879.99 |
-0.11 |
880.66 |
-0.04 |
6 |
東京 |
シドニー |
7792 |
7834.18 |
0.54 |
7834.18 |
0.54 |
7791.77 |
-0 |
7 |
東京 |
ワシントン |
10928 |
10916.5 |
-0.11 |
10916.5 |
-0.11 |
10927.9 |
-0 |
8 |
東京 |
ロンドン |
9583 |
9570.55 |
-0.13 |
9570.55 |
-0.13 |
9583.44 |
0 |
9 |
福岡 |
シドニー |
7778 |
7818.2 |
0.52 |
7818.2 |
0.52 |
7777.89 |
-0 |
10 |
福岡 |
ワシントン |
11494 |
11483.5 |
-0.09 |
11483.5 |
-0.09 |
11494.2 |
0 |
11 |
福岡 |
ロンドン |
9417 |
9405.24 |
-0.12 |
9405.24 |
-0.12 |
9417.03 |
0 |
12 |
シドニー |
ワシントン |
15709 |
15726.9 |
0.11 |
15726.9 |
0.11 |
15708.5 |
-0 |
13 |
シドニー |
ロンドン |
16990 |
17013.5 |
0.14 |
17013.5 |
0.14 |
16989.9 |
-0 |
14 |
ワシントン |
ロンドン |
5913 |
5904.16 |
-0.15 |
5904.16 |
-0.15 |
5912.87 |
-0 |
# 動く
def great_circular_distance(lat1, lng1, lat2, lng2):
y1, x1, y2, x2 = map(math.radians, (lat1, lng1, lat2, lng2))
dx = x2 - x1
s, c = math.sin, math.cos
r = 6378.137
dist = math.acos(
s(y1)*s(y2) + c(y1)*c(y2)*c(dx)
)
return dist*r
# 結果があやしい
def hybeny_distance(lat1, lng1, lat2, lng2):
y1, x1, y2, x2 = map(math.radians, (lat1, lng1, lat2, lng2))
dx, dy = x2 - x1, y2 - y1
my = (y1+y2)/2
rx = 6378.137 # 赤道半径(m) WGS84
ry = 6356.752314 # 極半径(m) WGS84
e2=(rx*rx-ry*ry)/rx/rx # 離心率 E^2
w = math.sqrt(1-e2*math.sin(my)*math.sin(my));
m = rx*(1-e2)/w**3
n = rx/w
return math.sqrt((dy*m)**2 + (dx*n*math.cos(my))**2)