NumPy und SciPy

Notizen

  • Die grundlegende Datenstruktur, die in NumPy definiert wird, ist ein ein- oder mehrdimensionales Objekt, das ndarray. Diese Arrays bieten dann eine einfache Möglichkeit, mathematische Operationen auf jedes Element anzuwenden. Gleich dimensionierte Arrays können auch addiert, subtrahiert, multipliziert und dividiert werden.

  • NumPy definiert dann auch eigene Funktionen, z.B. sin(x), die als Argument (neben einzelnen Zahlen) auch ganze ndarrays annehmen.

  • SciPy baut auf NumPy auf. Die umfangreichen Methoden, die SciPy zur Verfügung stellt, operieren in der Regel auf Datenobjekten vom Typ NumPy-Array. So ist es ohne große Umstände möglich, Funktionen numerisch nach Nullstellen oder Extremwerten zu untersuchen, zu integrieren, nichtlineare Fits an Messdaten durchzuführen u.v.a.m..

  • Sehr hilfreich ist in diesem Zusammenhang dieses Tutorial, das auf einem Workshop zum Thema basiert. Aus diesem stammen auch die vorgestellten Beispiele zur Nullstellen- und Extremwertbestimmung sowie zum Kurvenfitten.

  • Ein sehr gutes und online auch kostenlos verfügbares Buch mit vielen direkt als Skript nachvollziehbaren Beispielen ist das Python Data Science Handbook.

  • Die folgenden Programme demonstrieren einige Möglichkeiten:

    • Programm 1 enthält die Demonstration aus der Vorlesungen zu einigen Möglichkeiten der linearen Algebra mit NumPy. (b_matrix_od.txt, coeff_matrix_od.txt)

    • Programm 2 zeigt die Bestimmung von Minima und Nullstellen einer eindimensionalen Funktion.

    • Programm 3 zeigt das Fitten einer Messwertreihe an eine parametrisierte Funktion.

