Kurs

In diesem Tutorial lernst du zwei Pakete kennen, die sich besonders für die Arbeit mit Geodaten eignen: geopandas und Shapely. Anschließend nutzt du beide, um Geodaten mit Python einzulesen und die Spur des Hurrikans Florence vom 30. August bis zum 18. September zu visualisieren.
Was sind Geodaten?
Räumliche Daten, Geodaten, GIS-Daten oder Geodata sind Bezeichnungen für numerische Daten, die die geografische Lage eines physischen Objekts wie eines Gebäudes, einer Straße, eines Ortes, einer Stadt, eines Landes usw. gemäß einem geografischen Koordinatensystem bestimmen. Aus räumlichen Daten kannst du nicht nur die Lage, sondern auch Länge, Größe, Fläche oder Form eines Objekts ableiten. Ein Beispiel sind Koordinaten eines Objekts wie Breite, Länge und Höhe. Geografische Informationssysteme (GIS) oder andere spezialisierte Software lassen sich nutzen, um Geodaten zu speichern, zu visualisieren, zu bearbeiten und zu analysieren.
Warum Geodaten?
Geodaten haben unzählige Anwendungen im Alltag. Ein Beispiel ist die Karten-App, mit der du von A nach B navigierst. Ein weiteres siehst du praktisch täglich im Wetterbericht.

Genau: Geodaten stellen Positionsinformationen in Relation zu ihrer Umgebung dar – dein Haus auf dem Stadtplan, der Hurrikan auf der Weltkarte und so weiter. In diesem Tutorial nimmst du den zerstörerischen Hurrikan Florence unter die Lupe und verfolgst seinen Weg.
Benötigte Pakete
Bitte nicht überspringen. Dieser Teil ist wichtig. Wenn du unsicher bist, ob alle Voraussetzungen erfüllt sind, prüfe sie lieber noch einmal. Zuerst brauchst du die folgenden Pakete installiert.
- Pandas: Datenstrukturen und Tools für die Datenanalyse
- Numpy: grundlegendes Paket für wissenschaftliches Rechnen mit Python
- SciPy: (ausgesprochen „Sigh Pie“) Python-basiertes Open-Source-Ökosystem für Mathematik, Wissenschaft und Technik
- RTree: ctypes-Python-Wrapper für libspatialindex mit erweiterten räumlichen Indexfunktionen
- GDAL: Bibliothek zum Konvertieren von Raster- und Vektor-Geodatenformaten
- Fiona: Liest und schreibt räumliche Datendateien
- Shapely: Geometrische Objekte, Prädikate und Operationen
- GeoPandas: Erweitert die in pandas verwendeten Datentypen für räumliche Operationen auf Geometrietypen.
- PySAL: Bibliothek mit Funktionen für räumliche Analysen in Python zur Entwicklung von High-Level-Anwendungen.
- Matplotlib: 2D-Plotbibliothek für Python
- Missingno: Visualisierung fehlender Daten in Python
Installiere die Pakete in der obigen Reihenfolge, damit alles reibungslos funktioniert. Manche Pakete sind Voraussetzungen für andere, zum Beispiel benötigt GeoPandas das Paket Shapely, und für Shapely müssen RTree, GDAL und Fiona vorhanden sein. Am einfachsten installierst du Pakete mit: pip install PACKAGE_NAME
Wenn du Windows nutzt und die Installation so nicht klappt, findest du auf dieser Website passende Wheels zum Herunterladen und kannst sie mit pip install PATH_TO_PACKAGE installieren.
Zu den Daten
Wie du sicher mitbekommen hast, ist der verheerende Hurrikan Florence über Teile der US-Ostküste gezogen und hat Schäden von geschätzt 17 Milliarden USD hinterlassen. Dieses Tutorial zeigt dir, wo er entstanden ist, wann und wo er an Stärke gewann, und hilft dir, dieses Naturereignis in Python zu analysieren. Es gibt viele Websites mit Informationen zu diesem Hurrikan. Dieses Portal stellt zum Beispiel Daten zu Stürmen und Hurrikans in den USA von 1902 bis 2018 bereit – reichlich Material für weitere Analysen. Für dieses Tutorial verwenden wir nur die Daten zu Hurrikan Florence
Außerdem nutzt du die US-Karten-Geodaten aus dem Netz. Der Blogpost von Eric Celeste stellt diverse Grenzdatensätze für US-Countys und -Bundesstaaten bereit. Hier verwenden wir die GeoJSON-Datei „US States, 5m“.
# Load all importance packages
import geopandas
import numpy as np
import pandas as pd
from shapely.geometry import Point
import missingno as msn
import seaborn as sns
import matplotlib.pyplot as plt
% matplotlib inline
Schauen wir uns zunächst den ersten Geodaten-DataFrame an: US States Geodata.
# Getting to know GEOJSON file:
country = geopandas.read_file("data/gz_2010_us_040_00_5m.json")
country.head()

