›  Demo-PY2: Datenverwaltung mit Pandas

Nachdem in Demo-PY1: Python-Tutorial der erste Einstieg in die Syntax erfolgt ist, zeigt Demo-PY2 im nächsten Schritt, wie die Datenverwaltung und - visualisierung mit Hilfe der Python-Bibliothek Pandas durchgeführt wird. Ein Zeitreihen-Datensatz zum Stromverbrauch in Deutschland aus der Open-Power-System-Data (OPSD)-Plattform dient uns dabei als Anwendungsbeispiel. Die Daten werden in der interaktiven, webbasierten Anwendungsumgebung Jupyter Notebook analysiert. Im letzten Schritt der Demo erfolgt die Datenvisualisierung mit Hilfe der Bibliothek Matplotlib.

info-icon Motivation

Bei der Datenanalyse ist das Einlesen und Aufbereiten der Daten der erste und aufwendigste Schritt, da die Daten selten in der benötigten Form schon vorliegen. In vielen Fällen enthält die externe Datenquelle (z.B. eine CSV-Datei) mehr Daten als benötigt werden, oder einzelne Datenwerte fehlen, oder haben das falsche Format.

Python stellt drei leistungsfähige Bibliotheken für die Verarbeitung und Visualisierung von Daten zur Verfügung: Numpy, Pandas, Matplotlib, deren typische Verwendung wir an einem konkreten Anwendungsfall veranschaulichen.

Warum Pandas?

Pandas ist eine Open-Source-Bibliothek für die Programmiersprache Python und bietet leistungsstarke, benutzerfreundliche Datenstrukturen und Funktionen für den Zugriff auf Datentabellen, siehe pandas.pydata.org. In diesem Abschnitt wird die Bibliothek Pandas eine zentrale Rolle spielen, da sie es ermöglicht, große CSV-Dateien mit Zeitreihen-Daten in Pandas-Datenstrukturen ("DataFrames") zu konvertieren und die Daten weiter zu bearbeiten. Pandas-Funktionen wie iloc(), loc(), resample() werden verwendet, um Zeilen / Spalten / Zellen auszuwählen und Zeitreihen-Daten zu gruppieren und aggregieren.

Warum Matplotlib (und Seaborn)?

Matplotlib ist eine Python-Programmbibliothek für die graphische Darstellung mathematischer Funktionen und vom Funktionsumfang her vergleichbar mit MATLABs Plotting-Funktionen.

Seaborn ist eine Matplotlib-Erweiterung, die speziell auf Pandas Dataframes abgestimmt ist. Mit Hilfe der seaborn-Funktionen können graphische Darstellungen verschönert und professioneller gestaltet werden, z.B. kann man verschiedene Farbschemen auswählen.

info-iconÜbersicht

Demo-PY2 ist in 5 Abschnitte gegliedert. Zunächst wird der OPSD-Datensatz beschrieben und die Fragestellung, die wir mit unserer Datenvisualisierung beantworten wollen. Danach wird die Erstellung des Jupyter Notebooks und Vorbereitung benötigter Bibliotheken erläutert. In den folgenden Abschnitten beschreiben wir die Datenverwaltung mit Pandas und Datenvisualisierung mit Matplotlib.

  1. Der OPSD-Datensatz

  2. Jupyter Notebook erstellen

  3. Datenverwaltung mit Pandas

  4. Aufbereitung des OPSD-Datensatzes

  5. Datenvisualisierung mit Matplotlib

  6. YouTube-Video

Der OPSD-Datensatz

Open Power System Data ist eine offene Plattform für Energieforscher, die europaweit gesammelte Energiedaten in Form von csv-Dateien und sqlite-Datenbanken zur Verfügung stellt. Die Daten können kostenlos heruntergeladen und genutzt werden. Die Plattform wird von einem Konsortium (Europa-Universität Flensburg, TU Berlin, DIW Berlin und Neon Neue Energieökonomik) betrieben, mit dem Ziel, die Energieforschung zu unterstützen.