Aufgaben bis zum nächsten Mal

  • Installieren Sie, wenn möglich, die Anaconda-Python-Distribution auf ihrem Rechner. Darin sind alle wichtigen Pakete für die wiss. Anwendungen enthalten, und die Nutzung ist komfortabler als auf replit. Im Startmenü sollte dann auch ein Link für die Entwicklungsumgebung „Spyder“ auftauchen, der ein Arbeiten ähnlich wie auf replit erlaubt (Editor links, Ausgaben auf der Konsole rechts).

  • Bearbeiten Sie die folgende Bonusaufgabe 3 und speichern Sie das Ergebnis in Ihrem pythonanywhere-Account! Sie können den nachfolgenden Text der Aufgabenstellung auch direkt in den Editor bei pythonanywhere kopieren. (Frist bis Ende der Vorlesungszeit, 16.02.2025)

    bonus_b3_funktionsfit.py
    # Nachfolgend finden Sie ein Skript, das die Bestimmung von Nullstellen, Minima und einen Funktionsfit mittels simulierter Messwerte zeigt (Kombination der Beispiele aus der Vorlesung)
    # 1. Machen Sie sich die Bedeutung der einzelnen Zeilen klar.
    # 2. Erweitern Sie die Funktion f_ideal(x) um ein lineares Glied "-5*x" (also zu x**2+10*np.sin(x)-5*x) und bestimmen Sie die Nullstellen und Minima der resultierenden Funktion! Experimentieren Sie mit verschiedenen Startwerten für die Nullstellen- und Minima-Suche!
    # 3. Erweitern Sie nun auch die Funktion ``f_experimentell(x)`` um ein lineares Glied "-c*x"! Passen Sie den Fit so an, dass auch dieser dritte Parameter c mit bestimmt wird!
    # 4. Modifizieren Sie das Fit-Programm so, dass die simulierten Messdaten jetzt 2000 Wertepaare enthalten und das Rauschen 5fach bzw. 10fach größer ist.
    #    Wie beeinflusst die Anzahl der "Messpunkte" bzw. die Stärke des Rauschens die Übereinstimmung der gefitteten Parameter mit den idealen Werten (1, 10, -5)?
    
    
    import numpy as np # eine haeufig verwendete Art, NumPy einzubinden. Das Synonym np erspart Tipparbeit
    from scipy import optimize # aus dem SciPy-Paket wird nur das optimize-Modul eingebunden
    import matplotlib.pyplot as plt # einbinden der Plot-Funktionalitaet von Matplotlib zur graphischen Funktionsdarstellung
    
    def f_ideal(x): # unsere Beispielfunktion
        # beachte: weil die Funktion ndarrays verarbeiten soll, muss auch die Sinusfunktion von NumPy verwendet werden
        return x**2 + 10*np.sin(x)
    
    # x = np.arange(-10, 10, 0.1) # Datenbereich fuer einen ersten, einfachen Plot
    # plt.plot(x, f_ideal(x)) # Matplotlib in seiner simpelsten Form: x-Daten, y-Daten, fertig
    # plt.show() # und den Plot anzeigen...
    # An dieser Stelle wird das Skript pausiert! Es geht erst weiter, wenn das Fenster mit dem Plot geschlossen wird.
    
    
    
    
    
    # Bestimmung von Minima
    
    minimum1 = optimize.fmin_bfgs(f_ideal, 0) # fmin_bfgs stellt einen Mininierer zur Verfuegung, der ausgehend von einem vordefinierten Startwert den naechsten lokalen Minimumwert der uebergebenen Funktion findet
    minimum2 = optimize.fmin_bfgs(f_ideal, 3) # ein weiteres Minimum
    
    print("Minima f_ideal(x): ", minimum1, minimum2)
    
    # Wie würden Sie lokale Maxima suchen?
    
    
    # Bestimmung von Nullstellen
    
    nullstelle1 = optimize.fsolve(f_ideal, 1) # eine Nullstelle, gesucht wird ab Startwert 1
    nullstelle2 = optimize.fsolve(f_ideal, -3) # zweite Nullstelle
    
    print("Nullstellen f_ideal(x): ", nullstelle1, nullstelle2)
    
    # Eine Dokumentation zu allen diesen Funktionen erhalten sie auf der Kommandozeile mit help(), z.B. help(optimize.fsolve) oder in der Online-Dokumentation auf scipy.org
    
    
    
    
    
    # Funktionsfit
    
    xdata = np.linspace(-10, 10, num = 20) # ein ndarray mit 20 äquidistanten Werten von -10 bis 10, die x-Werte der simulierten Messdaten
    ydata = f_ideal(xdata) + 10*np.random.randn(xdata.size) # und die zugehoerigen y-Werte der simulierten Messdaten mit Rauschen drauf, xdata.size ist die Anzahl der Elemente im ndarray xdata
    
    def f_experiment(x, a, b): # die parametrisierte Funktion, die an die die verrauschten (Mess-)Daten gefittet werden sollen
        return a*x**2 + b*np.sin(x)
    
    guess = [2, 2] # eine Liste der initialen Startwerte fuer die Parameter, die der Fit-Prozedur uebergeben werden, in derselben Reihenfolge, wie sie in der Funktion f2 auf das x folgen, hier also erst a, dann b
    
    params, params_covariance = optimize.curve_fit(f_experiment, xdata, ydata, guess) # der eigentlich Fit-Aufruf
    
    print("Beste Fit-Parameter (a,b): ", params)
    # print("Kovarianzen: ", params_covariance)
    
    
    
    
    
    # Und ein Plot mit der theoretischen Kurve, den "Messwerten" und der gefitteten Funktion
    
    x = np.arange(-10, 10, 0.1) # ein ndarray mit dichter gesetzten x-Werten, damit der Plot der Funktionen f_ideal(x) und f_experiment(x) schön glatt ist
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(xdata, ydata, 'g.', label = "Messdaten")
    ax.plot(x, f_ideal(x), 'b-', label="f_ideal(x)")
    ax.plot(x, f_experiment(x, *params), 'r--', label="bester Fit f_experiment(x)")
    ax.legend()
    ax.set_xlabel('x')
    ax.set_ylabel('f(x)')
    
    plt.show()
    # An dieser Stelle wird das Skript pausiert! Es geht erst weiter, wenn das Fenster mit dem Plot geschlossen wird.