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 :
Forfaits :
Ressources utilisées dans cet article :
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 :
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.
Décomposons la tâche en étapes. Nos étapes requises ici sont les suivantes :
Pour terminer l'étape 1, nous utiliserons Python pour :
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()Copier après la connexion4 - 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.iodef 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 connexion5 - 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 connexionveuillez noter :
- 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
- 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 connexionStep 1 Complete
We now have two dataframes which we will use for the next steps:
- Our original stations dataframe containing the UK train stations latitude and longitude
- 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 distCopier après la connexion2 - 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 connexion3 - 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 connexionStep 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 connexion2 - 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 documentationurl = "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_timeCopier après la connexion3 - 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 connexionStep 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 connexionThankyou 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!