Wenn du den Typ des geladenen DataFrames prüfst, siehst du: Es ist ein GeoDataFrame und besitzt damit alle gewohnten Eigenschaften eines Pandas-DataFrame.
type(country)
geopandas.geodataframe.GeoDataFrame
Der Datentyp der Spalte mit den Koordinaten ist eine GeoSeries.
type(country.geometry)
geopandas.geoseries.GeoSeries
Jeder Wert in der GeoSeries ist ein Shapely-Objekt. Mögliche Typen sind:
- Point
- Line
- Polygon
- MultiPolygon
Jeder Typ passt zu anderen realen Objekten: Point z. B. für ein Gebäude, Line für eine Straße, Polygon für eine Stadt und MultiPolygon für ein Land mit mehreren zusammenhängenden Flächen. Mehr Details zu den Geometrietypen findest du hier: https://shapely.readthedocs.io/en/stable/manual.html#geometric-objects
type(country.geometry[0])
shapely.geometry.multipolygon.MultiPolygon
Wie bei einem Pandas-DataFrame besitzt auch ein GeoDataFrame das Attribut plot, das die Geometrie nutzt, um eine Karte zu zeichnen:
country.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x1cfe68c1358>

Wie du siehst, wirkt die US-Karte recht klein im Vergleich zum Rahmen. Das liegt daran, dass Alaska, Hawaii und Puerto Rico enthalten sind und weit auseinanderliegen. Für dieses Tutorial können wir Alaska und Hawaii ausklammern, da der Hurrikan dort nicht in der Nähe war. Außerdem kannst du Größe und Farbe anpassen:
# Exclude Alaska and Hawaii for now
country[country['NAME'].isin(['Alaska','Hawaii']) == False].plot(figsize=(30,20), color='#3B3C6E');

Gar nicht so schwer, oder? Jetzt hast du die US-Karte – laden wir die Hurrikan-Daten:
florence = pd.read_csv('data/florence.csv')
florence.head()

Explorative Datenanalyse
Das ist immer der erste Schritt beim Laden eines Datensatzes:
- Infos und Datentypen prüfen
- Fehlende Werte identifizieren
- Statistische Kenndaten betrachten
florence.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 105 entries, 0 to 104
Data columns (total 11 columns):
AdvisoryNumber 105 non-null object
Date 105 non-null object
Lat 105 non-null float64
Long 105 non-null float64
Wind 105 non-null int64
Pres 105 non-null int64
Movement 105 non-null object
Type 105 non-null object
Name 105 non-null object
Received 105 non-null object
Forecaster 104 non-null object
dtypes: float64(2), int64(2), object(7)
memory usage: 9.1+ KB
Fehlende Werte prüfen wir mit dem Paket missingno. Es visualisiert Missing Values sehr anschaulich. Wie unten zu sehen, fehlt nur ein Wert in der Spalte „Forecaster“, die wir hier nicht benötigen. Den können wir ignorieren.
# Notice you can always adjust the color of the visualization
msn.bar(florence, color='darkolivegreen');

