Вычисление haversine над двумя списками
В настоящее время я пытаюсь вычислить расстояние маршрута (широта / долгота) координат, которые у меня есть во фрейме данных Geopandas. Я довольно новичок в пакете, но в основном у меня есть несколько точек, которые составляют маршрут, и все, что я пытаюсь сделать, это найти полное реальное расстояние маршрута. Я могу сделать это с двумя фиксированными точками, которым я должен помочь пользователю @steve clark:
# Start
lon1 = 41.592181
lat1 = -87.638856
# End
lat2 = -86.754688
lon2 = 41.877575
def haversine(lat1, lon1, lat2, lon2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers
print('Distance from beginning to end of route in km: ',round((c * r), 2),'\n')
Я застрял на двух вещах, в настоящее время я обыскиваю, чтобы узнать, могу ли я просто рассчитать расстояние от Geopandas point()
объект, но, честно говоря, примеры, которые я нахожу, либо не связаны с моим вопросом, либо выходят за рамки моего понимания (в настоящее время).
Я могу вытянуть столбцы широты и долготы из моего gpd в списки, но я застрял, применяя его через цикл
LatList = geo_data['latitude'].tolist()
LonList = geo_data['longitude'].tolist()
Я пытаюсь добавить то, что я повторяю, в новый список и суммирую расстояния, но в итоге получаю список с тем же значением, добавленным 2850 раз. Любая помощь или направление приветствуется!
РЕДАКТИРОВАТЬ: По запросу, это код, который не работает
distance = []
for i, j in zip(LatList, LonList):
dlat = i - i+1
dlon = j - j+1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers
distance.append(round((c * r), 2))
print(distance)
4 ответа
Вам необходимо скорректировать определения i
, i+1
, j
а также j+1
иначе цикл не будет делать то, что вы хотите.
distance = []
LatLonList = list(zip(LatList, LonList))
# notice that if you do "for n in len(LatLonList)", the loop will fail in the last element
for n in len(LatLonList) -1:
dlat = LatLonList[n][0] - LatLonList[n+1][0] # this is for i
dlon = LatLonList[n][1] - LatLonList[n+1][1] # this is for j
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers
distance.append(round((c * r), 2))
print(distance)
В качестве примера используйте данные из геопандаса:
import pandas as pd
import geopandas
from shapely.geometry import Point
df = pd.DataFrame(
{'City': ['Buenos Aires', 'Brasilia', 'Santiago', 'Bogota', 'Caracas'],
'Country': ['Argentina', 'Brazil', 'Chile', 'Colombia', 'Venezuela'],
'Latitude': [-34.58, -15.78, -33.45, 4.60, 10.48],
'Longitude': [-58.66, -47.91, -70.66, -74.08, -66.86]})
df['Coordinates'] = list(zip(df.Longitude, df.Latitude))
df['Coordinates'] = df['Coordinates'].apply(Point)
gdf = geopandas.GeoDataFrame(df, geometry='Coordinates')
расстояние с использованием двух точек в качестве входных данных может быть записано, как показано ниже:
def haversine(point1, point2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
lon1, lat1 = point1.bounds[0], point1.bounds[1]
lon2, lat2 = point2.bounds[0], point2.bounds[1]
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers
# print('Distance from beginning to end of route in km: ',round((c * r), 2),'\n')
return c * r
и расчет с использованием pandas.DataFrame.apply
:
gdf['Coordinates'].apply(lambda x: gdf['Coordinates'].apply(lambda y: haversine(x, y)))
РЕДАКТИРОВАТЬ: рассчитать только половину матрицы
gdf[['Coordinates']].apply(lambda x: gdf.loc[:x.name, 'Coordinates'].apply(lambda y: haversine(x['Coordinates'], y)), axis=1)
Существует также пакет для вычисления расстояния Haversine https://pypi.org/project/haversine/ , который поставляется с версией numpy, которая ускорит вычисления по спискам.
Нашел этот код по этому актуальному вопросу: Расчет географического расстояния между списком координат (широта, долгота),
def calculate_distance(positions):
results = []
for i in range(1, len(positions)):
loc1 = positions[i - 1]
loc2 = positions[i]
lat1 = loc1[0]
lng1 = loc1[1]
lat2 = loc2[0]
lng2 = loc2[1]
degreesToRadians = (math.pi / 180)
latrad1 = lat1 * degreesToRadians
latrad2 = lat2 * degreesToRadians
dlat = (lat2 - lat1) * degreesToRadians
dlng = (lng2 - lng1) * degreesToRadians
a = math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(latrad1) * \
math.cos(latrad2) * math.sin(dlng / 2) * math.sin(dlng / 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
r = 6371000
results.append(r * c)
return (sum(results) / 1000) # Converting from m to km