NumPy Einsum für wissenschaftliche Berechnungen

NumPyNumPyBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In der wissenschaftlichen Berechnung ist die effiziente Durchführung von linearen Algebraoperationen von entscheidender Bedeutung. NumPy, eine grundlegende Python-Bibliothek für numerische Berechnungen, bietet zahlreiche Werkzeuge für diese Operationen. Unter diesen Werkzeugen zeichnet sich einsum (Einstein-Summation) als besonders leistungsstarke Funktion zur prägnanten Darstellung komplexer Array-Operationen aus.

Dieses Tutorial führt Sie durch das Verständnis, was einsum ist und wie Sie es effektiv in Ihrem Python-Code einsetzen können. Am Ende dieses Labs können Sie verschiedene Array-Operationen mit der einsum-Funktion ausführen und deren Vorteile gegenüber herkömmlichen NumPy-Funktionen verstehen.

Grundlagen von NumPy Einsum verstehen

Die Einstein-Summation (einsum) ist eine leistungsstarke NumPy-Funktion, die es Ihnen ermöglicht, viele Array-Operationen mit einer prägnanten Notation auszudrücken. Sie folgt der Einstein-Summenkonvention, die in der Physik und Mathematik üblicherweise zur Vereinfachung komplexer Gleichungen verwendet wird.

Öffnen der Python-Shell

Beginnen wir damit, die Python-Shell zu öffnen. Öffnen Sie ein Terminal auf dem Desktop und geben Sie ein:

python3

Sie sollten die Python-Eingabeaufforderung (>>>) sehen, was darauf hinweist, dass Sie jetzt in der interaktiven Python-Shell sind.

Importieren von NumPy

Zunächst müssen wir die NumPy-Bibliothek importieren:

import numpy as np
Open Python Shell

Was ist Einsum?

Die einsum-Funktion in NumPy ermöglicht es Ihnen, Array-Operationen mit einer Zeichenkettennotation anzugeben, die beschreibt, welche Indizes (Dimensionen) der Arrays betrachtet werden sollen.

Das grundlegende Format einer einsum-Operation lautet:

np.einsum('notation', array1, array2, ...)

Dabei beschreibt die Notationszeichenkette die auszuführende Operation.

Ein einfaches Beispiel: Vektor-Skalarprodukt

Beginnen wir mit einem einfachen Beispiel: der Berechnung des Skalarprodukts zweier Vektoren. In mathematischer Notation lautet das Skalarprodukt zweier Vektoren u und v:

\sum_i u_i \times v_i

So berechnen Sie es mit einsum:

## Create two random vectors
u = np.random.rand(5)
v = np.random.rand(5)

## Print the vectors to see their values
print("Vector u:", u)
print("Vector v:", v)

## Calculate dot product using einsum
dot_product = np.einsum('i,i->', u, v)
print("Dot product using einsum:", dot_product)

## Verify with NumPy's dot function
numpy_dot = np.dot(u, v)
print("Dot product using np.dot:", numpy_dot)
Dot Product

Die Notation 'i,i->' bedeutet:

  • i repräsentiert den Index des ersten Arrays (u)
  • Der zweite i repräsentiert den Index des zweiten Arrays (v)
  • Der Pfeil -> gefolgt von nichts gibt an, dass wir ein Skalarergebnis möchten (Summation über alle Indizes)

Die Einsum-Notation verstehen

Die einsum-Notation folgt diesem allgemeinen Muster:

'index1,index2,...->output_indices'
  • index1, index2: Bezeichnungen für die Dimensionen jedes Eingabe-Arrays
  • output_indices: Bezeichnungen für die Dimensionen im Ausgabe-Array
  • Wiederholte Indizes in den Eingabe-Arrays werden summiert
  • Indizes, die in der Ausgabe erscheinen, bleiben im Ergebnis erhalten

Beispielsweise in der Notation 'ij,jk->ik':

  • i, j sind die Dimensionen des ersten Arrays
  • j, k sind die Dimensionen des zweiten Arrays
  • j erscheint in beiden Eingabe-Arrays, also summieren wir über diese Dimension
  • i, k erscheinen in der Ausgabe, also bleiben diese Dimensionen erhalten

Dies ist genau die Formel für die Matrixmultiplikation!

Häufige Einsum-Operationen

Nachdem wir die Grundlagen von einsum verstanden haben, wollen wir einige häufige Operationen erkunden, die wir mit dieser leistungsstarken Funktion ausführen können.

Matrixtransposition

Das Transponieren einer Matrix bedeutet, ihre Zeilen und Spalten zu vertauschen. In mathematischer Notation, wenn A eine Matrix ist, ist ihre Transponierte A^T definiert als:

A^T_{ij} = A_{ji}

Schauen wir uns an, wie man die Matrixtransposition mit einsum durchführt:

