NumPy Matrixmultiplikation: Vollstaendiger Leitfaden zu np.dot, matmul und @
Updated on
Matrixmultiplikation ist grundlegend fuer maschinelles Lernen, Computergrafik, Signalverarbeitung und wissenschaftliches Rechnen. Aber NumPy bietet drei Moeglichkeiten, Matrizen zu multiplizieren -- np.dot(), np.matmul() und den @-Operator -- und die Unterschiede zwischen ihnen sind verwirrend. Die Verwendung des falschen kann stillschweigend falsche Ergebnisse liefern, besonders bei Arrays unterschiedlicher Dimensionen oder wenn Sie elementweise Multiplikation (*) mit Matrixmultiplikation verwechseln.
Dieser Leitfaden klaert jede Methode, zeigt wann welche zu verwenden ist und bietet praktische Beispiele fuer jedes gaengige Muster der linearen Algebra.
Elementweise vs. Matrixmultiplikation
Zuerst die entscheidende Unterscheidung. Der *-Operator fuehrt elementweise Multiplikation durch, KEINE Matrixmultiplikation:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# Elementweise Multiplikation (Hadamard-Produkt)
print(A * B)
# [[ 5 12]
# [21 32]]
# Matrixmultiplikation
print(A @ B)
# [[19 22]
# [43 50]]Die Matrixmultiplikation folgt der Regel: C[i,j] = sum(A[i,k] * B[k,j]) fuer alle k.
Der @-Operator (empfohlen)
Der @-Operator (eingefuehrt in Python 3.5) ist die sauberste und lesbarste Methode fuer Matrixmultiplikation:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = A @ B
print(C)
# [[19 22]
# [43 50]]Shape-Regeln
Damit die Matrixmultiplikation A @ B funktioniert, muss die Anzahl der Spalten in A gleich der Anzahl der Zeilen in B sein:
import numpy as np
# (2, 3) @ (3, 4) = (2, 4)
A = np.ones((2, 3))
B = np.ones((3, 4))
C = A @ B
print(C.shape) # (2, 4)
# (5, 3) @ (3, 2) = (5, 2)
A = np.random.randn(5, 3)
B = np.random.randn(3, 2)
C = A @ B
print(C.shape) # (5, 2)
# Nicht uebereinstimmend loest ValueError aus
# np.ones((2, 3)) @ np.ones((4, 2)) # ValueErrornp.matmul()
np.matmul() macht genau das, was @ macht. Sie sind fuer alle praktischen Zwecke gleichwertig:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# Diese liefern identische Ergebnisse
result1 = A @ B
result2 = np.matmul(A, B)
print(np.array_equal(result1, result2)) # TrueVerwenden Sie @ fuer saubereren Code. Verwenden Sie np.matmul(), wenn Sie es als Funktionsargument uebergeben muessen (z.B. an reduce).
np.dot()
np.dot() ist aelter und verhaelt sich anders als @/matmul bei hoeher-dimensionalen Arrays:
import numpy as np
# Fuer 1D-Arrays: Skalarprodukt (Skalarergebnis)
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.dot(a, b)) # 32 (1*4 + 2*5 + 3*6)
# Fuer 2D-Arrays: Matrixmultiplikation (wie @)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(np.dot(A, B))
# [[19 22]
# [43 50]]Hauptunterschied: Hoehere Dimensionen
Fuer Arrays mit mehr als 2 Dimensionen verhalten sich np.dot() und @ unterschiedlich:
import numpy as np
A = np.random.randn(2, 3, 4)
B = np.random.randn(2, 4, 5)
# @ behandelt als Batch von Matrixmultiplikationen: (2, 3, 4) @ (2, 4, 5) = (2, 3, 5)
result_matmul = A @ B
print(result_matmul.shape) # (2, 3, 5)
# np.dot verwendet anderes Broadcasting: summiert ueber letzte Achse von A und vorletzte von B
result_dot = np.dot(A, B)
print(result_dot.shape) # (2, 3, 2, 5) -- andere Form!Empfehlung: Verwenden Sie @ oder np.matmul() fuer Matrixmultiplikation. Verwenden Sie np.dot() nur fuer explizite Skalarprodukte von 1D-Vektoren.
Methodenvergleich
| Merkmal | @-Operator | np.matmul() | np.dot() | *-Operator |
|---|---|---|---|---|
| Operation | Matrixmultiplikation | Matrixmultiplikation | Skalarprodukt | Elementweise |
| 1D x 1D | Skalarprodukt (Skalar) | Skalarprodukt (Skalar) | Skalarprodukt (Skalar) | Elementweise |
| 2D x 2D | Matrixmultiplikation | Matrixmultiplikation | Matrixmultiplikation | Elementweise |
| N-D Batch | Batch-Matmul | Batch-Matmul | Andere Semantik | Elementweise |
| Lesbarkeit | Beste | Gut | OK | N/A |
| Skalare erlaubt | Nein | Nein | Ja | Ja |
| Empfohlen | Ja | Ja (funktional) | Nur fuer 1D-Skalarprodukt | Fuer Hadamard |
Skalarprodukt (Vektoren)
Das Skalarprodukt zweier Vektoren ist die Summe ihrer elementweisen Produkte:
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# Alle aequivalent fuer 1D-Vektoren
print(np.dot(a, b)) # 32
print(a @ b) # 32
print(np.sum(a * b)) # 32Anwendungen
import numpy as np
# Kosinusaehnlichkeit
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
vec1 = np.array([1, 2, 3])
vec2 = np.array([4, 5, 6])
print(f"Cosine similarity: {cosine_similarity(vec1, vec2):.4f}")
# 0.9746
# Projektion von a auf b
def project(a, b):
return (np.dot(a, b) / np.dot(b, b)) * b
print(project(np.array([3, 4]), np.array([1, 0])))
# [3. 0.]Matrix-Vektor-Multiplikation
import numpy as np
# Lineare Transformation
A = np.array([[2, 0], [0, 3]]) # Skalierungsmatrix
v = np.array([1, 1])
result = A @ v
print(result) # [2 3]
# Gewichte in einer neuronalen Netzwerkschicht anwenden
weights = np.random.randn(10, 5) # 10 Ausgaenge, 5 Eingaenge
inputs = np.random.randn(5)
output = weights @ inputs
print(output.shape) # (10,)Batch-Matrixmultiplikation
Fuer Deep Learning und Batch-Verarbeitung behandelt @ Batches automatisch:
import numpy as np
# Batch von 32 Matrizen, jeweils 4x3, mal Batch von 32 Matrizen, jeweils 3x5
batch_A = np.random.randn(32, 4, 3)
batch_B = np.random.randn(32, 3, 5)
result = batch_A @ batch_B
print(result.shape) # (32, 4, 5)Praktische Beispiele
Lineares Gleichungssystem
import numpy as np
# Ax = b loesen
# 2x + 3y = 8
# 4x + y = 10
A = np.array([[2, 3], [4, 1]])
b = np.array([8, 10])
x = np.linalg.solve(A, b)
print(f"x = {x[0]:.2f}, y = {x[1]:.2f}")
# x = 2.20, y = 1.20
# Verifizieren: A @ x sollte b ergeben
print(A @ x) # [8. 10.]Einfacher neuronaler Netzwerk-Vorwaertsdurchlauf
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# Netzwerk: 3 Eingaenge -> 4 versteckte -> 2 Ausgaenge
np.random.seed(42)
W1 = np.random.randn(4, 3) * 0.5 # Erste Schicht Gewichte
b1 = np.zeros(4)
W2 = np.random.randn(2, 4) * 0.5 # Zweite Schicht Gewichte
b2 = np.zeros(2)
# Vorwaertsdurchlauf
X = np.array([1.0, 0.5, -1.0]) # Eingabe
h = sigmoid(W1 @ X + b1) # Versteckte Schicht
y = sigmoid(W2 @ h + b2) # Ausgabeschicht
print(f"Input: {X}")
print(f"Hidden: {h}")
print(f"Output: {y}")PCA-Projektion
import numpy as np
# Beispieldaten generieren
np.random.seed(42)
data = np.random.randn(100, 5) # 100 Samples, 5 Features
# Daten zentrieren
data_centered = data - data.mean(axis=0)
# Kovarianzmatrix mit Matrixmultiplikation berechnen
cov = (data_centered.T @ data_centered) / (len(data) - 1)
# Eigenzerlegung
eigenvalues, eigenvectors = np.linalg.eigh(cov)
# Auf die Top-2-Komponenten projizieren
top_2 = eigenvectors[:, -2:] # Letzte 2 (groesste Eigenwerte)
projected = data_centered @ top_2
print(f"Original shape: {data.shape}")
print(f"Projected shape: {projected.shape}") # (100, 2)Matrixoperationen visualisieren
Zur Erkundung der Auswirkungen von Matrixtransformationen auf Daten ermoeglicht PyGWalker (opens in a new tab) die interaktive Visualisierung projizierter Daten in Jupyter:
import pandas as pd
import pygwalker as pyg
df = pd.DataFrame(projected, columns=['PC1', 'PC2'])
walker = pyg.walk(df)FAQ
Was ist der Unterschied zwischen np.dot und np.matmul?
Fuer 1D- und 2D-Arrays liefern sie das gleiche Ergebnis. Der Hauptunterschied liegt bei hoeher-dimensionalen Arrays: np.matmul() (und @) behandelt sie als Batches von Matrizen, waehrend np.dot() eine andere Broadcasting-Regel verwendet. Fuer neuen Code bevorzugen Sie @ oder np.matmul().
Was macht der @-Operator in NumPy?
Der @-Operator fuehrt Matrixmultiplikation durch, aequivalent zu np.matmul(). Er wurde in Python 3.5 eingefuehrt. Fuer 2D-Arrays berechnet A @ B das Standard-Matrixprodukt. Fuer hoeher-dimensionale Arrays fuehrt er Batch-Matrixmultiplikation durch.
Warum liefert A * B andere Ergebnisse als A @ B?
A * B fuehrt elementweise Multiplikation (Hadamard-Produkt) durch und multipliziert entsprechende Elemente. A @ B fuehrt Matrixmultiplikation durch, nach der Regel C[i,j] = sum(A[i,k] * B[k,j]). Dies sind grundlegend verschiedene Operationen.
Wie berechne ich ein Skalarprodukt zweier Vektoren in NumPy?
Fuer 1D-Arrays (Vektoren) verwenden Sie np.dot(a, b), a @ b oder np.sum(a * b). Alle drei geben das gleiche skalare Ergebnis zurueck: die Summe der elementweisen Produkte.
Welche Formen sind fuer die Matrixmultiplikation erforderlich?
Fuer A @ B muss die letzte Dimension von A gleich der vorletzten Dimension von B sein. Fuer 2D: (m, n) @ (n, p) = (m, p). Die Anzahl der Spalten in A muss gleich der Anzahl der Zeilen in B sein.
Fazit
Fuer Matrixmultiplikation in NumPy verwenden Sie den @-Operator als Standard -- er ist am lesbarsten und behandelt Batch-Operationen korrekt. Verwenden Sie np.dot() nur fuer explizite 1D-Vektor-Skalarprodukte. Verwechseln Sie niemals * (elementweise) mit @ (Matrixmultiplikation). Merken Sie sich die Shape-Regel: (m, n) @ (n, p) = (m, p), und Sie vermeiden die haeufigsten Fehler bei der Matrixmultiplikation.