A térképes, geolokációs adatok felhasználása ma már az adatelemzési repertoár magától értetődő része.
Minden jelentősebb vizualizációs szoftver képes térképes adatok megjelenítésére, e tekintetben tehát remek a helyzet. Előfordulhat ugyan, hogy nem vagyunk kibékülve az alapbeállításként használt Google Maps, OpenStreetMap, vagy Bing Maps egyik-másik tulajdonságával, komoly fejfájást azonban nem fognak okozni.
A megjelenítéshez azonban elő kell készíteni a térképes adatokat, s a rendelkezésre álló adatszetten túl gyakran kell (kéne) külső forrásból kiegészítő információkat beszereznünk. Erre mutatok három példát, megvalósításukkal együtt:
Python 3.6 szoftverkörnyezetben, az Anaconda csomag, és +1 letölthető csomag használatával mutatok be egy egyszerűbb megoldást. A Google térképszolgáltatásának, a Google Maps-nek a programozási interface-ét (API-ját) is használni fogom.
A teljes kód letölthető Jupyter Notebook (korábbi nevén: IPython Notebook) formátumban.
Tegyük föl, hogy különböző magyar városok polgármesteri hivatalainak címe áll rendelkezésre, szépen, rendezett formában, egy Excel-fájlban.
import haversine # légvonalban mért földrajzi távolság
import numpy as np
import pandas as pd
import requests # HTTP lekérdezések, ezt használjuk a Google Maps API-k eléréséhez
import time # késleltetés
import xlsxwriter # mentés Excel fájlba
pd.set_option("display.max_rows", 12)
Beolvasom Excelből a címeket, és a Python Pandas csomagjának DataFrame objektumában (egyfajta speciális táblázatban) tárolom.
df = pd.read_excel("Városháza.xlsx")
df.head() # áttekintés; csak az első néhány értéket jelenítjük meg
Megye | Irányítószám | Város | Közterület | |
---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. |
1 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. |
2 | Budapest | 1052 | Budapest | Városház u. 9-11. |
3 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. |
Első feladatként alakítsuk a címeket pontos földrajzi koordinátákká! A Google Maps Geocoding API felhasználásával egyszerűen meg tudjuk tenni, legalábbis ha nem túl sok címről van szó.
A felhasználási kvóta (most) napi 2500 lekérdezés – fejlesztési fázisban érdemes tehát a teljes adatkörnek csupán egy szeletén próbálkozni, s majd csak a kész verzióban lekérdezni az összes szükséges címet. API „kulcsot” igényelni ezen a címen lehet, ezt minden lekérdezésbe bele kell építeni (lásd a forráskódban).
A Google védekezik szervereinek túlterhelése ellen, ezért kisebb várakozást is érdemes beiktatni az egyes lekérdezések közé. 3 másodperc elég lehet, így persze lassulnak a lekérdezések, lehet tehát próbálkozni, és feszegetni a határokat :)
# konstansok, amit használni fogunk (Python nyelvben valódi konstansok híján: később szándékosan meg nem változtatott változók)
# Google Maps API kulcsok, például itt lehet igényelni: https://developers.google.com/maps/documentation/geocoding/get-api-key
CONST_GEOCODE_API_KEY = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" # ez most __használhatatlan__, szándékosan hamis kulcs ;)
CONST_DISTANCE_API_KEY = CONST_GEOCODE_API_KEY
# pontosító jellegű kiegészítések
CONST_ORSZAG = "Magyarország" # minden adatpont ebben az országban van
CONST_REGIO = "hu" # pontosító régió; még véletlenül sem az USA-ban található Budapest településre vagyunk kíváncsiak, hanem az itthonira :)
# várakozási idők két lekérdezés között (másodpercben)
CONST_SLEEP_GEOCODE_KOZOTT = 3
CONST_SLEEP_DISTANCEMATRIX_KOZOTT = 11
CONST_SLEEP_ERROR_KEZDETI = 15
CONST_SLEEP_ERROR_MAXIMUM = 30
Létrehozok új oszlopokat, ahol a földrajzi koordinátákat írom majd. Az ilyen típusú adatoknak hagyományosan kétféle leképezése ismert:
Most a tizedes törtszám leképezést fogom használni.
# két új oszlop a koordináták komponenseinek
for oszlop in ["geo_szelesseg", "geo_hosszusag"]:
df[oszlop] = None
df[oszlop] = df[oszlop].astype(float) # tizedes tört adattípus
df.info() # áttekintés; a DataFrame oszlopai és adattípusai
<class 'pandas.core.frame.DataFrame'> RangeIndex: 4 entries, 0 to 3 Data columns (total 6 columns): Megye 4 non-null object Irányítószám 4 non-null int64 Város 4 non-null object Közterület 4 non-null object geo_szelesseg 0 non-null float64 geo_hosszusag 0 non-null float64 dtypes: float64(2), int64(1), object(3) memory usage: 272.0+ bytes
df.head() # áttekintés; csak az első néhány értéket jelenítjük meg
Megye | Irányítószám | Város | Közterület | geo_szelesseg | geo_hosszusag | |
---|---|---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | NaN | NaN |
1 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | NaN | NaN |
2 | Budapest | 1052 | Budapest | Városház u. 9-11. | NaN | NaN |
3 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | NaN | NaN |
A Google Maps Geocoding API lekérdezését ketté bontom:
Lássuk a két kódot, mégpedig fordított sorrendben.
A Google válaszát annak szabványos struktúrája szerint dolgozom föl. JSON formátumban kérjem le a Google-től, amit Python dictionary típusként egyszerű tovább alakítani.
Több okból előfrodulhat, hogy a Google szerverétől nem érkezik rendes válasz:
Bizonyos esetekben érdemes változatlan formátumban újra (és újra, és újra...) lekérdezni; például ismeretlen hiba, nosza, várjunk egy keveset és próbáljuk újra! Más esetekben fölösleges várnunk (érvénytelen formátumban indított lekérést fölösleges megismételni).
def geocode_query(webcim, varakozas=CONST_SLEEP_ERROR_KEZDETI, max_varakozas=CONST_SLEEP_ERROR_MAXIMUM):
"""A Google Maps Geocoding API felé indított lekérdezések végrehajtása. Az eredmény Python dictionary (kulcs-érték szótár) típusú."""
rj = requests.get(webcim).json() # lekérdezést indítunk, és az eredményt JSON formátummá alakítjuk
if rj.get("status") == "OK" and len(rj.get("results", [])) > 0: # a Google Maps Geocoding API mondjuk elvileg akkor is visszaad egy üres "results" tömböt, ha nincs találat, de azért így a biztos...
# Itt persze lenne tér némi barkácsolásra, például hogy ne fixen a Google által fölkínált
# legelső lehetőséget használjuk (Pythonban: 0 indexű találat, rj["results"][0]),
# hanem egy másikat, esetleg többet is. Hiányos, zavaros, irányítószám nélküli címeknél
# lehet több eredményünk... Az egyszerűség kedvéért most csak a legelső szerepel.
return {"lat": rj["results"][0]["geometry"]["location"]["lat"],
"lng": rj["results"][0]["geometry"]["location"]["lng"],
"status_ok": 1} # remek, valódi eredményünk van
elif rj.get("status") == "UNKNOWN_ERROR" or rj.get("status") is None:
if varakozas > max_varakozas:
return {"lat": 0,
"lng": 0,
"status_ok": 0} # majd később kiszűrjük őket
else:
time.sleep(varakozas) # várakozunk
return geocode_query(webcim, varakozas*2) # növeljük a várakozási időt, s újra nekifutunk
else:
return {"lat": 0,
"lng": 0,
"status_ok": 0} # majd később kiszűrjük őket, és "INVALID_REQUEST", "MAX_ELEMENTS_EXCEEDED", "OVER_QUERY_LIMIT", "REQUEST_DENIED" esetén egyáltalán nem futunk neki ismét
A Google Maps Geocoding API felé indított lekérdezésnél maradhatnak pl. a magyar ékezetes karakterek az utcanevekben, semmi szükség őket átalakítani, a szóközöket azonban „+” jelre cserélem. Régiót, esetleg konkrét országot is megadok szűkítésként (van „Buda” az USA Texas államában is, például).
Paraméter, hogy az adott DataFrame hányadik oszlopában szerepel az irányítószám, a város, a cím, továbbá hogy a DataFrame hányadik oszlopában kell visszaadnom a földrajzi szélesség és hosszúság koordinátáit.
def geocode_dataframe(p, cim_oszlopok=(0, 1, 2), geo_oszlopok=(3, 4)):
"""A Google Maps Geocoding API felé indított lekérdezés összeállítása, és az eredmények tárolása."""
"""cim_oszlopok: irányítószám, város, városon belüli cím sorrendben kell a paraméter tuple-t érteni
geo_oszlopok: előbb a földrajzi szélesség, majd a földrajzi hosszúság oszlopa szerepel a tuple-ben"""
i = 0
while i < len(p):
lnk = "https://maps.googleapis.com/maps/api/geocode/json?address={varos}+{cim}+{irsz}+{orszag}®ion={region}&key={api_key}".format( \
cim = p.iloc[i, cim_oszlopok[2]].replace(" ", "+").strip(), \
varos = p.iloc[i, cim_oszlopok[1]].replace(" ", "+").strip(), \
irsz = str(p.iloc[i, cim_oszlopok[0]]), \
orszag = CONST_ORSZAG, \
region = CONST_REGIO, \
api_key = CONST_GEOCODE_API_KEY) # összeállítottuk a Google Maps Geocoding API lekérdezés webcímét
koordinatak = geocode_query(lnk) # megtörténik a tényleges lekérdezés
if koordinatak.get("status_ok") == 1:
for j in zip(geo_oszlopok, ["lat", "lng"]):
p.iloc[i, j[0]] = koordinatak.get(j[1]) # előbb a földrajzi szélesség, majd a földrajzi hosszúság
if i < len(p) - 1:
# Ajánlatos lehet pár másodperc szünetet tartani lekérdezések között, hogy a Google ne tekintse
# visszaélésszerű felhasználásnak. Az utolsó elem után persze már ne várakozzunk :)
time.sleep(CONST_SLEEP_GEOCODE_KOZOTT)
else:
for j in geo_oszlopok:
p.iloc[i, j] = None # explicit törlés, hogy már létező DataFrame-re újrafuttatva nehogy téves érték maradjon benne
i += 1
return p
A függvények definíciója után jöhet a tulajdonképpeni futtatás!
df = geocode_dataframe(df, cim_oszlopok=(1, 2, 3), geo_oszlopok=(4, 5)) # a Megye oszloppal nem kezdek semmit, de a többi oszlop pozíciója fontos paraméter
df.head() # áttekintés; csak az első néhány értéket jelenítjük meg
Megye | Irányítószám | Város | Közterület | geo_szelesseg | geo_hosszusag | |
---|---|---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 |
1 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 |
2 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 |
3 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 |
Amennyiben hiányos (üres) koordinátát találunk, tegyünk egy próbát, írjuk be az adott címet a Google Maps webböngészős felületére! Talán nem az API lekérdezéssel van ugyanis gond, hanem a Google Maps egyáltalán nem találja az adott címet!
Az eredményt Excel-fájlba mentem.
# írjuk ki az eredményt egy másik Excel-fájlba
writer = pd.ExcelWriter("Városháza (földrajzi koordinátákkal).xlsx", engine="xlsxwriter")
df.to_excel(writer, sheet_name="Munka1", index=False)
writer.save()
Az első feladattal tehát készen volnánk: előálltak a városházák geokoordinátái.
Második feladatként számoljuk ki a koordináták összes többi koordinátától való, légvonalban mért távolságát!
Mint azt földrajzórán megtanultuk, Földünk „Föld-alakú”, azaz „geoid” formájú, nem pedig tökéletes gömb. Mégis annak szokás tekinteni, és a légvonalban mért távolságot egy gömbfelszín két pontja közötti, a felszínen mért legrövidebb távolságként értelmezni.
Letöltök egy kis Python modult (pip install haversine
), és felhasználom. Két, Python tuple formájában beadott földrajzi koordináta távolságát adja vissza kilométerben (igény esetén mérföldben).
# illusztráció: földrajzi koordináták távolsága légvonalban, tökéletes gömbnek tekintett Föld felszínén mérve
# haversine Python-modul, és https://en.wikipedia.org/wiki/Haversine_formula
koordinatak_budapest = (47.5, 19.03) # Python tuple, szélesség és hosszúság
koordinatak_parizs = (48.8530511, 2.3496311) # Python tuple, szélesség és hosszúság
for i, mertekegyseg in enumerate(["kilométer", "mérföld"]):
tav = haversine.haversine(koordinatak_budapest, koordinatak_parizs, miles=bool(i==1)) # alapból kilométer, s miles=True esetén mérfőld
s = "{:{szeles}.{tizedes}f} {egyseg}".format(tav, szeles=10, tizedes=3, egyseg=mertekegyseg)
print(s)
1243.399 kilométer 772.612 mérföld
A koordinátás DataFrame-ből (táblázatból) párosításokat készítek: „egyirányú” módon, tehát pl. egy Budapest-Debrecen távot nem érdemes kétszer kiszámoltatni, oda-vissza. Egy pontnak az önmagától vett távolságára sem vagyunk kíváncsiak, értelemszerűen.
# Minden koordinátának minden másikkal vett párosítása, de csak egyszer (nem "oda-vissza")
df2 = pd.merge(df.reset_index().assign(descartes_segedvaltozo=1),
df.reset_index().assign(descartes_segedvaltozo=1),
on="descartes_segedvaltozo",
suffixes=("_1", "_2")) \
.drop("descartes_segedvaltozo", axis=1) \
.query("index_1 < index_2") \
.sort_values(["index_1", "index_2"]) \
.reset_index(drop=True) \
.drop(["index_1", "index_2"], axis=1)
df2.head(10) # áttekintés; csak az első néhány értéket jelenítjük meg
Megye_1 | Irányítószám_1 | Város_1 | Közterület_1 | geo_szelesseg_1 | geo_hosszusag_1 | Megye_2 | Irányítószám_2 | Város_2 | Közterület_2 | geo_szelesseg_2 | geo_hosszusag_2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 |
1 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 |
2 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 |
3 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 |
4 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 |
5 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 |
Alkalmazzuk a föntebb bemutatott modulban található függvényt, s az így előálló távolságokat új oszlopként adjuk hozzá a DataFrame-hez.
tav = df2.apply(lambda x: haversine.haversine((x["geo_szelesseg_1"], x["geo_hosszusag_1"]), (x["geo_szelesseg_2"], x["geo_hosszusag_2"])), axis=1)
df2["tavolsag_legvonalban"] = tav
df2.head(10) # áttekintés; csak az első néhány értéket jelenítjük meg
Megye_1 | Irányítószám_1 | Város_1 | Közterület_1 | geo_szelesseg_1 | geo_hosszusag_1 | Megye_2 | Irányítószám_2 | Város_2 | Közterület_2 | geo_szelesseg_2 | geo_hosszusag_2 | tavolsag_legvonalban | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | 180.820625 |
1 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | 161.078935 |
2 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 80.592251 |
3 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | 193.123654 |
4 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 161.550872 |
5 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 81.147876 |
Íme, a második feladat is elkészült: megtudtuk a koordináták légvonalban mért távolságát. A Python Pandas DataFrame jobb oldali szélső oszlopában immár ez látható.
Harmadik feladatként számoljuk ki a koordináták összes többi koordinátától való, közúton mért távolságát!
Ezt a Google Maps Distance Matrix API-val tudjuk lekérdezni. A Google felé földrajzi koordinátákat kell küldenünk, és igazán változatos beállítási lehetőségeink vannak:
def distancematrix_query(webcim, varakozas=CONST_SLEEP_ERROR_KEZDETI, max_varakozas=CONST_SLEEP_ERROR_MAXIMUM):
"""A Google Maps Distance Matrix API felé indított lekérdezések végrehajtása. Az eredmény Python dictionary (kulcs-érték szótár) típusú."""
tav = None
status_ok = 0
rj = requests.get(webcim).json()
if rj.get("status") == "OK":
try:
# Itt persze lenne tér némi barkácsolásra, például hogy ne fixen a Google által fölkínált
# legelső lehetőséget használjuk (Pythonban: 0 indexű találat, rj["rows"][0]),
# hanem egy másikat, esetleg többet is. Az egyszerűség kedvéért most csak a legelső szerepel.
# Tudtommal a Google API válaszában a "distance" amúgy mindig méterben áll rendelkezésre,
# és a mérföld/kilométer beállítás csak a "text" elemet befolyásolja.
tav = int(rj["rows"][0]["elements"][0]["distance"]["value"]) / 10**3 # kilométer-átváltás
status_ok = 1
except:
pass
return {"status_ok": status_ok,
"tav": tav}
elif rj.get("status") == "UNKNOWN_ERROR" or rj.get("status") is None:
if varakozas > max_varakozas:
return {"status_ok": status_ok,
"tav": tav}
else:
time.sleep(varakozas)
return distancematrix_query(webcim, varakozas*2)
else:
return {"status_ok": status_ok,
"tav": tav} # "INVALID_REQUEST", "MAX_ELEMENTS_EXCEEDED", "OVER_QUERY_LIMIT", "REQUEST_DENIED" esetén nem futunk neki ismét
Ha a kezdő- vagy végpont koordinátája nem elérhető, akkor be sem küldöm az API-nak útvonaltervezésre, így gyorsítva a futást. A koordináták oszlopait paraméterként adom meg, és ezt mindig földrajzi szélesség, majd földrajzi hosszúság sorrendben teszem.
def distancematrix_dataframe(p, geo_oszlopok=((0, 1), (2, 3)), tav_oszlop=4):
"""A Google Maps Distance Matrix API felé indított lekérdezés összeállítása, és az eredmények tárolása."""
i = 0
while i < len(p):
if any([np.isnan(p.iloc[i, geo_oszlopok[j][k]]) for j in range(2) for k in range(2)]): # hiányzó koordináta van, ezért nem számolunk távolságot
p.iloc[i, tav_oszlop] = None # explicit törlés, hogy már létező DataFrame-re újrafuttatva nehogy téves érték maradjon benne
else: # nincs hiányzó koordináta, tehát számolunk távolságot
# legyártjuk a Google Maps Distance Matrix API által várt, vesszővel elválasztott, tizedes ponttal működő koordinátás input string-eket, pl. "46.254568,20.148387"
geo1 = "{},{}".format(*(p.iloc[i, geo_oszlopok[0][j]] for j in range(2)))
geo2 = "{},{}".format(*(p.iloc[i, geo_oszlopok[1][j]] for j in range(2)))
s = "https://maps.googleapis.com/maps/api/distancematrix/json?origins={}&destinations={}&mode=driving&units=metric&avoid=ferries&key={api_key}".format(geo1, geo2, api_key=CONST_DISTANCE_API_KEY) # a lekérdezés webcíme; autózás (driving) helyett akár gyaloglás (walking) vagy biciklizés (bicycling) is megadható! Utóbbi esetben városon belül előnyben részesíti a kiépített bicikliutakat.
valasz = distancematrix_query(s) # lekérjük a távolságot az API-tól
if valasz.get("status_ok") == 1:
p.iloc[i, tav_oszlop] = valasz.get("tav")
if i < len(p) - 1:
# Ajánlatos lehet pár másodperc szünetet tartani lekérdezések között, hogy a Google ne tekintse
# visszaélésszerű felhasználásnak. Az utolsó elem után persze már ne várakozzunk :)
time.sleep(CONST_SLEEP_DISTANCEMATRIX_KOZOTT)
i += 1
return p
Új oszlopot hozok létre, oda írom majd a lekérdezés eredményét.
df2["tavolsag_kozuton"] = None
df2["tavolsag_kozuton"] = df2["tavolsag_kozuton"].astype(float) # tizedes tört adattípus
df2.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 6 entries, 0 to 5 Data columns (total 14 columns): Megye_1 6 non-null object Irányítószám_1 6 non-null int64 Város_1 6 non-null object Közterület_1 6 non-null object geo_szelesseg_1 6 non-null float64 geo_hosszusag_1 6 non-null float64 Megye_2 6 non-null object Irányítószám_2 6 non-null int64 Város_2 6 non-null object Közterület_2 6 non-null object geo_szelesseg_2 6 non-null float64 geo_hosszusag_2 6 non-null float64 tavolsag_legvonalban 6 non-null float64 tavolsag_kozuton 0 non-null float64 dtypes: float64(6), int64(2), object(6) memory usage: 752.0+ bytes
Az adott Python Pandas DataFrame újabb oszloppal bővült, s a legutolsó (jobb szélső) oszlopban lesz látható a friss eredményünk.
Jöhet a tulajdonképpeni futtatás!
df2 = distancematrix_dataframe(df2, geo_oszlopok=((4, 5), (10, 11)), tav_oszlop=13) # paraméterként az oszlop-indexek
df2.head(10) # áttekintés; csak az első néhány értéket jelenítjük meg
Megye_1 | Irányítószám_1 | Város_1 | Közterület_1 | geo_szelesseg_1 | geo_hosszusag_1 | Megye_2 | Irányítószám_2 | Város_2 | Közterület_2 | geo_szelesseg_2 | geo_hosszusag_2 | tavolsag_legvonalban | tavolsag_kozuton | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | 180.820625 | 216.902 |
1 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | 161.078935 | 171.474 |
2 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 80.592251 | 90.825 |
3 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | 193.123654 | 231.040 |
4 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 161.550872 | 182.643 |
5 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 81.147876 | 84.071 |
Készen vagyunk, a harmadik feladat eredménye a közúton mért távolság.
df2["kozut_legvonal_arany"] = df2["tavolsag_kozuton"] / df2["tavolsag_legvonalban"] # csak kiváncsiságból
df2.head(10)
Megye_1 | Irányítószám_1 | Város_1 | Közterület_1 | geo_szelesseg_1 | geo_hosszusag_1 | Megye_2 | Irányítószám_2 | Város_2 | Közterület_2 | geo_szelesseg_2 | geo_hosszusag_2 | tavolsag_legvonalban | tavolsag_kozuton | kozut_legvonal_arany | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | 180.820625 | 216.902 | 1.199542 |
1 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | 161.078935 | 171.474 | 1.064534 |
2 | Csongrád | 6720 | Szeged | Széchenyi tér 10. | 46.254568 | 20.148387 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 80.592251 | 90.825 | 1.126969 |
3 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | 193.123654 | 231.040 | 1.196332 |
4 | Hajdú-Bihar | 4024 | Debrecen | Piac u. 20. | 47.529631 | 21.625422 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 161.550872 | 182.643 | 1.130560 |
5 | Budapest | 1052 | Budapest | Városház u. 9-11. | 47.495268 | 19.054405 | Bács-Kiskun | 6000 | Kecskemét | Kossuth tér 1. | 46.907950 | 19.691978 | 81.147876 | 84.071 | 1.036022 |
# írjuk ki az eredményt egy Excel-fájlba
writer = pd.ExcelWriter("Városháza (távolságok).xlsx", engine="xlsxwriter")
df2.to_excel(writer, sheet_name="Munka1", index=False)
writer.save()
Ennyi hát, ízelítőül.