Maison > développement back-end > Tutoriel Python > Comment calculer la distance (temps et miles) entre les géographies de votre portefeuille et un comparateur (Point A et Point B)

Comment calculer la distance (temps et miles) entre les géographies de votre portefeuille et un comparateur (Point A et Point B)

Linda Hamilton
Libérer: 2024-10-07 06:10:30
original
1038 Les gens l'ont consulté

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


Copier après la connexion

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'})


Copier après la connexion
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()


Copier après la connexion

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 []


Copier après la connexion

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()


Copier après la connexion

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()


Copier après la connexion

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


Copier après la connexion

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()


Copier après la connexion

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()


Copier après la connexion

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()


Copier après la connexion

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


Copier après la connexion

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()


Copier après la connexion

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()


Copier après la connexion

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.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal