Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung Nächste Überarbeitung | Vorherige Überarbeitung | ||
talit:python_advanced [2023-08-11 14:34] – [Mit Jupyter Notebook arbeiten] sca | talit:python_advanced [2025-08-29 16:33] (aktuell) – [Numba] sca | ||
---|---|---|---|
Zeile 61: | Zeile 61: | ||
In Jupyter-Notebooks kann man sogenannte **Magic-Befehle** verwenden, welche immer mit `%` beginnen. Diese und viele anderen wichtigen Befehle findet man im folgenden **Cheat Sheet:** | In Jupyter-Notebooks kann man sogenannte **Magic-Befehle** verwenden, welche immer mit `%` beginnen. Diese und viele anderen wichtigen Befehle findet man im folgenden **Cheat Sheet:** | ||
+ | {{ : | ||
+ | |||
+ | Klicke auf folgenden Link, um das Cheat Sheet als PDF herunterzuladen: | ||
{{ : | {{ : | ||
Zeile 375: | Zeile 378: | ||
Diese Funktionen bieten eine kompakte und elegante Möglichkeit, | Diese Funktionen bieten eine kompakte und elegante Möglichkeit, | ||
+ | ===== Numba ===== | ||
+ | |||
+ | Numba ist ein Just-in-Time (JIT) Compiler für Python, der Funktionen mit Hilfe von LLVM in Maschinencode übersetzt. Besonders nützlich ist Numba für **numerische Berechnungen mit NumPy**, da es diese **massiv beschleunigen** kann – auch durch **Parallelisierung**. | ||
+ | |||
+ | Installation | ||
+ | <code bash> | ||
+ | pip install numba | ||
+ | </ | ||
+ | |||
+ | Tipps: | ||
+ | |||
+ | * **Vermeide Python-Objekte** (z. B. Listen, Dictionaries). | ||
+ | * Nutze **NumPy-Arrays** und primitive Datentypen (z.B. int). | ||
+ | * Verwende `numba.set_num_threads(n)` zur Kontrolle der Thread-Anzahl. | ||
+ | |||
+ | |||
+ | ==== Beispiel: Prinzahlen ==== | ||
+ | |||
+ | Wir schauen einen Code an, der ermittelt, wie viele Primzahlen es bis und mit einer vorgegebenen Zahl `n_max` gibt. Die Funktion `is_prime()` wurde dabei möglichst ineffizient programmiert. | ||
+ | |||
+ | Version 1 ist der ursprüngliche Code, ganz ohne numba. In Version 2 wurde der Code mit ganz wenigen einfachen Anpassungen ungeschrieben und mit numba parallelisiert. Dabei konnte die Laufzeit von 26.5s auf 0.4s reduziert werden!!! | ||
+ | |||
+ | **Version 1:** Ursprünglicher Code ohne numba. Zeit: 26.5s | ||
+ | <code python> | ||
+ | n_max = 1e5 | ||
+ | |||
+ | def is_prime(x): | ||
+ | for i in range(2,x): | ||
+ | if x % i == 0: | ||
+ | return False | ||
+ | return True | ||
+ | |||
+ | nr_primes = 0 | ||
+ | for i in range(2, | ||
+ | if is_prime(i): | ||
+ | nr_primes += 1 | ||
+ | print(nr_primes) | ||
+ | </ | ||
+ | |||
+ | **Version 2:** Erste Optimierung mit numba. Zeit: 0.4s | ||
+ | <code python> | ||
+ | from numba import njit, prange | ||
+ | import numpy as np | ||
+ | |||
+ | @njit | ||
+ | def is_prime(x): | ||
+ | for i in range(2,x): | ||
+ | if x % i == 0: | ||
+ | return False | ||
+ | return True | ||
+ | |||
+ | @njit(parallel=True, | ||
+ | def run(): | ||
+ | n_max = 3e4 | ||
+ | nr_primes = 0 | ||
+ | for i in prange(2, | ||
+ | if is_prime(i): | ||
+ | nr_primes += 1 | ||
+ | return nr_primes | ||
+ | |||
+ | nr_primes = run() | ||
+ | print(nr_primes) | ||
+ | </ | ||
+ | |||
+ | Bemerkungen: | ||
+ | |||
+ | * @njit(parallel=True) aktiviert die **Parallelisierung**. | ||
+ | * `range` ersetzt durch `prange` (parallel-range): | ||
+ | |||
+ | ==== Beispiel: Numpy-Arrays ==== | ||
+ | |||
+ | Hier ein einfaches Beispiel, welches Numpy-Arrays involviert: | ||
+ | |||
+ | **Version 1**: ohne numba (8.0s) | ||
+ | <code python> | ||
+ | |||
+ | import numpy as np | ||
+ | |||
+ | def berechne_sinus(x_vals): | ||
+ | result = np.empty_like(x_vals) | ||
+ | for i in range(len(x_vals)): | ||
+ | result[i] = np.sin(x_vals[i]) | ||
+ | return result | ||
+ | |||
+ | x = np.linspace(0, | ||
+ | y = berechne_sinus(x) | ||
+ | </ | ||
+ | |||
+ | **Version 2**: mit numba (0.2s) | ||
+ | <code python> | ||
+ | import numpy as np | ||
+ | from numba import njit, prange | ||
+ | |||
+ | @njit(parallel=True, | ||
+ | def berechne_sinus(x_vals): | ||
+ | result = np.empty_like(x_vals) | ||
+ | for i in prange(len(x_vals)): | ||
+ | result[i] = np.sin(x_vals[i]) | ||
+ | return result | ||
+ | |||
+ | x = np.linspace(0, | ||
+ | y = berechne_sinus(x) | ||
+ | </ | ||