NumPy

Programmbibliothek für die Programmiersprache Python

NumPy ist eine Programmbibliothek für die Programmiersprache Python, die eine einfache Handhabung von Vektoren, Matrizen oder generell großen mehrdimensionalen Arrays ermöglicht. Neben den Datenstrukturen bietet NumPy auch effizient implementierte Funktionen für numerische Berechnungen an.[3]

NumPy

Basisdaten

Hauptentwickler Das NumPy-Team
Entwickler Travis Oliphant
Erscheinungsjahr 1995 (als Numeric); 2006 (als NumPy)
Aktuelle Version 2.0.0
Betriebssystem plattformübergreifend
Programmier­sprache Python, C[1], Fortran
Kategorie Numerische Bibliothek für wissenschaftliches Rechnen
Lizenz 3-Klausel-BSD[2]
numpy.org

Der Vorgänger von NumPy, Numeric, wurde unter Leitung von Jim Hugunin entwickelt. Travis Oliphant gliederte modifizierte Funktionalitäten des Konkurrenten Numarray in Numeric ein und veröffentlichte dies 2005 als NumPy. Die Bibliothek ist quelloffen und wird von vielen Mitwirkenden weiterentwickelt.

Merkmale

Bearbeiten

Der für Python standardmäßig installierte Interpreter CPython führt Kommandos als unoptimierten Bytecode aus. Mathematische Algorithmen sind in dieser Python-Variante oft langsamer als eine äquivalente kompilierte Umsetzung. NumPy stellt hier eine performante Alternative dar. Bestehende iterative Algorithmen müssen dazu gegebenenfalls für mehrdimensionale Array-Operationen umgeschrieben werden. NumPys Operatoren und Funktionen sind optimiert für derartige Arrays und ermöglichen so eine besonders effiziente Evaluation.

Die Handhabung von NumPy-Arrays in Python ist damit vergleichbar zu MATLAB; beide ermöglichen eine schnelle Ausführung von Algorithmen, solange diese für ganze Arrays oder Matrizen statt einzelne Skalare konzipiert sind. Die Integration von NumPy in Python ermöglicht die Verwendung und Kombination mit vielen weiteren Paketen aus dem umfangreichen Python-Umfeld. Weitere MATLAB-ähnliche Funktionen bietet die Python-Bibliothek SciPy. Auch der Funktionsumfang der Matplotlib-Bibliothek zur einfachen Erstellung von Plots in Python ist den Möglichkeiten von MATLAB sehr ähnlich. Intern verwenden sowohl MATLAB als auch NumPy die beiden Programmbibliotheken BLAS und LAPACK für eine effiziente Berechnung linearer Algebra.

Die Python-Schnittstelle des weit verbreiteten Computer-Vision-Pakets OpenCV verwendet intern NumPy-Arrays zur Verarbeitung von Daten. Bilder mit mehreren Farbkanälen werden beispielsweise mit dreidimensionalen Arrays dargestellt. Indexierung, Slicing oder Maskierung mit anderen Arrays sind daher sehr effiziente Methoden um gezielt auf bestimmte Pixel zugreifen zu können. NumPy-Arrays als universelle Datenstruktur für Bilder, extrahierte Feature-Punkte, Faltungsmatrizen und vieles mehr erleichtern die Entwicklung und das Debugging von Algorithmen zur Bildverarbeitung.

Die ndarray-Datenstruktur

Bearbeiten