## Create a random matrix
A = np.random.rand(3, 4)
print("Original matrix A:")
print(A)
print("Shape of A:", A.shape)  ## Should be (3, 4)

## Transpose using einsum
A_transpose = np.einsum('ij->ji', A)
print("\nTransposed matrix using einsum:")
print(A_transpose)
print("Shape of transposed A:", A_transpose.shape)  ## Should be (4, 3)

## Verify with NumPy's transpose function
numpy_transpose = A.T
print("\nTransposed matrix using A.T:")
print(numpy_transpose)

Die Notation 'ij->ji' bedeutet:

  • ij repräsentiert die Indizes der Eingabematrix (i für Zeilen, j für Spalten)
  • ji repräsentiert die Indizes der Ausgabematrix (j für Zeilen, i für Spalten)
  • Wir tauschen im Wesentlichen die Positionen der Indizes

Matrixmultiplikation

Die Matrixmultiplikation ist eine grundlegende Operation in der linearen Algebra. Für zwei Matrizen A und B ist ihr Produkt C definiert als:

C_{ik} = \sum_j A_{ij} \times B_{jk}

So führt man die Matrixmultiplikation mit einsum aus:

## Create two random matrices
A = np.random.rand(3, 4)  ## 3x4 matrix
B = np.random.rand(4, 2)  ## 4x2 matrix

print("Matrix A shape:", A.shape)
print("Matrix B shape:", B.shape)

## Matrix multiplication using einsum
C = np.einsum('ij,jk->ik', A, B)
print("\nResult matrix C using einsum:")
print(C)
print("Shape of C:", C.shape)  ## Should be (3, 2)

## Verify with NumPy's matmul function
numpy_matmul = np.matmul(A, B)
print("\nResult matrix using np.matmul:")
print(numpy_matmul)

Die Notation 'ij,jk->ik' bedeutet:

  • ij repräsentiert die Indizes der Matrix A (i für Zeilen, j für Spalten)
  • jk repräsentiert die Indizes der Matrix B (j für Zeilen, k für Spalten)
  • ik repräsentiert die Indizes der Ausgabematrix C (i für Zeilen, k für Spalten)
  • Der wiederholte Index j wird summiert (Matrixmultiplikation)

Elementweise Multiplikation

Die elementweise Multiplikation besteht darin, die entsprechenden Elemente zweier Arrays zu multiplizieren. Für zwei Matrizen A und B mit der gleichen Form ist ihr elementweises Produkt C:

C_{ij} = A_{ij} \times B_{ij}

So führt man die elementweise Multiplikation mit einsum aus:

## Create two random matrices of the same shape
A = np.random.rand(3, 3)
B = np.random.rand(3, 3)

print("Matrix A:")
print(A)
print("\nMatrix B:")
print(B)

## Element-wise multiplication using einsum
C = np.einsum('ij,ij->ij', A, B)
print("\nElement-wise product using einsum:")
print(C)

## Verify with NumPy's multiply function
numpy_multiply = A * B
print("\nElement-wise product using A * B:")
print(numpy_multiply)

Die Notation 'ij,ij->ij' bedeutet:

  • ij repräsentiert die Indizes der Matrix A
  • ij repräsentiert die Indizes der Matrix B
  • ij repräsentiert die Indizes der Ausgabematrix C
  • Es werden keine Indizes summiert, was bedeutet, dass wir einfach die entsprechenden Elemente multiplizieren

Fortgeschrittene Einsum-Operationen

Nachdem wir uns mit den grundlegenden einsum-Operationen vertraut gemacht haben, wollen wir einige fortgeschrittenere Anwendungen erkunden. Diese Operationen zeigen die wahre Stärke und Flexibilität der einsum-Funktion.

Diagonalelementextraktion

Das Extrahieren der Diagonalelemente einer Matrix ist eine häufige Operation in der linearen Algebra. Für eine Matrix A bilden ihre Diagonalelemente einen Vektor d, wobei:

d_i = A_{ii}

So extrahiert man die Diagonale mit einsum:

## Create a random square matrix
A = np.random.rand(4, 4)
print("Matrix A:")
print(A)

## Extract diagonal using einsum
diagonal = np.einsum('ii->i', A)
print("\nDiagonal elements using einsum:")
print(diagonal)

## Verify with NumPy's diagonal function
numpy_diagonal = np.diagonal(A)
print("\nDiagonal elements using np.diagonal():")
print(numpy_diagonal)

Die Notation 'ii->i' bedeutet:

  • ii repräsentiert den wiederholten Index für die Diagonalelemente von A
  • i bedeutet, dass wir diese Elemente in ein 1D-Array extrahieren

Matrixspur

Die Spur einer Matrix ist die Summe ihrer Diagonalelemente. Für eine Matrix A ist ihre Spur:

\text{trace}(A) = \sum_i A_{ii}

So berechnet man die Spur mit einsum:

