For-Schleifen#
Wir betrachten zunächst ein kleines Beispiel: das Kartenausteilen bei einem Spieleabend. Stellen Sie sich vor, Sie möchten mit Ihren Freund:innen UNO spielen. Zu Beginn erhält jede Spielerin und jeder Spieler sieben Karten. Beim Austeilen gehen Sie systematisch vor, indem reihum alle eine Karte bekommen – und das wiederholen Sie genau sieben Mal, bis alle die richtige Anzahl Karten haben.
Solche sich wiederholenden Abläufe lassen sich in Python mit einer for-Schleifen umsetzen. For-Schleifen eignen sich besonders gut für Situationen, in denen bereits im Voraus feststeht, wie oft eine Wiederholung stattfinden soll. Im Gegensatz zu while-Schleifen ist die Anzahl der Iterationen von Beginn an bekannt. In der Numerik kommen for-Schleifen häufig zum Einsatz, wenn ein numerisches Vefahren eine feste Anzahl an Iterationen durchlaufen soll.
Bemerkung
Wenn ein Codeblock mehrfach oder für eine feste Menge an Werten ausgeführt werden soll, verwenden Sie eine for-Schleife.
Die Syntax#
Der Code im Schleifenrumpf einer for-Schleife wird so lange ausgeführt, bis alle Elemente des Iterationsbereichs, in diesem Fall \(\texttt{range(N)}\), vollständig durchlaufen worden sind. In jedem Schleifendurchlauf nimmt die Schleifenvariable (auch Iterationsvariable genannt) \(\texttt{var}\) nacheinander die Werte aus dem Iterationsbereich an. Mit jedem dieser Werte wird der Schleifenrumpf erneut durchlaufen. Die Schleife endet automatisch, wenn das Ende des Iterationsbereichs erreicht worden ist. Anschließend wird der Code \(\texttt{another}\) \(\texttt{statement 1, 2}\) ausgeführt. Wie auch bei der while-Schleife kennzeichnet der Doppelpunkt den Beginn des Schleifenrumpfs. Der eigentliche Schleifenrumpf wird, wie in Python üblich, eingerückt.
Der Iterationsbereich ist nicht auf \(\texttt{range()}\) beschränkt. Auch Listen, Tupel oder andere Datenstrukturen können durchlaufen werden. Besonders in der Numerik werden wir häufig über Zahlenbereiche iterieren.
Python |
Mathematik |
Beispiel |
|---|---|---|
\(\texttt{range(b)}\) |
\(\{0, 1, \cdots, b-1\}\) |
\(\texttt{range(5)} = \{0,1,2,3,4\}\) |
\(\texttt{range(a, b)}\) |
\(\{a, a+1, \dots, b - 1\}\) |
\(\texttt{range(5, 9)} = \{5, 6, 7, 8 \}\) |
\(\texttt{range(a, b, s)}\) |
\(\{a + i \cdot s < b \, \mid \, i \in \mathbb{N}\}\) |
\( \texttt{range(5, 11, 2)} = \{5, 7, 9\}\) |
Angenommen, Sie möchten die Summe der ersten \(N\) natürlichen Zahlen berechnen. Dazu können Sie eine for-Schleife verwenden, in der Sie zunächst \(\texttt{summe} = 0\) setzen und anschließend in jedem Schleifendurchlauf den aktuellen Wert von \(i\) zur Variablen \(\texttt{summe}\) addieren, und zwar für alle \(i = 1, \ldots, N\). Nach Abschluss der Schleife enthält \(\texttt{summe}\) das gewünschte Ergebnis.
Die Variable \(\texttt{summe}\) wird mit \(\texttt{summe}=0\) und die Variable \(N\) mit \(N=5\) initialisiert.
Der Iterationsbereich \(\texttt{range(1, N+1)}\) entspricht \(\{1, 2, \ldots, N\}\). Zu Beginn der for-Schleife wird \(i\) auf das erste Element von \(\texttt{range(1, N+1)}\) gesetzt.
Aufgabe 1.1
Schreiben Sie eine for-Schleife, welche die ersten vier Elemente von \(\texttt{x}\) ausgibt. Nennen Sie die Schleifenvariable \(\texttt{idx}\).
x = np.arange(5, 21)
print(x[idx])
Hinweis
Schreiben Sie die for-Schleifen mithilfe der Schlüsselwörter \(\texttt{for}\) und \(\texttt{range}\). Das Schlüsselwort \(\texttt{for}\) sollte über dem \(\texttt{print}\)-Befehl stehen. Bedenken Sie, dass Arrays in Python bei dem Index \(0\) beginnen.
Lösung
x = np.arange(5, 21)
for idx in range(4):
print(x[idx])
Aufgabe 1.2
Passen Sie die for-Schleife so an, dass die Schleifenvariable \(\texttt{idx}\) bei \(6\) beginnt, bei \(14\) endet und um \(2\) erhöht wird.
x = np.arange(5, 21)
print(x[idx])
Lösung
x = np.arange(5, 21)
for idx in range(6, 15, 2):
print(x[idx])
Beispiel - Fibonacci-Zahlen#
Im Folgenden wollen wir mithilfe von Python die ersten \(n\) Fibonacci-Zahlen bestimmen. Die Fibonacci-Zahlen \(\texttt{f}_k\) sind rekursiv definiert durch:
Aufgabe 2.1
Passen Sie den nachfolgenden Code so an, dass die ersten \(n\) Fibonacci-Zahlen berechnet und in \(\texttt{fib}\) gespeichert werden. Ergänzen Sie dazu eine for-Schleife mit Schleifenvariable \(k\).
import matplotlib.pyplot as plt
n = 102
fib = np.ones(n)
fib[k] = fib[k-1] + fib[k-2]
plt.figure()
plt.plot(fib)
plt.xlabel("k")
plt.ylabel("Fibonacci Zahlen")
plt.show()
Hinweis
Benutzen Sie eine for-Schleife der Form:
for k in range(2, n):
# Code
Lösung
n = 102
fib = np.ones(n)
for k in range(2, n):
fib[k] = fib[k-1] + fib[k-2]
plt.figure()
plt.plot(fib)
plt.xlabel("k")
plt.ylabel("Fibonacci Zahlen")
plt.show()
Aufgabe 2.2
Führen Sie den Code für unterschiedliche \(n\) aus. Welchen Effekt hat das Verändern der Schleifenvaraible auf das Ergebnis?
Beispiel - Erneuerbare Energien#
Als nächstes sollen Sie die Entwicklung erneuerbarer Energien für verschiedene Länder analysieren. Die entsprechenden Daten stammen von der öffentlichen Plattform Our World in Data und enthalten umfassende Informationen über den Energieverbrauch verschiedener Länder, unter anderem auch über den prozentualen Anteil erneuerbarer Energien am Gesamtenergieverbrauch.
Der nachfolgende, versteckte Code extrahiert die für uns wichtigen Daten. Sie müssen nicht nachvollziehen wie die Rohdaten im Hintergrund verarbeitet und vorbereitet werden. Für Sie ist nur wichtig, wie die aufbereiteten Daten aussehen:
\(\texttt{years}\) - NumPy Array, welches die Jahre 2005 bis 2023 enthält
\(\texttt{countries}\) - NumPy Array, welche die verschiedenen Länder enthält
\(\texttt{data}\) - NumPy Array, welches die Daten zum Anteil erneuerbarer Energien der Länder enthält. Eine Zeile entspricht einem Jahr, eine Spalte einem Land.
Show code cell content
import pandas as pd
import numpy as np
# Datenquelle
url = "https://raw.githubusercontent.com/owid/energy-data/master/owid-energy-data.csv"
df = pd.read_csv(url)
# Auswahlparameter
countries = [
"Germany",
"United States",
"China",
"Norway",
"Brazil",
"Italy",
"France",
"Netherlands",
"Sweden",
"Switzerland",
"Belgium",
]
variable = "renewables_share_energy"
# Daten filtern und auf relevante Spalten reduzieren
df_filtered = df[(df["country"].isin(countries)) & (df["year"] >= 2005)]
df_pivot = df_filtered.pivot(index="year", columns="country", values=variable)
# Nur vollständige Zeilen und relevante Länder
df_selected = df_pivot[countries].dropna()
# Jahr als eigene Spalte
df_selected_with_years = df_selected.copy()
df_selected_with_years.insert(0, "year", df_selected.index)
# Umwandeln in NumPy-Array
years = df_selected_with_years.to_numpy()[:, 0]
data = df_selected_with_years.to_numpy()[:, 1:]
countries = np.array(countries)
Größe von eindimensionalen Arrays bestimmen
Bevor Sie mit der Aufgabe starten, werfen wir noch einen kurzen Blick darauf, wie sich die Größe eines eindimensionalen Arrays bestimmen lässt. Dies ist besonders nützlich, wenn man mit einer \(\texttt{for}\)-Schleife über dessen Elemente iterieren möchte. Zum einen liefert \(\texttt{np.size(x)}\) die Anzahl aller Elemente des Arrays \(\texttt{x}\) (wie Sie aus dem Kapitel Funktionsaufrufe kennen). Alternativ eignet sich für eindimensionale Arrays auch \(\texttt{len(x)}\), um direkt die Länge zu ermitteln.
Aufgabe 3.1
Erstellen Sie die Variable \(\texttt{num_years}\), welche die Größe von \(\texttt{years}\) enthält.
# Ihr Code
Lösung
# Option 1
num_years = np.size(years)
# Option 2
num_years = len(years)
Aufgabe 3.2
Erstellen Sie die Variable \(\texttt{num_countries}\), welche die Anzahl der Länder enthält.
# Ihr Code
Lösung
# Option 1
num_countries = np.size(countries)
# Option 2
num_countries = len(countries)
Zurück zur eigentlichen Aufgabe
Ein gängiger Ansatz um eine for-Schleife zu schreiben, besteht darin den Schleifenrumpf zunächst für einen festen Wert der Schleifenvaiable zu programmieren. Sobald Code wie gewünscht läuft, wird der feste Wert durch die for-Schleife ersetzt.
Der nachfolgende Code plottet den Anteil der erneuerbaren Energien am Gesamtenergieverbrauch des ersten Landes in \(\texttt{countries}\). Er funktioniert bereits, sodass Ihre Aufgabe darin besteht die Zuweisung \(\texttt{k = 1}\) durch eine for-Schleife zu ersetzen, die durch alle Elemente in \(\texttt{countries}\) iteriert.
Aufgabe 3.3
Passen Sie den Code so an, dass die Daten an erneuerbaren Energien für alle Länder in \(\texttt{countries}\) in einem Diagramm geplottet werden.
import numpy as np
import matplotlib.pyplot as plt
plt.figure()
k = 1
# plotten der Regression und der Daten für Land k
plt.plot(years, data[:, k], label=countries[k])
# Achsenbeschriftung und Legende (muss nur einmal ausgeführt werden)
plt.legend(loc=(1.04, 0))
plt.xlabel("Jahre")
plt.ylabel("Anteil erneuerbarer Energien (%)")
plt.show()
Hinweis
Der Befehl \(\texttt{plt.plot}\) kann auch innerhalb einer Schleife ausgeführt werden.
Lösung
plt.figure()
for k in range(len(countries)):
plt.plot(years, data[:, k], label=countries[k])
plt.legend(loc=(1.04, 0))
plt.xlabel("Jahre")
plt.ylabel("Anteil erneuerbarer Energien (%)")
plt.show()