Die Kernfunktionalität von NumPy basiert auf der Datenstruktur „ndarray“ (n-dimensionales Array), die auch als „NumPy Array“ bezeichnet wird. Dessen wesentliche Bestandteile sind ein Zeiger auf einen zusammenhängenden Speicherbereich zusammen mit Metadaten, welche die darin gespeicherten Daten beschreiben:[4][3]

 
Das NumPy-Array: Ein Zeiger auf Daten (engl. data) und die Metadaten Datentyp, Form und Schrittlänge (engl. data type, shape, stride)
Datentyp
Anders als in Pythons eigener List-Datenstruktur sind NumPy-Arrays homogen typisiert: Alle Elemente eines Arrays müssen vom selben Datentyp sein.
Form (engl. shape)
Definiert die Dimensionen in jeder Indexausprägung („Achse“) des Arrays und die Anzahl der Achsen (bzw. Indizes).
Schrittlängen (engl. strides)
Die Schrittlängen beschreiben für jede Achse, wie viele Bytes man im linearen Speicher springen muss, wenn ein zu dieser Achse gehöriger Index um 1 erhöht wird, zum Beispiel um zwischen zwei Zeilen oder zwei Spalten zu springen.

Diese Arrays erlauben es außerdem, von allozierten Puffern anderer Sprachen zu lesen, ohne Daten kopieren zu müssen. Mit C/C++-, Cython- oder Fortran-Erweiterungen des CPython-Interpreters können so auch einfach weitere bestehende Numerikbibliotheken mitverwendet werden. Dieses Verhalten wird beispielsweise von SciPy genutzt, welches Wrapper für externe Bibliotheken wie BLAS oder LAPACK bereitstellt. NumPy bietet native Unterstützung für Memory Mapping der ndarrays.[4]

Einschränkungen

Bearbeiten

Tatsächliches Einfügen oder Anhängen von Array-Einträgen wie bei Pythons Listen ist nicht möglich. Die Funktion np.pad(), mit der Arrays erweitert werden können, legt neue Arrays gewünschter Größe an, kopiert bestehende hinein und liefert dies zurück. Auch bei der Aneinanderreihung zweier Arrays mit np.concatenate([a1,a2]) werden die Arrays nicht wirklich verkettet, sondern ein neues zusammenhängendes Array zurückgegeben. Bei NumPys Funktion np.reshape() ist eine Umformung auch nur möglich, wenn sich die Anzahl der Array-Einträge nicht ändert. Diese Einschränkungen sind darauf zurückzuführen, dass NumPy-Arrays im Speicher als zusammenhängender Bereich angelegt werden müssen. Das Blaze-Framework bietet hier eine Alternative, welches diese Einschränkung beheben soll.[5]

Die Verwendung von NumPy-Arrays allein gegenüber Python-Listen bringt noch keinen Geschwindigkeitsvorteil mit sich. Entsprechende Algorithmen müssen zunächst in eine vektortaugliche Form umgeschrieben werden. Dies kann von Nachteil sein, da eventuell temporäre Arrays in Größe der Eingabe angelegt werden müssen und sich damit die Speicherkomplexität von konstant zu linear vergrößert. Eine Laufzeitkompilation wurde schon in einigen Paketen implementiert, um diese Probleme zu vermeiden. Open-Source-Lösungen, die mit NumPy interagieren können, sind unter anderem numexpr[6] und Numba.[7] Außerdem gibt es mit Cython noch eine statisch kompilierbare Alternative.

NumPy Arrays werden den Anforderungen bei der Verarbeitung großer Datenmengen und denen des Deep Learnings oftmals nicht gerecht. Zum Beispiel lädt NumPy die in den Arrays enthaltenen Daten komplett in den Arbeitsspeicher eines Computers, dessen Kapazität von wissenschaftlichen Datensätzen aber oft überschritten wird. Viele Deep Learning-Anwendungen wurden erst dadurch ermöglicht, dass die dafür notwendigen Operationen der linearen Algebra auf Rechnerverbünden mit spezieller, hochparalleler Hardware wie Grafikkarten und Tensor-Prozessoren verlagert wurden, NumPy aber für die Berechnung auf dem Prozessor und auf einzelnen Computer konzipiert wurde. Um diese Herausforderungen zu meistern, sind viele alternative Array-Implementierungen für Python erschienen, wie zum Beispiel Dask[8] zum parallelen Rechnen auf Rechnerverbünden und TensorFlow und JAX[9] für Berechnungen auf Grafikkarten. Der Einfluss NumPys wird daran deutlich, dass diese Bibliotheken meistens eine NumPy-ähnliche Programmierschnittstelle oder eine Untermenge davon zur Verfügung stellen, um Anfängern den Umstieg zu erleichtern und eine Änderung der Array-Implementierung mit nur minimalen Änderungen am Programmquelltext zu ermöglichen.[3]