Für unsere Demo verwenden wir als Basis einen OPSD-Zeitreihen-Datensatz zur elektrischen Energieerzeugung in Deutschland für den Datenzeitraum: 01.01.2016 - 31.12.2018 mit einer stündlichen Auflösung.

Wir wollen Fragen beantworten wie: Wie ändert sich der Verbrauch von Strom insgesamt, Solar- und Windenergie über die Jahre? Wann im Laufe eines Jahres ist der Verbrauch am höchsten?

Jupyter Notebook erstellen

Für die Datenverwaltung und Datenvisualisierung wird ein Jupyter-Notebook erstellt. Über Programme öffnen wir die Jupyter Notebooks-Anwendung und erstellen mit Hilfe des Menüpunkts "New" ein neues Python3-Notizbuch mit dem Namen elab2go-Demo-PY2.

Die Details der Verwendung von Jupyter Notebooks sind im Abschnitt Jupyter Notebooks verwenden beschrieben.

Datenverwaltung mit Pandas

Pandas verfügt über zwei Datenstrukturen, Series und DataFrames, und eine Vielzahl von Funktionen, mit denen man diese Datenstrukturen aufbereiten und manipulieren kann. Die Pandas-Funktionen lassen sich einteilen in Funktionen für das Laden und Speichern von Daten, Funktionen für die Datenaufbereitung, Funktionen für die Aggregation von Daten, und Funktionen zum Visualisieren ("Plotten") der Daten.

Eine Series ist ein eindimensionales indizierbares Objekt, das Daten in einer Zeile oder Spalte speichert. Die einfachste Series entsteht aus einer Liste von Daten:

  import pandas as pd 
  name = pd.Series(["Max Muster", "Anna Test", "John Doe"]) 
  adresse = pd.Series(["Schoenstrasse 11", "Unter de Linden 2", "Amperstrasse 1"]) 
  tel = pd.Series(["0151 (345678)", "0171 (123456)", "0161 (987654)"]) 
  print(name) 

Ein DataFrame repräsentiert eine tabellarische Datenstruktur mit einer geordneten Kollektion von Spalten, die jeweils verschiedene Datentypen haben können. DataFrames können auf verschiedene Arten erzeugt werden, zum Beispiel aus mehreren Series oder aus einem Dictionary, dessen Werte gleich lange Listen sind, wie im folgenden Beispiel:

Beispiel: DataFrame aus Series oder Dictionary erzeugen

 adressbuch = { 
 import pandas as pd
  "Name": ["Max Muster", "Anna Test", "John Doe"], 
  "Adresse": ["Schoenstrasse 11", "Unter de Linden 2", "Amperstrasse 1"], 
  "Telefonnummer": ["0151 (345678)", "0171 (123456)", "0161 (987654)"] 
  } 
 df1 = pd.concat([name, adresse, tel], axis=1) #  DataFrame aus Series
 df2 = pd.DataFrame(adressbuch) # DataFrame aus Dictionary 
 df1 # Ausgabe des DataFrames df1  

Aufbereitung des OPSD-Datensatzes

Der OPSD-Datensatz, der in Form einer csv-Datei time_series_60min.csv vorliegt, wird nun mit Hilfe der Pandas-Datenstrukturen und Funktionen eingelesen, aufbereitet und tabellarisch ausgegeben.

1. Importieren der Programmbibliotheken

In der ersten Codezelle des Jupyter Notebooks importieren wir die benötigten Programmbibliotheken: Pandas, Matplotlib und Seaborn. In Python kann man mit Hilfe der import-Anweisung entweder eine komplette Programmbibliothek importieren, oder nur einzelne Funktionen der Programmbibliothek. Beim Import werden für die jeweiligen Bibliotheken oder Funktionen Alias-Namen vergeben: für pandas vergeben wir den Alias pd, etc.

 import pandas as pd # Wird für Datenverwaltung und Datenbereinigung benötigt 
 import matplotlib as plt # Wird für die Visualisierung, Plots etc. benötigt 
 import matplotlib.dates as mpd 
 import seaborn as sns # Erweiterung von matplotlib, schönere Graphen 

