Skip to content

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))  # ValueError

np.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))  # True

Verwenden 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@-Operatornp.matmul()np.dot()*-Operator
OperationMatrixmultiplikationMatrixmultiplikationSkalarproduktElementweise
1D x 1DSkalarprodukt (Skalar)Skalarprodukt (Skalar)Skalarprodukt (Skalar)Elementweise
2D x 2DMatrixmultiplikationMatrixmultiplikationMatrixmultiplikationElementweise
N-D BatchBatch-MatmulBatch-MatmulAndere SemantikElementweise
LesbarkeitBesteGutOKN/A
Skalare erlaubtNeinNeinJaJa
EmpfohlenJaJa (funktional)Nur fuer 1D-SkalarproduktFuer 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))    # 32

Anwendungen

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.

📚