Beispiele

Bearbeiten
Array-Erzeugung
>>> import numpy as np
>>> x = np.array([1, 2, 3])
>>> x
array([1, 2, 3])
>>> y = np.arange(10) # analog zu Python's y = [i for i in range(10)], nur wird ein Array statt einer Liste generiert
>>> y
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Basic operations
>>> a = np.array([1, 2, 3, 6])
>>> b = np.linspace(0, 2, 4) # erzeugt vier äquidistante Werte im Intervall [0,2]
>>> c = a - b
>>> c
array([ 1.    , 1.33333333, 1.66666667, 4.    ])
>>> a**2 # Python Operatoren können direkt auf Arrays angewandt werden
array([ 1, 4, 9, 36])
Universelle Funktionen
>>> a = np.linspace(-np.pi, np.pi, 100)
>>> b = np.sin(a)
>>> c = np.cos(a)
Lineare Algebra
>>> from numpy.random import rand
>>> from numpy.linalg import solve, inv
>>> a = np.array([[1, 2, 3], [3, 4, 6.7], [5, 9.0, 5]])
>>> a.transpose()
array([[1. , 3. , 5. ],
       [ 2. , 4. , 9. ],
       [ 3. , 6.7, 5. ]])
>>> inv(a)
array([[-2.27683616, 0.96045198, 0.07909605],
       [ 1.04519774, -0.56497175, 0.1299435 ],
       [ 0.39548023, 0.05649718, -0.11299435]])
>>> b = np.array([3, 2, 1])
>>> solve(a, b) # Löst die Gleichung ax = b
array([-4.83050847, 2.13559322, 1.18644068])
>>> c = rand(3, 3) # Erzeugt eine zufällige 3x3 Matrix mit Werten im Intervall [0,1]
>>> c
array([[0.3242542 , 0.94330798, 0.27474668],
       [0.45979412, 0.39204496, 0.58138993],
       [0.66361452, 0.90350118, 0.65898373]])
>>> np.dot(a, c) # Punkt-Produkt/Skalarprodukt der Matrizen
array([[ 3.23468601,  4.43790144,  3.41447772],
       [ 7.25815638, 10.45156168,  7.56499072],
       [ 9.07749071, 12.76245045,  9.9011614 ]])
>>> a @ c # Möglich ab Python 3.5 und NumPy 1.10
array([[ 3.23468601,  4.43790144,  3.41447772],
       [ 7.25815638, 10.45156168,  7.56499072],
       [ 9.07749071, 12.76245045,  9.9011614 ]])
Integration in OpenCV
>>> import numpy as np
>>> import cv2
>>> r = np.reshape(np.arange(256*256)%256,(256,256)) # 256x256 Pixel Array mit horizontalem Verlauf von 0 bis 255 für den roten Farbkanal
>>> g = np.zeros_like(r) # Array selber Größe und selbem Datentyp wie r aber gefüllt mit Nullen für den grünen Farbkanal
>>> b = r.T # Das transponierte r Array wird als vertikaler Verlauf des blauen Farbkanals verwendet.
>>> cv2.imwrite('gradients.png', np.dstack([b,g,r])) # OpenCV interpretiert Bilder in BGR, das in dritter Dimension gestapelte Array wird als 8bit RGB PNG-Datei 'gradients.png' gespeichert
True
Nächste-Nachbar-Suche – Iterativer Python-Algorithmus und vektorisierte NumPy-Alternative
>>> # # # Iterative Python Variante # # #
>>> points = [[9,2,8],[4,7,2],[3,4,4],[5,6,9],[5,0,7],[8,2,7],[0,3,2],[7,3,0],[6,1,1],[2,9,6]]
>>> qPoint = [4,5,3]
>>> minIdx = -1
>>> minDist = -1
>>> for idx, point in enumerate(points): # iteriere über alle Punkte
        dist = sum([(dp-dq)**2 for dp,dq in zip(point,qPoint)])**0.5 # berechne die Euklidische Distanz jedes Punkts zu q
        if dist < minDist or minDist < 0: # wenn nötig, aktualisiere die minimale Distanz und Index des entsprechenden Punkts
            minDist = dist
            minIdx = idx