Schauen wir uns einige Statistiken an – etwa die mittlere, maximale und minimale Windgeschwindigkeit dieses Hurrikans.
# Statistical information
florence.describe()
| Lat | Long | Wind | Pres | |
|---|---|---|---|---|
| count | 105.000000 | 105.000000 | 105.000000 | 105.000000 |
| mean | 25.931429 | 56.938095 | 74.428571 | 981.571429 |
| std | 7.975917 | 20.878865 | 36.560765 | 22.780667 |
| min | 12.900000 | 18.400000 | 25.000000 | 939.000000 |
| 25% | 18.900000 | 41.000000 | 40.000000 | 956.000000 |
| 50% | 25.100000 | 60.000000 | 70.000000 | 989.000000 |
| 75% | 33.600000 | 76.400000 | 105.000000 | 1002.000000 |
| max | 42.600000 | 82.900000 | 140.000000 | 1008.000000 |
Oft musst du Daten bereinigen und auf die relevanten Spalten reduzieren. Hier benötigen wir Zeit, Koordinaten (Breite und Länge), Windgeschwindigkeit, Luftdruck und Name. Movement und Type sind optional, den Rest können wir entfernen.
# dropping all unused features:
florence = florence.drop(['AdvisoryNumber', 'Forecaster', 'Received'], axis=1)
florence.head()

Wenn du die Daten allein plottest, musst du die Koordinaten meist nicht weiter anfassen. Sollen sie wie auf einer Karte wirken, ist jedoch wichtig, Längen- und Breitengrade zu prüfen. Hier liegen die Längengrade westlich, wir müssen also ein „-“ voranstellen, damit die Darstellung korrekt ist:
# Add "-" in front of the number to correctly plot the data:
florence['Long'] = 0 - florence['Long']
florence.head()

Jetzt können wir Breiten- und Längengrad kombinieren, um Hurrikan-Koordinaten zu erzeugen, die wir anschließend für die Visualisierung in GeoPoints umwandeln.
# Combining Lattitude and Longitude to create hurricane coordinates:
florence['coordinates'] = florence[['Long', 'Lat']].values.tolist()
florence.head()

# Change the coordinates to a geoPoint
florence['coordinates'] = florence['coordinates'].apply(Point)
florence.head()

Prüfen wir den Typ des DataFrames florence und der Spalte coordinates. Es sind ein Pandas-DataFrame und eine Pandas-Series.
type(florence)
pandas.core.frame.DataFrame
type(florence['coordinates'])
pandas.core.series.Series
Nach der Umwandlung in Geodaten prüfen wir erneut: Jetzt sind es GeoDataFrame und GeoSeries.
# Convert the count df to geodf
florence = geopandas.GeoDataFrame(florence, geometry='coordinates')
florence.head()

type(florence)
geopandas.geodataframe.GeoDataFrame
type(florence['coordinates'])
geopandas.geoseries.GeoSeries
Beachte: Auch als GeoDataFrame bzw. GeoSeries verhalten sich die Objekte wie normale DataFrames und Series. Du kannst also weiterhin filtern, gruppieren oder Min-, Max- und Mittelwerte berechnen.
# Filtering from before the hurricane was named.
florence[florence['Name']=='Six']

