Ich bin neu hier im Forum und dies ist mein erster Beitrag, daher gerne darauf aufmerksam machen, falls etwas nicht korrekt ist oder fehlen sollte beim untenstehenden Beschrieb. Bei einem persönlichen Projekt bin ich auf gewisse Performance-Probleme gestossen bzw. funktioniert meine For-Schleife zwar , aber sie beendet sich nicht, obwohl alle Pandas-Zeilen "durchgearbeitet" wurden.
Kurzer Beschrieb meines privaten Projektes:
1. Ich habe mir einen Scraper gebaut mit Scrapy, der gewisse Daten sammelt und mir in eine CSV-Datei schreibt. Bei jedem Scrapy-Durchlauf werden die neu generierten Daten in der gleichen csv-Datei ergänzt inkl. Generierungs-Datum. Unter anderem beinhaltet diese CSV-Datei eine Spalte mit einer Adresse. In einer neue Spalte möchte ich dann die Latitude/Longitude ergänzen, um es auf einer interaktiven Karte anzuzeigen.
2. Die gescrapten Daten werden bereinigt und in die richtige Form gebracht, um sie danach in einem interaktiven Dashboard (mit Dash) darzustellen.
Meine Probleme:
1. Die Schwierigkeit besteht darin, dass es bei jedem Scraping-Durchgang ca. 1'000 neue Zeilen zur CSV-Datei hinzukommen. Teils sind die Latitude/Longitude bereits mit Geopy generiert worden aus der Adress-Spalte, neu hinzugefügte Zeilen sind aber ohne Latitude/Longitude vorhanden. Untenstehender Python-Code liest diese CSV-Datei jeweils als Pandas DataFrame ein, und mit einer For-Schleife iteriere ich über die DataFrame-Zeilen und falls die Spalte "Latitude/Longitude" nicht "nan" ist, soll es weitergehen und sonst soll die Spalte "Latitude/Longitude" mittels Geolocator aus der Spalte "Wohnungs-Adresse" mit der Latitude und Longitude befüllt werden. Soweit funktioniert die For-Schleife, ich muss diese aber in der Pycharm-Console selbst abbrechen, sonst läuft sieendlos. Vermutlich habe ich einen Überlegungsfehler, weshalb die For-Schleife nicht beendet wird und endlos läuft.
2. Die Performance ist nicht wirklich gut...einerseits aufgrund der iterrows()-Anwendung und der apply-Benutzung. Fällt euch da vielleicht eine elegantere Lösung ein für mein Vorhaben? Die Daten werden immer mehr und wenn ich immer für alle Zeilen die Lat/Long generieren müsste, würde dies irgendwann auch aufgrund der Beschränkung nicht mehr funktionieren. Daher möchte ich immer nur die fehlenden Lat/Long-Werte jeweils ergänzen.
So sehen die generierten Daten in der CSV-Datei aus:
2022-12-21,serp_responsive#badge_new_building_lite,2.5,55,0,"Rue du Port 31, 1820 Montreux, VD",VD,,clean
2022-12-21,serp_responsive#badge_new_building_lite,3.5,88,590000,"Telmoos 10, 1716 Plaffeien, FR",FR,,clean
So mit generierter Latitude/Longitude aus der For-Schleife:
2022-12-21,serp_responsive#badge_new_building_lite,2.5,55,0,"Rue du Port 31, 1820 Montreux, VD",VD,"(46.442212049999995, 6.896893654157193)",clean
2022-12-21,serp_responsive#badge_new_building_lite,3.5,88,590000,"Telmoos 10, 1716 Plaffeien, FR",FR,"(46.7372459, 7.2921369)",clean
Code: Alles auswählen
import pandas as pd
import geopy.geocoders as geo
from geopy.extra.rate_limiter import RateLimiter
# csv-Datei wird eingelesen (Spalte "Wohnungs_Adresse" mit der Adresse; Spalte "Latitude/Longitude" mit teils generierten Koordinaten und neue Zeilen werden mit "nan" hinterlegt
df = pd.read_csv(r'output\appartements_bereinigt.csv', delimiter=',', parse_dates=True)
# Geolocator Einstellungen für Generierung von Koordinaten aus einer Adresse
geolocator = geo.Nominatim(user_agent='Daten_Bereinigung')
geo.options.default_timeout = 10
geocode = RateLimiter(geolocator.geocode, min_delay_seconds=2)
# Funktion zur Generierung von Latitude/Longitude (try/except, da es nicht bei jeder Adresse möglich ist aufgrund unvollständiger Angaben)
def eval_results(x):
try:
return (x.latitude, x.longitude)
except:
return (None, None)
# Die Schleife prüft, ob bereits Latitude/Longitude in jeder Zeile vorhanden ist (falls Zeilen nicht "nan" wird die Schleife weitergeführt), falls nicht, werden diese generiert, durch apply-Anwendung von Geolocator und obiger Python-Funktion
anzahl_zeilen_df = len(df)
for row in df[['Latitude/Longitude']].iloc[:anzahl_zeilen_df].iterrows():
if str(row[1][0]) != 'nan':
continue
else:
df['Latitude/Longitude'] = df['Wohnungs_Adresse'].apply(geolocator.geocode, timeout=30).apply(
lambda x: eval_results(x))
df.to_csv(r'output_clean\appartements_clean_lat_lon.csv', sep=',', index=False)
Falls ihr noch mehr Angaben braucht, gerne melden, dann werde ich diese ergänzen.
Viele Grüsse
Dario