import numpy as np
#' Definiere Matrix
A = np.array([[1, 2], [3, 4]])
A
#' Definiere Vektor
v = np.array([1, 2])
v
#' Matrix mit Einsen
E = np.ones((3, 2))
E
Ei = np.ones_like(A)
Ei
#' Nullmatrix
Z = np.zeros((3, 2))
Z
#' Einheitsmatrix Identitaet
I = np.eye(3)
I
#' transponierte Matrix
A
A.T
A.transpose()
#' Spur
A.trace()
#' Eigenschaften
A.size
A.shape
A.ndim
#' komplexwertige Matrix
C = np.array([[1.+2.j, 2.-1.j], [2.+1.j, 3.-5.j]]);
C
#' transponiert-konjugierte / adjungierte Matrix
display(C.T.conj(),C)
C.real
C.imag
Achtung: +, -, , %, /, ** wirken eintragsweise Die Standardoperationen wirken eintragsweise auf die Einträge der Arrays. A A ist also KEINE Matrix-Matrix-Multiplikation!
#' eintragsweise +
A+A
#' eintragsweise *
A*A
#' eintragsweise /
C/A
#' eintragsweise **
A**A
Broadcasting / Expansion in der Singleton Dimenson +, -, * , %, / wirken eintragsweise wobei die fehlende Dimension expandiert wird.
v = np.array([-5, 7])
v
#' Das erste Element von v wird zu jeder zu jedem Element der ersten Spalte addiert
A+v
#' Das erste Element von v wird ...
A*v
A.astype(float)**v
#' zu jedem Eintrag wird 1 addiert
A + 1
#' jeder Eintrag wird durch 3 dividiert
A / 3
#' 3 wird durch jeden Eintrag dividiert
3 / A
#' mit np.dot
A
np.dot(A, A)
#' @ Operator
#' verkürzte Notation: @
#' Statt des "dot"-Befehls kann man auch das @-Zeichen verwenden.
A@A
#' Matrix-Vektor Produkt funktioniert genau so
v = np.array([1, 2])
v
np.dot(A, v)
#' Auch hier kann @ verwendet werden
A@v
#' Skalarprodukt zweier Vektoren
np.dot(v, v)
#' Beachte: gleiche Resultate
np.dot(v, v.T)
v@v
np.dot(v.T, v)
Wieso ist das so? 'v' ist KEIN Zeilen/Spaltenvektor (hat nur eine Dimension), also bewirkt das Transponieren nichts.
# Achtung
xxl = np.array([i**2. for i in range(18952)])
xxl@xxl
#' Kreuzprodukt / Vektorprodukt mit np.cross
x = np.array([1, 0, 0])
y = np.array([0, 1, 0])
np.cross(x, y)
#' Dyadisches Produkt / tensorielles Produkt
#' (Multiplikation eines Spaltenvektor mit einem Zeilenvektor liefert Matrix)
np.outer(v, v)
Mehr Informationen zu Operationen auf Arrays finden Sie unter
https://www.python-kurs.eu/numpy_numerische_operationen_auf_arrays.php
Übersichtlicher: Definiere Vektoren als Zeilen- bzw. Spaltenvektor
#' @ funktionert dann immer so wie man es aus der linearen Algebra erwartet,
#' d.h. Zeilenvektor @ Spaltenvektor liefert skalare Größe,
#' Spaltenvektor @ Zeilenvektor liefert Matrix
v = np.array([1, 0]).reshape(2, 1) # Spaltenvektor
u = np.array([0, 1]).reshape(1, 2) # Zeilenvektor
A = np.array([[1, 2], [3, 4]])
#' Zahl
u@v
#' Matrix
v@u
#' Matrix-Vektor-Produkt
A@v
#' Das klappt auch von links
u@A
#' Achtung, hier stimmen die Dimensionen nicht mehr!
#A@u
Weitere Informationen zu reshape: https://www.python-kurs.eu/numpy_dimensionen_anpassen.php
#' np.amax(A) oder A.max() liefert das maximale Matrixelement:
np.max(A), A.max()
#'Maximum entlang der ersten Achse
A.max(1)
#' Maximum der 1. Zeile
A
np.max(A[0, :])
# "flattens" A in ein 1-dim. Array
A.flatten()
np.argmin(B) / np.argmax(B) liefert Index bezüglich "flattened array" des kleinsten / größten Matrixelements Falls das größte / kleinste Element mehrfach vorkommt, dann erhält man denersten Index
B = np.array([[2, 1], [1, 2]])
B
B.max(), B.argmax()
#' liefert das (erste) maximale Element
B.flatten()[np.argmax(B)]
#' Unterschied zu np.maximum
display(A,B,np.maximum(A,B))
#' broadcasting wird angewendet
v = np.array([5,1])
v
np.maximum(A,v)
A = np.arange(12)
#' A ist ein 1D array
A.shape
A.reshape(i,j) transformiert A in ein array mit i Zeilen und j Spalten
#' B hat zwei Dimensionen
B = A.reshape(3, 4)
B.shape, B
#' Die Anzahl der Elemente ändert sich natürlich nicht
A.size-B.size
#' Wichtig: A und B zeigen noch immer auf die selben Einträge im Speicher!
A[3] = -42
B[0,0] = -567
C = A.reshape(3, 4).copy()
C[0] = 123
display(A, B, C)
A = np.arange(16).reshape(4, 4)
A
#'Diagonale von A
np.diag(A)
#' Untere Dreiecksmatrix
np.tril(A)
#' Obere Dreiecksmatrix
np.triu(A)
#' np.diag kann auch Diagonalmatrizen erzeugen
B = np.diag(v.flatten())
B
#' np.diag für Nebendiagonalen
NU = np.diag(A, k=1) # obere Nebendiagonale
NU
NL = np.diag(A, k=-1) # untere Nebendiagonale
NL
#' Benutze np.diag zur Definition von Matrizen
x = [1, 2, 3]
A = np.diag(x, k=-1) + np.diag(x, k=1)
A
Wir können Integer-Arrays verwenden um andere Arrays zu definieren
#' 1. Beispiel zur Verwendung von Index-Arrays
# Array mit den ersten 8 Zweierpotenzen
a = 2**np.arange(8);
a
# Array mit geraden Zahlen von 0 bis 7
i = 2*np.arange(4); # Index-Array
i
# Jedes zweite Element von a in b speichern
b = a[i]
b
#' Beachte: Diesen Vektor können wir auch folgendermaßen erzeuge:
a[::2]
#' Die Konstruktion unter Verwendung von Index-Arrays ist aber im Allgemeinen flexibler
#' 2. Beispiel zur Verwendung von Index-Arrays
# Erzeuge einen Vektor, der die Gegendiagonale einer Matrix enthält
A = np.arange(16).reshape(4, 4)
A
i = np.arange(4)
j = i[::-1]
b = A[i, j]
b
#' Bsp: Setze alle negativen Matrixeinträge auf Null
A
B = A - A.T
B
B<0
B[B < 0] = 0
B
#' elementweises logisches "oder" und "und"
B = A - A.T
B
#' Welche Elemente von B sind kleiner als -5 ODER größer als 6?
IA = np.logical_or(B < -5, B > 6)
IA
#' Welche Elemente von B sind kleiner als 2 UND größer als 0?
np.logical_and(B < 7, B > 0)
B[IA] = 100
B
Erzeugt ein zusammengesetztes Array aus Blöcken des 2. Arrays unter Verwendung der durch das 1. Array beschriebenen Skalierung
#' einmal so rum
np.kron([1, 10, 100], [5, 6, 7])
#' anders rum kommt was anderes raus
np.kron([5, 6, 7], [1, 10, 100])
np.kron(np.eye(2), np.ones((2, 2)))
np.kron(np.ones((2, 2)),np.eye(2))
Füge eine Zeile oder Spalte b zu einer 3x3 Matrix A hinzu
#' Zeile anhängen mit np.vstack:
A = np.ones((3, 3))
b = np.array((2, 2, 2))
np.vstack([A, b])
#' Spalte anhängen mit np.hstack
A = np.ones((3, 3))
b = np.array((2, 2, 2)).reshape(3, 1) # erzeugt Spaltenvektor
np.hstack([A, b])
Alternativ kann man auch die (mächtigere) Funktion "np.concatenate" verwenden (siehe Hilfe)