>>> print 'Nächster Punkt zu q: ', points[minIdx]
Nächster Punkt zu q: [3, 4, 4]
>>>
>>>
>>> # # # Äquivalente NumPy Vektorisierung # # #
>>> import numpy as np
>>> points = np.array([[9,2,8],[4,7,2],[3,4,4],[5,6,9],[5,0,7],[8,2,7],[0,3,2],[7,3,0],[6,1,1],[2,9,6]])
>>> qPoint = np.array([4,5,3])
>>> minIdx = np.argmin(np.linalg.norm(points-qPoint,axis=1)) # berechne alle Euklidischen Distanzen auf einmal und bestimme den Index des kleinsten Werts
>>> print 'Nächster Punkt zu q: ', points[minIdx]
Nächster Punkt zu q: [3 4 4]

Geschichte

Bearbeiten

Die Programmiersprache Python war ursprünglich nicht für numerische Berechnungen optimiert, erlangte aber schnell große Bekanntheit im Anwendungsbereich des Wissenschaftlichen Rechnens. So wurde 1995 die Interessengemeinschaft matrix-sig gegründet, die das Ziel verfolgte, ein einheitliches Paket zur Array-Handhabung zu definieren. Eines der Mitglieder war Python-Autor Guido van Rossum, welcher Syntaxerweiterungen, besonders die Indexierung, direkt in Python einpflegte, um die Verwendung von Arrays zu vereinfachen.[10] Die erste Implementierung eines Matrizenpakets wurde von Jim Fulton entwickelt, die später von Jim Hugunin generalisiert und als Numeric[10] (teilweise auch Numerical Python Extensions) bekannt wurde, dem Vorläufer von NumPy.[11][12] Hugunin war damals Student am MIT,[12]:10, verließ das Projekt aber 1997 um weiter an JPython zu arbeiten.[10] Paul Dubois vom LLNL übernahm die Leitung des Projekts.[12]:10 Weitere Beitragende der ersten Stunde waren außerdem David Ascher, Konrad Hinsen und Travis Oliphant.[12]:10

Das Paket Numarray wurde als Alternative zu Numeric entwickelt, die mehr Flexibilität bieten sollte.[4] Beide Pakete gelten inzwischen als veraltet und werden nicht mehr weiterentwickelt.[13] Numarray and Numeric hatten jeweils ihre Stärken und Schwächen und wurden eine Zeit lang noch parallel für unterschiedliche Anwendungsbereiche eingesetzt. Die letzte Version (v24.2) von Numeric erschien am 11. November 2005, die letzte (v1.5.2) von Numarray am 24. August 2006.[14]

Anfang 2005 begann Travis Oliphant den Funktionsumfang von Numarray in Numeric zu übertragen, um die Entwicklergemeinschaft auf ein vereinigtes Projekt zu konzentrieren; das Ergebnis wurde 2005 als NumPy 1.0 veröffentlicht.[4] Dieses neue Projekt war außerdem Teil von SciPy, wurde aber auch separat als NumPy angeboten um zu vermeiden, dass das große SciPy-Paket installiert werden muss nur, um mit Array-Objekten arbeiten zu können. Von Version 1.5.0 an kann NumPy auch mit Python 3 verwendet werden.[15]

2011 begann die Entwicklung einer NumPy-API für PyPy.[16] Bislang wird allerdings noch nicht der gesamte NumPy-Funktionsumfang unterstützt.[17]

