Daten plotten und fitten#
Zunächst werden die für dieses Jupyter Notebook benötigten Libraries geladen:
#Benötigte Libraries:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import plotly.offline as py
py.init_notebook_mode(connected=True)
import plotly.graph_objs as go
import plotly.tools as tls
import seaborn as sns
import time
import warnings
warnings.filterwarnings('ignore')
# MatplotLib Settings:
plt.style.use('default') # Matplotlib Style wählen
plt.rcParams['font.size'] = 10; # Schriftgröße
.csv-Datei als DataFrame einlesen#
Im Folgenden Nutzen wir globale Klimadaten, die auf der Webseite der NASA zu finden sind: https://data.giss.nasa.gov/gistemp/. Hierbei handelt es sich um Temperaturdaten, die Anomalien gegenüber dem Mittelwert in den Jahren 1951-1980 aufweisen.
Es werden Daten von Dateien (online oder offline) eingelesen mit der Python Bilbiothek pandas
. Die Daten werden in sogenannten DataFrames hier mit dem Namen global_mean
abgespeichert.
#link = "https://data.giss.nasa.gov/gistemp/graphs_v4/graph_data/Global_Mean_Estimates_based_on_Land_and_Ocean_Data/graph.csv"
link = 'data/graph.csv'
global_mean = pd.read_csv(link, header = 1) #DataFrame erstellen
Wir geben das DataFrame aus um uns die Messdaten einmal anzusehen:
global_mean.head(10) # Ausgabe der ersten 5 Spalten
#global_mean.tail(5) # Ausgabe der letzten 5 Spalten
#global_mean # Ausgabe des DataFrames
Year | No_Smoothing | Lowess(5) | |
---|---|---|---|
0 | 1880 | -0.17 | -0.09 |
1 | 1881 | -0.08 | -0.13 |
2 | 1882 | -0.11 | -0.17 |
3 | 1883 | -0.18 | -0.20 |
4 | 1884 | -0.28 | -0.24 |
5 | 1885 | -0.33 | -0.26 |
6 | 1886 | -0.32 | -0.27 |
7 | 1887 | -0.36 | -0.27 |
8 | 1888 | -0.17 | -0.27 |
9 | 1889 | -0.11 | -0.26 |
In der ersten Spalte befinden sich lediglich die Indizes der Messungen. Die zweite Spalte beinhaltet das Jahr und die dritte Spalte zeigt den gemessenen globalen Temperaturunterschied im Vergleich zur gemittelten Temeratur der Jahre 1951-1980. Die letzte Spalte zeigt die gleichen Messwerte, jedoch gefiltert.
Einzelne Spalten kann man sich anzeigen lassen, indem den Spaltel-Namen des zugehörigen DataFrames nutzt:
global_mean['Year']
0 1880
1 1881
2 1882
3 1883
4 1884
...
137 2017
138 2018
139 2019
140 2020
141 2021
Name: Year, Length: 142, dtype: int64
Daten plotten und Diagramm sichern mit ‘matplotlib’#
Als Beispiel für eine gelungene grafische Darstellung wollen wir die beiden Spalten, No_Smoothing and Lowess(5) gegenüber der Zeitachse Year plotten. Hierfür benützen wir die Python Library matplotlib
. Einmal geplottet kann das zuletzt angezeigte Diagramm in verschiedenen Formaten mit plt.savefig('klima_plot1.png')
abgespeichert werden. Wenn nicht anders angegeben, wird die Datei im gleichen Ordner angelegt.
import matplotlib.pyplot as plt
#plt.style.use('default')
plt.figure(figsize=(10,5))
plt.rcParams['font.size'] = 10; # Schriftgröße
plt.plot(global_mean["Year"],global_mean["No_Smoothing"], ls="--", lw=1, marker="s", ms=3, color="tab:gray", alpha=0.5, label="Werte");
plt.plot(global_mean["Year"],global_mean["Lowess(5)"], lw=4, color="tab:blue", label="Glättung (NASA)");
plt.xlabel('Jahr')
plt.ylabel("Jahresmitteltemperaturabweichung [°C]")
plt.legend();
plt.grid();
plt.savefig('klima_plot1.png')
plt.savefig('klima_plot1.pdf')
Daten verarbeiten#
Die Bibliothek pandas
ist sehr umfangreich und wird viel zur Datenverarbeitung genutzt. Im folgenden dazu einige Beispiele:
Statistische Größen: Mittelwert, Standardabweichung, Min, Max#
Für jede Spalte lassen sich statistische Größen wie z.B. die Anzahl der Einträge pro Spalte, deren Mittelwert, Standardabweichung, Minimal- und Maximalwert bestimmen:
global_mean.describe() #Dataframe Statistik
Year | No_Smoothing | Lowess(5) | |
---|---|---|---|
count | 142.000000 | 142.000000 | 142.000000 |
mean | 1950.500000 | 0.053169 | 0.053169 |
std | 41.135953 | 0.364161 | 0.352324 |
min | 1880.000000 | -0.490000 | -0.420000 |
25% | 1915.250000 | -0.200000 | -0.227500 |
50% | 1950.500000 | -0.065000 | -0.040000 |
75% | 1985.750000 | 0.252500 | 0.235000 |
max | 2021.000000 | 1.010000 | 0.930000 |
Maximum und zugehöriges Jahr ausgeben#
Dies können wir benutzen, um beispielsweise die maximale Temperaturdifferenz zu ermitteln:
global_mean["No_Smoothing"].std()
0.36416107752007404
Wenn wir wissen wollen, wann diese maximale Temperaturdifferenz auftrat, muss der zugehörige Index dieses Events gespeichert werden:
index_max = global_mean["No_Smoothing"].idxmax()
print(index_max)
136
Diesen Index können wir nun benutzen, um mittels .loc
Befehl den Eintrag zu diesem Index auszugeben:
global_mean.loc[index_max]
Year 2016.00
No_Smoothing 1.01
Lowess(5) 0.87
Name: 136, dtype: float64
Daten aufsteigend/absteigend sortieren#
Mit .sort_values("Spaltenname")
können wir auch die Tabelle nach dem definierten Spaltennamen sortieren (standardmäßig in ansteigender Reihenfolge):
global_mean.sort_values("No_Smoothing", ascending=False).head(10)
Year | No_Smoothing | Lowess(5) | |
---|---|---|---|
140 | 2020 | 1.01 | 0.93 |
136 | 2016 | 1.01 | 0.87 |
139 | 2019 | 0.98 | 0.93 |
137 | 2017 | 0.92 | 0.91 |
135 | 2015 | 0.90 | 0.83 |
138 | 2018 | 0.85 | 0.92 |
141 | 2021 | 0.84 | 0.93 |
134 | 2014 | 0.75 | 0.79 |
130 | 2010 | 0.72 | 0.65 |
133 | 2013 | 0.68 | 0.74 |
Mit ascending=False
wird absteigend sortiert:
global_mean.sort_values("No_Smoothing", ascending = False)
Year | No_Smoothing | Lowess(5) | |
---|---|---|---|
140 | 2020 | 1.01 | 0.93 |
136 | 2016 | 1.01 | 0.87 |
139 | 2019 | 0.98 | 0.93 |
137 | 2017 | 0.92 | 0.91 |
135 | 2015 | 0.90 | 0.83 |
... | ... | ... | ... |
30 | 1910 | -0.44 | -0.42 |
31 | 1911 | -0.45 | -0.40 |
24 | 1904 | -0.47 | -0.31 |
37 | 1917 | -0.47 | -0.30 |
29 | 1909 | -0.49 | -0.41 |
142 rows × 3 columns
WICHTIG: Der Dataframe global_mean
wird dadurch nicht verändert, es handelt sich nur um eine Anzeige!
Daten glätten#
Die von der NASA verwendete Glättung ist die LOcally WEighted Scatter-plot Smoother (LOWESS). Dabei wird in einem lokal zu definierenden Bereich eine lineare Regression durchgeführt. Eine genauere Erklärung zur Methode findet ihr auf Youtube.
Es gibt natürlich viele Methoden und Filter, um Daten zu glätten. Wir wollen nun versuchen, die Methode der NASA zu rekonstruieren. Hierfür benutzen wir die Python Library statsmodels
und erstellen eine weitere Spalte Lowess(own)
in unserem DataFrame global_mean
. In diese Spalte schreiben wir die geglätteten Werte von den Rohdaten global_mean["No_Smoothing"]
indem wir die Funktion lowess
aufrufen. Details zu Nutzung der Funktion findet ihr https://www.statsmodels.org:
an erster Stelle in der Funktion werden die Y-Werte eingegeben, hier
global_mean["No_Smoothing"]
an zweiter Stelle in der Funktion werden die X-Werte eingegeben, hier
global_mean["Year"]
die Option
frac
ist eine Zahl zwischen 0 und 1. Dies ist der Anteil der Daten, der bei der Schätzung der einzelnen y-Werte verwendet wird.Ausgegeben wird zweidimensionalas Array. Die erste Spalte enthält die sortierten x-Werte und die zweite Spalte die zugehörigen geschätzten y-Werte. Um die zweite Spalte in den DataFrame zu speichern, wählen wir diese mit
[:,1]
aus.
from statsmodels.nonparametric.smoothers_lowess import lowess
global_mean["Lowess(eigene)"] = lowess(global_mean["No_Smoothing"],global_mean["Year"], frac=1/14)[:,1]
global_mean
Year | No_Smoothing | Lowess(5) | Lowess(eigene) | |
---|---|---|---|---|
0 | 1880 | -0.17 | -0.09 | -0.092698 |
1 | 1881 | -0.08 | -0.13 | -0.129873 |
2 | 1882 | -0.11 | -0.17 | -0.167172 |
3 | 1883 | -0.18 | -0.20 | -0.203172 |
4 | 1884 | -0.28 | -0.24 | -0.239029 |
... | ... | ... | ... | ... |
137 | 2017 | 0.92 | 0.91 | 0.911976 |
138 | 2018 | 0.85 | 0.92 | 0.921410 |
139 | 2019 | 0.98 | 0.93 | 0.926072 |
140 | 2020 | 1.01 | 0.93 | 0.929365 |
141 | 2021 | 0.84 | 0.93 | 0.931468 |
142 rows × 4 columns
import matplotlib.pyplot as plt
plt.style.use('default')
plt.figure(figsize=(10,5))
plt.rcParams['font.size'] = 10;
plt.plot(global_mean["Year"],global_mean["No_Smoothing"], ls="-", lw=1, marker="s", ms=3, color="tab:gray", alpha=0.5, label="Werte");
plt.plot(global_mean["Year"],global_mean["Lowess(5)"], lw=4, color="tab:blue", label="Glättung (NASA)");
plt.plot(global_mean["Year"],global_mean["Lowess(eigene)"], lw=2,ls='-' , color="tab:red", label="Glättung (eigene)");
plt.xlabel('Jahr')
plt.ylabel("Jahresmitteltemperaturabweichung [°C]")
plt.legend();
plt.grid();
Messunsicherheiten als Fehlerbalken hinzufügen#
Bei diesem Datenset stehen uns leider keine Messunsicherheiten zur Verfügung. Um Sie jedoch als Fehlerbalken miteinzubeziehen, wollen wir im Folgenden annehmen, dass der Temperaturunterschied auf 0.25K genau messen werden konnte und fügen die unserem Datensatz hinzu:
global_mean["uncertainty"] = 0.25
print(global_mean)
Year No_Smoothing Lowess(5) Lowess(eigene) uncertainty
0 1880 -0.17 -0.09 -0.092698 0.25
1 1881 -0.08 -0.13 -0.129873 0.25
2 1882 -0.11 -0.17 -0.167172 0.25
3 1883 -0.18 -0.20 -0.203172 0.25
4 1884 -0.28 -0.24 -0.239029 0.25
.. ... ... ... ... ...
137 2017 0.92 0.91 0.911976 0.25
138 2018 0.85 0.92 0.921410 0.25
139 2019 0.98 0.93 0.926072 0.25
140 2020 1.01 0.93 0.929365 0.25
141 2021 0.84 0.93 0.931468 0.25
[142 rows x 5 columns]
Grafisch darstellen tun wir Messunsicherheiten mittels Fehlerbalken und der Matplotlib-Funktion plt.errorbar
.
plt.errorbar(global_mean["Year"],global_mean["No_Smoothing"], yerr=global_mean["uncertainty"], ls="-", lw=1, marker="s", ms=3, color="tab:gray", alpha=0.5, label="Werte");
plt.plot(global_mean["Year"],global_mean["Lowess(5)"], lw=4, color="tab:blue", label="Glättung (NASA)");
plt.xlabel('Jahr')
plt.ylabel("Jahresmitteltemperaturabweichung [°C]")
plt.legend();
plt.grid();
Ausgleichsgerade berechnen und plotten#
Mittels linearer Regression kann der Temperaturanstieg aus den Daten berechnet werden. Hierfür wird die Python Library numpy
benutzt und die Funktion polyfit
aufgerufen und in als model
gespeichert. Diese Funktion benutzt die Least-Square Methode für polynomische Modelle. Weitere Informationen zu der Funktion findet ihr hier. Mit der Option cov=True
wird die Kovarianz-Matrix berechnet, welche die Unsicherheiten für die Fit-Parameter beinhaltet.
import numpy as np
import pandas as pd
x=global_mean["Year"]
y=global_mean["No_Smoothing"]
y_err = global_mean["uncertainty"]
model = np.polyfit(x, y, deg=1, w=1/y_err, cov=True) # 1. Wert = Anstieg , 2. Wert = Schnittpunkt mit y-Achse
y_model = model[0][0]*x+model[0][1] # Modell einer linearen Regression
plt.ylabel("Jahresmitteltemperaturabweichung [°C]")
plt.xlabel("Jahr")
plt.errorbar(global_mean["Year"],global_mean["No_Smoothing"], yerr=global_mean["uncertainty"], ls="-", lw=1, marker="s", ms=3, color="tab:gray", alpha=0.5, label="Werte");
plt.plot(x,y_model, ls="-", lw=3, color="tab:red", label=f"lineare Regression y=({model[0][0]*1000:.3f}+-{np.sqrt(model[1][0][0]*1000):.3f})1e-3*x+({model[0][1]:.3f}+-{np.sqrt(model[1][1][1]):.3f})");
plt.legend(fontsize=12);
plt.grid();
model
(array([ 7.72740894e-03, -1.50191421e+01]),
array([[ 1.33257719e-07, -2.59919181e-04],
[-2.59919181e-04, 5.07196269e-01]]))
Das Model beinhaltet zwei Matrizen:
model
(array([ 7.72740894e-03, -1.50191421e+01]),
array([[ 1.33257719e-07, -2.59919181e-04],
[-2.59919181e-04, 5.07196269e-01]]))
Im ersten Array stehen die Fit-Parameter der linearen Ausgleichsgeraden entsprechend der obigen Deklaration: y_model = model[0][0]*x+model[0][1]
.
Im zweiten Array, hier eine 2x2 Matrix, sind die Unsicherheiten in Form von der Kovarianz-Matrix dargestellt.
Der Temperaturanstieg kann entsprechend ausgegeben werden:
print(f"Temperaturanstieg pro Jahr (von 1981 bis 2020): {model[0][0]:.3f}°C/Jahr")
print(f"Temperaturanstieg seit Beginn der Messung: {(y_model.iloc[-1]-y_model.iloc[0]):.3f}°C")
Temperaturanstieg pro Jahr (von 1981 bis 2020): 0.008°C/Jahr
Temperaturanstieg seit Beginn der Messung: 1.090°C
Warnung
Die lineare Regression bezieht hier den ganzen Zeitraum mit ein! Im folgenden betrachten wir für den Temperaturgradienten nur die Daten von 1980 bis 2020!
x=global_mean.loc[global_mean["Year"] >= 1980,"Year"]
y=global_mean.loc[global_mean["Year"] >= 1980,"No_Smoothing"]
y_err = global_mean.loc[global_mean["Year"] >= 1980,"uncertainty"]
model = np.polyfit(x, y, deg=1, w=1/y_err, cov=True) # 1. Wert = Anstieg , 2. Wert = Schnittpunkt mit y-Achse
y_model = model[0][0]*x+model[0][1] # Modell einer linearen Regression
print(f"Temperaturanstieg pro Jahr (von 1980 bis 2020): {model[0][0]:.3f}°C/Jahr")
Temperaturanstieg pro Jahr (von 1980 bis 2020): 0.019°C/Jahr
plt.ylabel("Jahresmitteltemperaturabweichung [°C]")
plt.xlabel("Jahr")
plt.errorbar(global_mean["Year"],global_mean["No_Smoothing"], yerr=global_mean["uncertainty"], ls="-", lw=1, marker="s", ms=3, color="tab:gray", alpha=0.5, label="Werte");
plt.plot(x,y_model, ls="-", lw=3, color="tab:red", label=f"lineare Regression y=({model[0][0]*1000:.3f}+-{np.sqrt(model[1][0][0]*1000):.3f})1e-3*x+({model[0][1]:.3f}+-{np.sqrt(model[1][1][1]):.3f})");
plt.legend(fontsize=12);
plt.grid();
Beliebige Funktion fitten#
Mit der Polyfit Funktion können in erster Linie Polynome gefittet werden.
Für beliebige Modellierung, wie z.B. Exponential-Funktionen, werden die Funktionen in aller Regel selber definiert. Hierfür eignet sich die scipy-Funktion curve_fit
.
import pandas as pd
from scipy.optimize import curve_fit
Als erstes wird die Funktion deklariert, hier nutzen wird wieder eine lineare Regression:
def lin_reg(x, a, b):
return a*x + b
def quadratic_fit(x, a, b, c):
return a*x**2 + b*x + c
Die wir anschließend an die Daten anpassen:
popt, pcov = curve_fit(quadratic_fit, x, y)
print('Fit:', popt)
print('Mit der Kovarianz-Matrix', pcov)
Fit: [ 2.41606861e-04 -9.47677075e-01 9.29408439e+02]
Mit der Kovarianz-Matrix [[ 1.14888003e-08 -4.59666876e-05 4.59764893e-02]
[-4.59666876e-05 1.83914056e-01 -1.83954621e+02]
[ 4.59764893e-02 -1.83954621e+02 1.83996544e+05]]
plt.ylabel("Jahresmitteltemperaturabweichung [°C]")
plt.xlabel("Jahr")
plt.errorbar(global_mean["Year"],global_mean["No_Smoothing"], yerr=global_mean["uncertainty"], ls="-", lw=1, marker="s", ms=3, color="tab:gray", alpha=0.5, label="Werte");
plt.plot(x,quadratic_fit(x,*popt), ls="-", lw=3, color="tab:red", label="Quadratischer Fit y=( %5.3f * x^2 + %5.3f * x + %5.3f)" % tuple(popt));
plt.legend(fontsize=12);
plt.grid();