Umgang mit NumPy¶
NumPy ist eine Python-Bibliothek zur Handhabung großer Datenmengen in Arrays und stellt die technologische Basis für arraybasierte NumPy-Traceschrittvorlagen dar. Das offizielle Handbuch von NumPy ist über folgenden Link erreichbar: https://docs.scipy.org/doc/numpy/index.html
Als einführende Literatur sei insbesondere das Quickstart-Tutorial empfohlen: https://docs.scipy.org/doc/numpy/user/quickstart.html
Ergänzend dazu werden nachfolgend einige Aspekte beleuchtet, die für die Traceanalyse besonders relevant sind.
Boolsche Operatoren¶
Ob ein Numpy-Array Elemente enthält oder einzelne Elemente des Arrays wahr sind, kann nicht
implizit über if arr: print('hallo') oder direkt über den Wahrheitswert bool(arr) geprüft
werden. Stattdessen müssen entsprechende Mechanismen von NumPy genutzt werden, die im nachfolgenden
Beispiel erläutert werden:
import numpy as np
arr = np.array([3, 1, -2, 0], dtype=np.float64)
# Ist arr gültig?
if isinstance(arr, np.ndarray):
print('arr ist ein gültiges NumPy-Array')
# Ist arr leer?
if len(arr) > 0:
print('arr ist nicht leer')
# Umgang mit Wahrheitswerten
positive = arr >= 0 # Neues Array, das Ergebnis der elementweisen Prüfung auf >= 0 enthält: [True, True, False, True]
print(np.all(positive)) # False, da nicht alle Elemente von positive True sind
print(np.any(positive)) # True, da positive mindestens einmal (im konkreten Fall dreimal) True enthält
Vorsicht
Der Wahrheitswert von np.nan („not a number“) ist True! Der Ausdruck np.all(np.array([0.1, 3.0, np.nan]))
ergibt dementsprechend True.
Maskierung¶
Für den Zugriff auf Einzelwerte oder Teil-Arrays kann auch für NumPy-Arrays der Index-/Slicing-Mechanismus von Python verwendet werden:
import numpy as np
arr = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(arr[3:5]) # [3, 4]
print(arr[:4]) # [0, 1, 2, 3]
print(arr[8:]) # [8, 9]
NumPy bietet allerdings noch deutlich leistungsfähigere Möglichkeiten zur Auswahl einer Teilmenge von Werten. Zum einen können durch Angabe einer boolschen Maske bestimmte Werte selektiert werden, zum anderen können gewünschte Elemente auch in einem Array von Indizes angegeben werden.
Boolsche Maskierung: Alle Werte >= threshold
import numpy as np
arr = np.array([0, 3, 7, 13, 10, 11, 12.5, 15])
threshold = 12
mask = arr >= threshold # Bool-Maske: [False, False, False, True, False, False, True, True]
print(arr[mask]) # [13, 12.5, 15]
Boolsche Maskierung: Alle Signalwerte innerhalb zeitlicher Grenzen
import numpy as np
values = np.array([100, 200, 300, 400, 500])
timestamps = np.arange(5.0) # [0.0, 1.0, 2.0, 3.0, 4.0]
# Alle Werte im geschlossenen Zeitintervall von 1.0 bis 2.5
mask = np.logical_and(1.0 <= timestamps, timestamps <= 2.5)
print(values[mask]) # [200, 300]
Index-Array: Signalwechsel von 20 auf 30
import numpy as np
values = np.array([0, 10, 20, 30, 40])
timestamps = np.arange(5.0) # [0.0, 1.0, 2.0, 3.0, 4.0]
# Bool-Maske erstellen, die True enthält, wo eine 20 gefolgt von einer 30 gefunden wird
boolMask = np.logical_and(values[:-1] == 20, values[1:] == 30) # [False, False, True, False]
# Entsprechendes Index-Array erstellen, Obacht: boolMask enthält ein Element weniger als values
indexArr = np.arange(values.shape[0] - 1)[boolMask] # [2]
# indexArr enthält bisher Position der 20, es soll jedoch der Wechsel 20 -> 30 gefunden werden
indexArr = indexArr + 1 # [3]
# Alternativ mit numpy.where()
indexArr = np.where(boolMask)[0] + 1 # [3]
print(timestamps[indexArr]) # [3.0]
print(values[indexArr]) # [30]