2. Daten einlesen

In der zweiten Codezelle werden die OPSD-Daten, die in der csv-Datei time_series_60min_xs.csv gespeichert sind, mit Hilfe der Funktion read_csv() der Pandas-Bibliothek in den Arbeitsspeicher des Python-Programms eingelesen. Die Funktion read_csv() speichert die Daten in ein DataFrame mit dem Namen opsd_full.

 # Lese CSV-Datei ein 
 opsd_full = pd.read_csv('time_series_60min.csv', index_col=0, parse_dates=True)  
 # Zeige erste drei Zeilen zur Kontrolle an 
 opsd_full.head(3) 

Die Ausgabe nach Ausführung dieses Codeblocks sieht ähnlich aus wie abgebildet. Die Index-Spalte des DataFrames ist hier die Spalte TimestampUTC und wird als Zeilenüberschrift hervorgehoben.


3. Datenspalten auswählen

Wir benötigen aus der heruntergeladenen csv-Datei nur die Spalten TimestampUTC, Verbrauch, Solar und Wind. In der dritten Codezelle wird die Pandas-Funktion iloc() verwendet, um aus dem Dataframe opsd_full die benötigten Spalten auszuwählen und in ein neues DataFrame mit dem Namen opsd zu kopieren.

 # Behalte aus dem Datensatz nur die benötigten Spalten 
 opsd = opsd_full.iloc[:,[2,4,5]].copy() 
 # Zeige erste drei Zeilen zur Kontrolle an 
 opsd.head(3)  

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


4. Datenframe nach Excel exportieren

In der vierten Codezelle wird der vereinfachte Datensatz wird als Sicherung in eine neue csv-Datei exportiert. Für den Export wird die Pandas-Funktion to_csv() verwendet. Die Option "Index=True" bedeutet, dass auch die Index-Spalte bzw. Zeilenüberschrift (in unserem Fall: TimestampUTC) mit exportiert wird.

 # Exportiere den vereinfachten Datensatz als Sicherung in eine neue csv-Datei 
 opsd.to_csv (r'time_series_60min_xs.csv', index = True, header=True) 

5. Datenspalten durch 1000 teilen

In der fünften Datenzelle teilen wir die Verbrauchs-Spalten durch 1000. Dies stellt sicher, dass die Anzeige der Verbrauchsdaten in GWh erfolgt anstelle von MWh. Pandas stellt eine Reihe arithmetischer Operationen (add, sub, mul, div) zur Verfügung, die man auf den Elementen eines DataFrames ausführen kann. Hier verwenden wir die Pandas-Funktion div(), um alle Elemente der ausgewählten Spalten durch 1000 zu teilen.

 # Teile die Verbrauchsspalten durch 1000, damit die Anzeige in GWh erfolgt 
 opsd.iloc[:,0:3] = opsd.iloc[:,0:3].div(1000) 
 # Zeige drei zufällige Zeilen zur Kontrolle an 
 opsd.sample(3, random_state=0) 

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


6. Extrahiere Jahr, Monat und Tag aus der Datumsspalte

Wir fügen dem Datensatz drei neue Spalten hinzu, indem wir aus der Index-Spalte des DataFrames opsd die entsprechenden Bestandteile extrahieren.

 # Extrahiere Jahr, Monat und Tag aus dem Datum 
 opsd['Jahr'] = opsd.index.year 
 opsd['Monat'] = opsd.index.month 
 opsd['Tag'] = opsd.index.weekday_name 
 # Zeige drei zufällige Datensätze an 
 opsd.sample(3, random_state=0) 

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


