如何计算您的投资组合地理位置与比较器(A 点和 B 点)之间的距离(时间和英里)

Linda Hamilton
发布: 2024-10-07 06:10:30
原创
1035 人浏览过

Utiliser Python pour calculer les distances géographiques

Ce code est utile pour tous ceux qui cherchent à faire correspondre un portefeuille contenant des données géographiques à n'importe quelle autre géographie dans le but de calculer le temps de trajet et la distance entre les deux points. Il s'inspire d'une tâche qui m'a été confiée pour aider les bailleurs de fonds à comprendre à quel point les projets approuvés étaient proches les uns des autres après avoir interrogé la répartition géographique de leurs candidats.

Cet article explique comment utiliser les appels API, les fonctions intégrées et personnalisées pour faire correspondre une liste d'organismes de bienfaisance (point A) à la gare la plus proche (point B) et calculer la distance en miles et conduire temps en minutes.

D'autres cas d'utilisation incluent, à titre d'exemple :

  • Code postal correspondant à l'école la plus proche
  • Code postal correspondant à l'association caritative la plus proche
  • Code postal correspondant au fournisseur NHS le plus proche
  • Code postal correspondant au parc national le plus proche
  • Correspondance du code postal de la liste A au code postal le plus proche de la liste B

Exigences

Forfaits :

  • pandas
  • numpy
  • demandes
  • json
  • haversine