Am 15. November 2017 gab das Team rund um NumPy bekannt, ab dem 1. Januar 2019 neue Funktionen nur noch für Python 3 bereitstellen zu wollen, während für Python 2 nur noch Fehlerbereinigungen erscheinen werden. Ab dem 1. Januar 2020 würden dann keine weiteren Aktualisierungen mehr für Python 2 folgen.[18][19][20]

Siehe auch

Bearbeiten

Literatur

Bearbeiten
Bearbeiten
Commons: NumPy – Sammlung von Bildern, Videos und Audiodateien

Einzelnachweise

Bearbeiten
  1. The numpy Open Source Project on Open Hub: Languages Page. In: Open Hub. (abgerufen am 14. Juli 2018).
  2. github.com. (abgerufen am 1. September 2016).
  3. a b c Charles R. Harris, K. Jarrod Millman, Stéfan J. van, Ralf Gommers, Pauli Virtanen, David Cournapeau, Eric Wieser, Julian Taylor, Sebastian Berg, Nathaniel J. Smith, Robert Kern, Matti Picus, Stephan Hoyer, Marten H. van, Matthew Brett, Allan Haldane, Jaime Fernández del, Mark Wiebe, Pearu Peterson, Pierre Gérard-Marchant, Kevin Sheppard, Tyler Reddy, Warren Weckesser, Hameer Abbasi, Christoph Gohlke, Travis E. Oliphant: Array programming with NumPy. In: Nature. 585. Jahrgang, Nr. 7825, 16. September 2020, S. 357–362, doi:10.1038/s41586-020-2649-2 (englisch, nature.com).
  4. a b c d Stéfan van der Walt, S. Chris Colbert und Gaël Varoquaux: The NumPy array: a structure for efficient numerical computation. In: Computing in Science and Engineering. IEEE, 2011, arxiv:1102.1523 (englisch).
  5. Blaze Ecosystem Docs. In: Read the Docs. Abgerufen am 6. Januar 2016 (englisch).
  6. Francesc Alted: numexpr. Abgerufen am 8. März 2014 (englisch).
  7. Numba. Abgerufen am 6. Januar 2016 (englisch).
  8. Dask, auf dask.org
  9. JAX reference documentation, auf jax.readthedocs.io
  10. a b c K. Jarrod Millman, Michael Aivazis: Python for Scientists and Engineers. In: Computing in Science and Engineering. 13. Jahrgang, Nr. 2, 2011, S. 9–12 (englisch, computer.org).
  11. Travis Oliphant: Python for Scientific Computing. In: Computing in Science and Engineering. 2007 (englisch, h2desk.com [PDF]).
  12. a b c d David Ascher, Paul F. Dubois, Konrad Hinsen, Jim Hugunin, Travis Oliphant: Numerical Python. 1999, abgerufen am 6. Januar 2016 (englisch).
  13. @1@2Vorlage:Toter Link/www.stsci.eduNumarray Homepage (Seite dauerhaft nicht mehr abrufbar, festgestellt im Februar 2024. Suche in Webarchiven)
  14. NumPy Sourceforge Files. Abgerufen am 6. Januar 2016 (englisch).
  15. NumPy 1.5.0 Release Notes. Abgerufen am 6. Januar 2016 (englisch).
  16. PyPy Status Blog: Numpy funding and status update. Abgerufen am 6. Januar 2016 (englisch).
  17. NumPyPy Status. Abgerufen am 6. Januar 2016 (englisch).
  18. Add NumPy · python3statement/python3statement.github.io. In: GitHub. Abgerufen am 7. Juli 2018 (englisch).
  19. Moving to require Python 3 (englisch), auf python3statement.org, abgerufen am 17. Oktober 2018
  20. Plan for dropping Python 2.7 support. In: Scipy.org. Archiviert vom Original am 8. Juli 2018; abgerufen am 7. Juli 2018 (englisch).