7. Datumsbereiche (Zeilen) auswählen

Wir wählen mit Hilfe der Pandas-Funktion-loc() zwei Datumsbereiche aus, die miteinander verglichen werden sollen. Die Funktion loc() dient ähnlich wie iloc() der Auswahl von Bereichen aus einem DataFrame. Während die iloc()-Funktion den Index einer Spalte als Filter verwendet, passiert die Auswahl bei loc() über Zeilen- und Spaltenüberschriften.

 # Wähle den Monat Juli im Jahr 2017 aus 
 opsd_juli_2017 = opsd.loc['2017-07-01 00':'2017-07-31 23'] 
 # Wähle den Monat Juli im Jahr 2018 aus 
 opsd_juli_2018 = opsd.loc['2018-07-01 00':'2018-07-31 23'] 
 opsd_juli_2018.sample(3, random_state=0) 

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


8. Auswertungen auf Tages-,Wochen- und monatlicher Basis

Wir haben bisher die stündlichen Verbrauchswerte betrachtet, so wie sie in der heruntergeladenen Datei zur Verfügung gestellt waren. Für die Betrachtung eines größeren Zeitraums (Monate und Jahre) benötigen wir die Verbrauchswerte pro Tag, Woche und Monat. Wir müssen als Nächstes also eine Änderung der Zeitskala, ein sogenanntes Resampling durchführen. Mit Resampling ist der Prozess gemeint, der eine Zeitreihe von einer Frequenz in eine andere überführt. Die Frequenzumwandlung wird in Pandas mit Hilfe der Methode resample() durchgeführt.

Beispiel: Berechne Tagessummen, Wochen-Mittelwerte, Monatssummen

 # Wähle Spalten aus  
 spalten = ['Verbrauch', 'Wind', 'Solar']  
 # Gruppiere jede der Spalten nach Tag  
 opsd_tag = opsd[spalten].resample('D').sum()  
   
 # Gruppiere jede der Spalten nach Woche  
 # Aggregiere die Werte über den Mittelwert  
 opsd_woche = opsd_tag[spalten].resample('W').mean()  
   
 # Gruppiere jede der Spalten nach Monat  
 # Monate mit weniger als 28 Tagen werden nicht gezählt  
 opsd_monat = opsd[spalten].resample('M').sum(min_count=28)  
   
 # Gebe zur Kontrolle drei zufällige Werte aus  
 opsd_tage.sample(3, random_state=0)  

Datenvisualisierung mit Matplotlib

Um Matplotlib verwendet zu können, muss die Bibliothek zunächst importiert werden:

 import matplotlib.pyplot as plt

Die Syntax von Matplotlib ist einfach und vergleichbar mit der Syntax der MATLAB-plot-Funktionalität. Um ein Diagramm zu erstellen, wird zunächst ein Figure-Objekt erstellt, dem mehrere Subplots hinzugefügt werden können. Die wichtigsten Befehle zum Plotten sind plot für eindimensionale und surf für mehrdimensionale Diagramme. Der plot-Befehl erhält als Parameter die x- und y-Koordinaten der darzustellenden Daten, und optional einen String mit Formatierungsangaben, wie im folgenden Beispiel:

Beispiel: Zeichne die Sinus- und Cosinus-Funktion auf dasselbe Diagramm.

 import numpy as np  
 x = np.linspace(0,10,40)  
 y1 = np.sin(x);y2 = np.cos(x);  
 fig=plt.figure(figsize=[4,2])  
 plt.plot(x, y1,'r*',x, y2,'b+')   

Die Ausgabe nach Ausführung dieses Codeblocks sieht ähnlich aus wie abgebildet. Das Diagramm kann weiter verschönert werden, indem man Beschriftungen für die Achsen, einen Titel, eine Legende etc. festlegt.