# Groupping by name to see how many names it has in the data set:
florence.groupby('Name').Type.count()
Name
FLORENCE 6
Florence 85
SIX 4
Six 10
Name: Type, dtype: int64
Die mittlere Windgeschwindigkeit von Hurrikan Florence ermitteln:
print("Mean wind speed of Hurricane Florence is {} mph and it can go up to {} mph maximum".format(round(florence.Wind.mean(),4),
florence.Wind.max()))
Mean wind speed of Hurricane Florence is 74.4286 mph and it can go up to 140 mph maximum
Die durchschnittliche Windgeschwindigkeit von Hurrikan Florence beträgt damit 74,43 Meilen pro Stunde (119,78 km/h), das Maximum liegt bei 140 Meilen pro Stunde (225,308 km/h). Um ein Gefühl für diese Kräfte zu bekommen: Die Beaufortskala, entwickelt von der britischen Royal Navy, beschreibt die Wirkung des Windes auf Wasser und Land. Bereits bei 48 bis 55 mph können Bäume brechen oder entwurzelt werden und „erhebliche Gebäudeschäden“ auftreten.

Da möchtest du nicht draußen sein.
Visualisierung
Wie beim Pandas-DataFrame hat auch ein GeoDataFrame das Attribut .plot. Es nutzt die Koordinaten der GeoDataFrame, um sie auf einer Karte zu platzieren. Schau dir das an:
florence.plot(figsize=(20,10));

Was ist passiert? Du siehst nur lauter Punkte ohne Kontext. Ist etwas kaputt?
Nein. Dieser DataFrame enthält lediglich die Positionsdaten des Hurrikans zu verschiedenen Zeitpunkten – also lassen sich ohne Basiskarte nur Punkte darstellen.
Als Nächstes plotten wir die Positionen auf der US-Karte, um zu sehen, wo Florence entlangzog und wie stark er jeweils war. Dafür verwenden wir die US-Karte (vom Anfang) als Basis und zeichnen die Hurrikan-Positionen darüber.
# Plotting to see the hurricane overlay the US map:
fig, ax = plt.subplots(1, figsize=(30,20))
base = country[country['NAME'].isin(['Alaska','Hawaii']) == False].plot(ax=ax, color='#3B3C6E')
# plotting the hurricane position on top with red color to stand out:
florence.plot(ax=base, color='darkred', marker="*", markersize=10);

Sieht gut aus! Jetzt runden wir das Ganze mit weiteren Details ab:
- Titel hinzufügen
- Positionen nach Windgeschwindigkeit einfärben, um die Stärke beim Auftreffen zu sehen
- Achsen ausblenden
- Legende ergänzen
- Ergebnis als Bilddatei speichern
fig, ax = plt.subplots(1, figsize=(20,20))
base = country[country['NAME'].isin(['Alaska','Hawaii']) == False].plot(ax=ax, color='#3B3C6E')
florence.plot(ax=base, column='Wind', marker="<", markersize=10, cmap='cool', label="Wind speed(mph)")
_ = ax.axis('off')
plt.legend()
ax.set_title("Hurricane Florence in US Map", fontsize=25)
plt.savefig('Hurricane_footage.png',bbox_inches='tight');

Der Hurrikan war also vor der Küste am stärksten. Mit Annäherung an Land verlor er an Kraft, doch selbst bei 60 bis 77 mph kann er noch schwere Schäden anrichten.
Fazit
Starke Arbeit! Du hast die wichtigsten Schritte kennengelernt, um mit Geodaten in Python zu arbeiten. Außerdem weißt du jetzt, wie du Geodaten visualisierst und Formen, Farben sowie Overlays so anpasst, dass sie eine Geschichte erzählen. Wenn du üben möchtest, findest du online massenhaft frei verfügbare Geodaten. Ein Beispiel ist die oben verlinkte Wetter-Website.
Für weiterführende Informationen schau in dieses Buch: „Python Geospatial Development Essentials“ von Karim Bahgat (2015).
Wenn du mit mir in Kontakt treten möchtest, schreib mir gern eine E‑Mail an dqvu.ubc@gmail.com oder vernetze dich via LinkedIn. Viel Spaß beim Lernen und bleib sicher!
Wenn du mehr über Geodaten in Python lernen willst, sieh dir den DataCamp-Kurs Visualizing Geospatial Data in Python an.
Die in diesem Tutorial verwendeten Daten findest du hier:
