Вычисление 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
Другие вопросы по тегам