Ressources utilisées dans cet article :

  • Données des associations caritatives (pour cet exemple, j'ai sélectionné les 100 premières associations caritatives à partir d'un extrait des associations caritatives avec des dépenses supérieures à 5 millions du registre des commissions caritatives)
  • Données des gares britanniques (comme elles ne sont pas facilement disponibles, j'ai utilisé un document github contenant les gares britanniques ainsi que leur longitude, latitude et code postal)
  • Postcodes.io (une API pour rechercher et extraire les données des codes postaux du Royaume-Uni)
  • Projet OSRM (une API de calcul d'itinéraires)

Pourquoi utiliser Python pour cela ?

Les étapes décrites ici peuvent sembler complexes et complexes, mais le résultat final est un modèle qui peut être réutilisé et reformaté pour répondre à vos besoins lorsque vous cherchez à calculer les distances géographiques entre le point A et le point B pour plusieurs lignes de données.

Disons que vous travaillez avec 100 associations caritatives, par exemple. Vous aimeriez savoir à quel point ces organismes de bienfaisance se trouvent à proximité des gares ferroviaires à proximité dans le cadre d'une analyse plus large de la géographie de ces organismes de bienfaisance. Il se peut que vous souhaitiez cartographier visuellement ces données ou les utiliser comme point de départ pour une analyse plus approfondie, par exemple en examinant l'accessibilité de la participation à l'organisme de bienfaisance depuis un endroit éloigné.



Quel que soit le cas d'utilisation, si vous souhaitez le faire manuellement, vos étapes seraient les suivantes :

  1. Trouver le code postal de l'association caritative
  2. Utilisez un outil en ligne pour vérifier la gare la plus proche de l'association caritative
  3. Utilisez un outil cartographique en ligne pour connaître la distance en miles et le temps de conduite pour vous rendre de l'organisme de bienfaisance à la gare la plus proche
  4. Enregistrer les résultats dans une feuille de calcul
  5. Répétez les étapes 1 à 4 pour les 99 associations caritatives restantes

Cela peut être efficace pour une poignée d'organismes de bienfaisance, mais après un certain temps, le processus deviendra long, fastidieux et sujet aux erreurs humaines.



En utilisant Python pour accomplir cette tâche, nous pouvons automatiser les étapes et avec seulement quelques ajouts requis par l'utilisateur, exécutez simplement notre code à la fin.

Que peut faire Python ?

Décomposons la tâche en étapes. Nos étapes requises ici sont les suivantes :

  1. Trouver la gare la plus proche d'un code postal donné
  2. Calculez la distance entre les deux
  3. Calculer le temps de conduite pour le déplacement
  4. Produire un ensemble de données contenant toutes les informations requises

Pour terminer l'étape 1, nous utiliserons Python pour :

  • importer notre ensemble de données contenant les détails de l'association, y compris son code postal
  • utilisez l'API Postcodes.io pour extraire la longueur et la latitude de chaque code postal
  • compilez à nouveau ces informations dans un cadre de données contenant les informations d'origine, ainsi que la longitude et la latitude pour chaque organisme de bienfaisance.

Étape 1 : Trouver la gare la plus proche d'un code postal donné

1- importer des colis


# data manipulation
import numpy as np
import pandas as pd

# http requests
import requests

# handling json
import json

# calculating distances
import haversine as hs
from haversine import haversine, Unit


登录后复制

2 - importer et nettoyer les données


# import as a pandas dataframe, specifying which columns to import
charities = pd.read_excel('charity_list.xlsx', usecols='A, C, E')
stations = pd.read_csv('uk-train-stations.csv', usecols=[1,2,3])

# renaming stations columns for ease of use
stations = stations.rename(columns={'station_name':'Station Name','latitude':'Station Latitude', 'longitude':'Station Longitude'})


登录后复制
Notre variable contenant notre ensemble de données caritatives, nommée « charities », sera notre dataframe maître, que nous utiliserons au fur et à mesure pour fusionner avec les données que nous extrayons.



Pour l'instant, notre prochaine étape consiste à créer notre fonction permettant d'extraire la longitude et la latitude des codes postaux de nos associations caritatives.

3 - convertir les codes postaux en liste pour la fonction de correspondance


charities_pc = charities['Charity Postcode'].tolist()


登录后复制

4 - créez une fonction qui prend un code postal, fait une requête à postcodes.io, enregistre la latitude et la longitude et renvoie les données dans une nouvelle trame de données.


pour plus d'informations, veuillez consulter la documentation postcodes.io


def bulk_pc_lookup(postcodes):

    # set up the api request
    url = "https://api.postcodes.io/postcodes"
    headers = {"Content-Type": "application/json"}

    # specify our input data and response, specifying that we are working with data in json format
    data = {"postcodes": postcodes}
    response = requests.post(url, headers=headers, data=json.dumps(data))

    # specify the information we want to extract from the api response

    if response.status_code == 200:
        results = response.json()["result"]
        postcode_data = []

        for result in results:
            postcode = result["query"]

            if result["result"] is not None:
                latitude = result["result"]["latitude"]
                longitude = result["result"]["longitude"]
                postcode_data.append({"Charity Postcode": postcode, "Latitude": latitude, "Longitude": longitude})

        return postcode_data

    # setting up a fail safe to capture any errors or results not found
    else:
        print(f"Error: {response.status_code}")
        return []


登录后复制

5 - transmettre notre liste de codes postaux caritatifs dans la fonction pour extraire les résultats souhaités


# specify where the postcodes are
postcodes = charities_pc

# save the results of the function as output
output = bulk_pc_lookup(postcodes)

# convert the results to a pandas dataframe
output_df = pd.DataFrame(output)
output_df.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

veuillez noter :

  1. if your Point B data (in this case, the UK rail stations) does not already contain latitude and longitude, you will need to also performs steps 3 to 5 on the Point B data as well
  2. postcodes.io allows bulk look up requests for up to 100 postcodes at a time. if your dataset contains more than 100 postcodes, you will need to either manually create new excel sheets containing only 100 rows per sheet, or you will need to write a function to break your dataset into the required length for the API call

6 - we can now either merge our output_df with our original charity dataset, or, to leave our original data untouched, create a new dataframe that we will use for the rest of the project for our extracted results


charities_output = pd.merge(charities, output_df, on="Charity Postcode")

charities_output.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

Step 1 Complete

We now have two dataframes which we will use for the next steps:

  1. Our original stations dataframe containing the UK train stations latitude and longitude
  2. Our new charities_output dataframe containing the original charity information and the new latitude and longitude information extracted from our API call

Step 2 - Calculate the distance between Point A (charity) and Point B (train station), and record the nearest result for Point A

In this section, we will be using the haversine distance formula to:

  • check the distance between a charity and every UK train station
  • match the nearest result i.e. the UK train station with the minimum distance from our charity
  • loop over our charities dataset to find the nearest match for each row
  • record our results in a dataframe

Please note, for further information on using the haversine module, consult the documentation

1 - create a function for calculating the distance between Point A and Point B


def calc_distance(lat1, lon1, lat2, lon2):

    # specify data for location one, i.e. Point A
    loc1 = (lat1, lon1)

    # specify the data for location two, i.e. Point B
    loc2 = (lat2, lon2)

    # calculate the distance and specify the units as miles
    dist = haversine(loc1, loc2, unit=Unit.MILES)

    return dist


登录后复制

2 - create a loop that calculates the distance between Point A and every row in Point B, and match the result where Point B is nearest to Point A


# create an empty dictionary to store the results
results = {}

# begin with looping over the dataset containing the data for Point A
for index1, row1 in charities_output.iterrows():

    # specify the location of our data
    charity_name = row1['Charity Name']
    lat1 = row1['Latitude']
    lon1 = row1['Longitude']

    # track the minimum distance between Point A and every row of Point B
    min_dist = float('inf')
    # as the minimum distance i.e. nearest Point B is not yet known, create an empty string for storage
    min_station = ''

    # loop over the dataset containing the data for Point B
    for index2, row2 in stations.iterrows():

        # specify the location of our data
        lat2 = row2['Station Latitude']
        lon2 = row2['Station Longitude']

        # use our previously created distance function to calculate the distance
        dist = calc_distance(lat1, lon1, lat2, lon2)

        # check each distance - if it is lower than the last, this is the new low. this will repeat until the lowest distance is found
        if dist < min_dist:
            min_dist = dist
            min_station = row2['Station Name']

    results[charity_name] = {'Nearest Station': min_station, 'Distance (Miles)': min_dist}

# convert the results dictionary into a dataframe
res = pd.DataFrame.from_dict(results, orient="index")

res.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

3 - merge our new information with our charities_output dataframe


# as our dataframe output has used our charities as an index, we need to re-add it as a column
res['Charity Name'] = res.index

# merging with our existing output dataframe
charities_output = charities_output.merge(res, on="Charity Name")

charities_output.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

Step 2 Complete

We now have all our information in one place, charities_output, containing:

  • Our charity information
  • The nearest station to each charity
  • The distance in miles

Step 3 - Calculate the driving time for travel

Our final step uses Project OSRM to find the driving distance between each of our charities and its nearest station. This is helpful as miles are not always an accurate descriptor of distance, where, for example, in a city like London, a 1 mile journey might take as long as a 5 mile journey in a rural area.

To prepare for this step, we must have one dataframe containing the following information:

  • charity information: name, longitude, latitude, nearest station, distance in miles
  • station information: name, longtiude, latitude

1- create a data frame with the above information


drive_time_df = pd.merge(charities_output, stations, left_on='Nearest Station', right_on='Station Name')
drive_time_df = drive_time_df.drop(columns=['Station Name'])

drive_time_df.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

2 - now that our dataframe is ready, we can set up our function for calculating drive time using Project OSRM



please note: for further information, consult the documentation


url = "http://router.project-osrm.org/route/v1/driving/{lon1},{lat1};{lon2},{lat2}"

# function 

def calc_driveTime(row):

    # extract lat and lon
    lat1, lon1 = row['Latitude'], row['Longitude']
    lat2, lon2 = row['Station Latitude'], row['Station Longitude']

    # request
    response = requests.get(url.format(lat1=lat1, lon1=lon1, lat2=lat2, lon2=lon2))

    # parse response
    data = json.loads(response.content)

    # drive time in seconds
    drive_time_sec = data["routes"][0]["duration"]

    # convert to minutes
    drive_time = round((drive_time_sec) / 60, 0)

    return drive_time


登录后复制

3 - pass our data into our new function to calculate driving time in minutes


# apply the above function to our dataframe
driving_time_res = drive_time_df.apply(calc_driveTime, axis=1)

# add dataframe results as a new column
drive_time_df['Driving Time (Minutes)'] = driving_time_res

drive_time_df.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

Step 4 Complete

We now have all our desired information in one compact dataframe. For layout purposes, and depending on what we want to do next with our data, we can create one final dataframe as output, containing the following information:

  • Charity Name
  • Nearest Station
  • Distance (Miles)
  • Driving Time (Minutes)

final_output = drive_time_df.drop(columns=['Charity Number', 'Charity Postcode', 'Latitude', 'Longitude', 'Station Latitude', 'Station Longitude'])

final_output.head()


登录后复制

How to calculate the distance (time and miles) between the geographies of your portfolio and a comparator (Point A and Point B)

Thankyou for reading! I hope this was helpful. Please checkout my website if you are interested in my work.

以上是如何计算您的投资组合地理位置与比较器(A 点和 B 点)之间的距离(时间和英里)的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板