Bei der Verwendung von Matplotlib mit Pandas ist es nicht erforderlich, die x- und y-Koordinaten des darzustellenden Diagramms explizit anzugeben wie in unserem Minibeispiel. Der plot-Befehl ist als Methode der Pandas-Datenstrukturen integriert, so dass ein DataFrame df direkt mit df.plot() visualisiert werden kann.

Datenvisualisierung 1: Entwicklung des täglichen Stromverbrauchs

Wir visualisieren zunächst die Spalte "Verbrauch" des DataFrames "opsd_tag", d.h. den täglichen Stromverbrauch in Deutschland vom 01.01.2016 bis 31.12.2018.

 sns.set(rc={'figure.figsize':(12, 4)})   
 ax = opsd_tag['Verbrauch'].plot(lineWidth=1, color='b')  
 ax.set_title('Täglicher Stromverbrauch DE 2016 - 2018') 
 ax.set_xlabel('Datum');  
 ax.set_ylabel('Tägl. Verbrauch (GWh)');  
 ax.set_ylim(800,1800)  

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


Datenvisualisierung 2: Entwicklung des monatlichen Stromverbrauchs

Im nächsten Schritt wollen wir sehen, wie sich der monatliche Verbrauch von Strom, Solar- und Windenergie von 2016 bis 2018 entwickelt hat. Als Datenquelle verwenden wir nun die aggregierten monatlichen Daten, d.h. den zuvor erstellten DataFrame "opsd_monat".

 # Visualisiere den monatlichen Verbrauch  
 ax = opsd_monat["Verbrauch"].plot(lineWidth=2, color='b')  
 ax = opsd_monat["Solar"].plot(lineWidth=1.5, color='r', marker='*',)  
 ax = opsd_monat["Wind"].plot(lineWidth=1.5, color='g', marker='o')  
 ax.legend();  
 ax.set_title('Monatlicher Stromverbrauch DE 2016 - 2018') 
 ax.set_xlabel('Datum');  
 ax.set_ylabel('GWh');  

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


Vergleiche den Stromverbrauch 2017 vs. 2018

Wir verwenden wieder die plot()-Funktion der Matplotlib, um den Stromverbrauch der Jahre 2017 und 2018 gegenüberzustellen. Die beiden graphischen Darstellungen werden als Subplots derselben Figur nebeneinander gestellt. Wir versehen die Diagramme auch mit Titeln und Achsen-Beschriftungen.

 opsd_2017 = opsd_tag.loc['2017-01-01':'2017-12-31']  
 opsd_2018 = opsd_tag.loc['2018-01-01':'2018-12-31']  
 # Setze die Größe der Anzeige  
 sns.set(rc={'figure.figsize':(14, 4)})  
 # Subplot mit einer Zeile und 2 Spalten  
 plt.subplot(1, 2, 1)   
 ax1 = opsd_2017["Verbrauch"].plot(lineWidth=1.5, color='b')  
 ax1.set_ylabel('Verbrauch (GWh)')  
 ax1.set_title('Stromverbrauch DE 2017')  
 plt.subplot(1, 2, 2)  
 ax2 = opsd_2018["Verbrauch"].plot(lineWidth=1.5, color='r')  
 ax2.set_ylabel('Verbrauch (GWh)')  
 ax2.set_title('Stromverbrauch DE  2018')  

Die Ausgabe nach Ausführung dieses Codeblocks sieht folgendermaßen aus:


YouTube-Video

Die Verwendung des erstellten Jupyter Notebook wird durch ein 5-Minuten-Video (Screencast mit zusätzlichen Erläuterungen) veranschaulicht.

Mit Beiträgen von:
 M. Sc. Anke Welz, Franc Willy Pouhela
 Prof. Dr. Eva Maria Kiss
Tools, Software und weiterführende Links:
Python, Anaconda, Jupyter Notebook, Pandas, Seaborn, Tutorial: Time Series Analysis with Pandas