## Using the same matrix A from above
trace = np.einsum('ii->', A)
print("Trace of matrix A using einsum:", trace)

## Verify with NumPy's trace function
numpy_trace = np.trace(A)
print("Trace of matrix A using np.trace():", numpy_trace)

Die Notation 'ii->' bedeutet:

  • ii repräsentiert den wiederholten Index für die Diagonalelemente
  • Der leere Ausgabeindex bedeutet, dass wir alle Diagonalelemente summieren, um ein Skalar zu erhalten

Batch-Matrixmultiplikation

einsum zeigt seine Stärke besonders bei Operationen auf höherdimensionalen Arrays. Beispielsweise umfasst die Batch-Matrixmultiplikation das Multiplizieren von Matrixpaaren aus zwei Batches.

Wenn wir einen Batch von Matrizen A mit der Form (n, m, p) und einen Batch von Matrizen B mit der Form (n, p, q) haben, ergibt die Batch-Matrixmultiplikation ein Ergebnis C mit der Form (n, m, q):

C_{ijk} = \sum_l A_{ijl} \times B_{ilk}

So führt man die Batch-Matrixmultiplikation mit einsum aus:

## Create batches of matrices
n, m, p, q = 5, 3, 4, 2  ## Batch size and matrix dimensions
A = np.random.rand(n, m, p)  ## Batch of 5 matrices, each 3x4
B = np.random.rand(n, p, q)  ## Batch of 5 matrices, each 4x2

print("Shape of batch A:", A.shape)
print("Shape of batch B:", B.shape)

## Batch matrix multiplication using einsum
C = np.einsum('nmp,npq->nmq', A, B)
print("\nShape of result batch C:", C.shape)  ## Should be (5, 3, 2)

## Let's check the first matrix multiplication in the batch
print("\nFirst result matrix from batch using einsum:")
print(C[0])

## Verify with NumPy's matmul function
numpy_batch_matmul = np.matmul(A, B)
print("\nFirst result matrix from batch using np.matmul:")
print(numpy_batch_matmul[0])

Die Notation 'nmp,npq->nmq' bedeutet:

  • nmp repräsentiert die Indizes von Batch A (n für Batch, m für Zeilen, p für Spalten)
  • npq repräsentiert die Indizes von Batch B (n für Batch, p für Zeilen, q für Spalten)
  • nmq repräsentiert die Indizes des Ausgabe-Batches C (n für Batch, m für Zeilen, q für Spalten)
  • Der wiederholte Index p wird summiert (Matrixmultiplikation)

Warum Einsum verwenden?

Sie fragen sich vielleicht, warum wir einsum verwenden sollten, wenn NumPy bereits spezialisierte Funktionen für diese Operationen bietet. Hier sind einige Vorteile:

  1. Einheitliche Schnittstelle: einsum bietet eine einzige Funktion für viele Array-Operationen
  2. Flexibilität: Es kann Operationen ausdrücken, die sonst mehrere Schritte erfordern würden
  3. Lesbarkeit: Wenn Sie die Notation verstehen, wird der Code prägnanter
  4. Leistung: In vielen Fällen sind einsum-Operationen optimiert und effizient

Für komplexe Tensoroperationen bietet einsum oft die klarste und direkteste Implementierung.

Zusammenfassung

In diesem Lab haben Sie die leistungsstarke einsum-Funktion in NumPy kennengelernt, die die Einstein-Summenkonvention für Array-Operationen implementiert. Lassen Sie uns zusammenfassen, was Sie gelernt haben:

  1. Grundlegende Einsum-Konzepte: Sie haben gelernt, wie Sie die einsum-Notation verwenden können, um Array-Operationen auszudrücken, wobei Indizes die Array-Dimensionen repräsentieren und wiederholte Indizes Summationen anzeigen.

  2. Häufige Operationen: Sie haben mehrere grundlegende Operationen mit einsum implementiert:

    • Vektor-Skalarprodukt (Vector dot product)
    • Matrixtransposition
    • Matrixmultiplikation
    • Elementweise Multiplikation
  3. Fortgeschrittene Anwendungen: Sie haben komplexere Operationen erkundet:

    • Diagonalelementextraktion
    • Matrixspur
    • Batch-Matrixmultiplikation

Die einsum-Funktion bietet einen einheitlichen und flexiblen Ansatz für Array-Operationen in NumPy. Während es spezialisierte Funktionen wie np.dot, np.matmul und np.transpose für bestimmte Operationen gibt, bietet einsum eine konsistente Schnittstelle für eine Vielzahl von Operationen, was besonders bei der Arbeit mit höherdimensionalen Arrays von Wert ist.

Wenn Sie Ihre Reise in der wissenschaftlichen Berechnung und Datenwissenschaft fortsetzen, wird einsum ein leistungsstarkes Werkzeug in Ihrem Arsenal sein, um komplexe Array-Operationen mit prägnantem und lesbarem Code auszuführen.