Kann mir jemand erklären, was der Zweck von meshgrid
in Numpy ist? Ich weiß, dass damit ein Koordinatennetz zum Plotten erstellt wird, aber ich kann den direkten Nutzen davon nicht wirklich sehen.
Ich studiere "Python Machine Learning" von Sebastian Raschka und er benutzt es, um die Entscheidungsgrenzen zu zeichnen. Siehe Eingabe 11 hier .
Ich habe diesen Code auch in der offiziellen Dokumentation ausprobiert, aber die Ausgabe ist für mich nicht wirklich sinnvoll.
x = np.arange(-5, 5, 1)
y = np.arange(-5, 5, 1)
xx, yy = np.meshgrid(x, y, sparse=True)
z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2)
h = plt.contourf(x,y,z)
Bitte zeigen Sie mir, wenn möglich, auch viele Beispiele aus der realen Welt.
Der Zweck von meshgrid
ist das Erstellen eines rechteckigen Gitters aus einem Array von x-Werten und einem Array von y-Werten.
Wenn wir zum Beispiel ein Gitter erstellen möchten, in dem wir einen Punkt bei jedem ganzzahligen Wert zwischen 0 und 4 in x- und y-Richtung haben. Um ein rechteckiges Gitter zu erstellen, benötigen wir jede Kombination der Punkte x
und y
.
Das werden 25 Punkte sein, oder? Wenn wir also für alle diese Punkte ein X- und Y-Array erstellen wollten, machen wir könnten.
x[0,0] = 0 y[0,0] = 0
x[0,1] = 1 y[0,1] = 0
x[0,2] = 2 y[0,2] = 0
x[0,3] = 3 y[0,3] = 0
x[0,4] = 4 y[0,4] = 0
x[1,0] = 0 y[1,0] = 1
x[1,1] = 1 y[1,1] = 1
...
x[4,3] = 3 y[4,3] = 4
x[4,4] = 4 y[4,4] = 4
Dies würde zu den folgenden x
- und y
-Matrizen führen, so dass die Paarung des entsprechenden Elements in jeder Matrix die x- und y-Koordinaten eines Punktes im Gitter ergibt.
x = 0 1 2 3 4 y = 0 0 0 0 0
0 1 2 3 4 1 1 1 1 1
0 1 2 3 4 2 2 2 2 2
0 1 2 3 4 3 3 3 3 3
0 1 2 3 4 4 4 4 4 4
Wir können diese dann zeichnen, um zu überprüfen, ob es sich um ein Raster handelt:
plt.plot(x,y, marker='.', color='k', linestyle='none')
Offensichtlich wird dies besonders für große Bereiche von x
und y
sehr langwierig. Stattdessen kann meshgrid
dies tatsächlich für uns generieren: Alles, was wir angeben müssen, sind die eindeutigen Werte x
und y
.
xvalues = np.array([0, 1, 2, 3, 4]);
yvalues = np.array([0, 1, 2, 3, 4]);
Wenn wir jetzt meshgrid
aufrufen, erhalten wir automatisch die vorherige Ausgabe.
xx, yy = np.meshgrid(xvalues, yvalues)
plt.plot(xx, yy, marker='.', color='k', linestyle='none')
Die Erstellung dieser rechteckigen Gitter ist für eine Reihe von Aufgaben nützlich. In dem von Ihnen bereitgestellten Beispiel können Sie einfach eine Funktion (sin(x**2 + y**2) / (x**2 + y**2)
) über einen Wertebereich für x
und y
abtasten.
Da diese Funktion in einem rechteckigen Raster abgetastet wurde, kann die Funktion jetzt als "Bild" angezeigt werden.
Außerdem kann das Ergebnis jetzt an Funktionen übergeben werden, die Daten im Rechteckraster erwarten (d. H. contourf
).
Tatsächlich ist der Zweck von np.meshgrid
Bereits in der Dokumentation erwähnt:
Koordinatenmatrizen von Koordinatenvektoren zurückgeben.
Erstellen Sie N-D-Koordinaten-Arrays für vektorisierte Auswertungen von N-D-Skalar-/Vektorfeldern über N-D-Gittern, wenn eindimensionale Koordinaten-Arrays x1, x2, ..., xn gegeben sind.
Der Hauptzweck besteht also darin, Koordinatenmatrizen zu erstellen.
Sie haben sich wahrscheinlich gerade gefragt:
Der Grund, warum Sie Koordinatenmatrizen mit Python/NumPy benötigen, ist, dass es keine direkte Beziehung zwischen Koordinaten und Werten gibt, außer wenn Ihre Koordinaten mit Null beginnen und rein positive ganze Zahlen sind. Dann können Sie einfach die Indizes eines Arrays als Index verwenden. Wenn dies jedoch nicht der Fall ist, müssen Sie Koordinaten neben Ihren Daten speichern. Hier kommen Gitter ins Spiel.
Angenommen, Ihre Daten lauten:
1 2 1
2 5 2
1 2 1
Jeder Wert repräsentiert jedoch einen 2 Kilometer breiten Bereich horizontal und 3 Kilometer vertikal. Angenommen, Ihr Ursprung befindet sich in der oberen linken Ecke und Sie möchten Arrays, die die Entfernung darstellen, die Sie verwenden könnten:
import numpy as np
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)
wo v ist:
0 2 4
0 2 4
0 2 4
und h:
0 0 0
3 3 3
6 6 6
Wenn Sie also zwei Indizes haben, sagen wir x
und y
(deshalb ist der Rückgabewert von meshgrid
normalerweise xx
oder xs
). Anstelle von x
habe ich in diesem Fall h
für horizontal gewählt!) Dann können Sie die x-Koordinate des Punktes, die y-Koordinate des Punktes und den Wert an diesem Punkt erhalten, indem Sie verwenden:
h[x, y] # horizontal coordinate
v[x, y] # vertical coordinate
data[x, y] # value
Das macht es viel einfacher, die Koordinaten zu verfolgen und (noch wichtiger) Sie können sie an Funktionen übergeben, die die Koordinaten kennen müssen.
np.meshgrid
Selbst wird jedoch häufig nicht direkt verwendet, meistens wird nur eines von similar Objekten np.mgrid
Oder np.ogrid
Verwendet. Hier repräsentiert np.mgrid
Den sparse=False
Und np.ogrid
Den sparse=True
Fall (ich beziehe mich auf das sparse
Argument von np.meshgrid
) . Beachten Sie, dass es einen signifikanten Unterschied zwischen np.meshgrid
Und np.ogrid
Und np.mgrid
Gibt: Die ersten beiden zurückgegebenen Werte (wenn es zwei oder mehr gibt) werden umgekehrt. Oft spielt dies keine Rolle, aber Sie sollten je nach Kontext aussagekräftige Variablennamen vergeben.
Zum Beispiel ist es im Fall eines 2D-Gitters und matplotlib.pyplot.imshow
Sinnvoll, das erste zurückgegebene Element von np.meshgrid
x
und das zweite y
zu benennen, während es ist umgekehrt für np.mgrid
und np.ogrid
.
np.ogrid
und spärliche Gitter>>> import numpy as np
>>> yy, xx = np.ogrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
Wie bereits erwähnt, ist die Ausgabe im Vergleich zu np.meshgrid
Umgekehrt. Deshalb habe ich sie anstelle von yy, xx
Als xx, yy
Entpackt:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6), sparse=True)
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5],
[-4],
[-3],
[-2],
[-1],
[ 0],
[ 1],
[ 2],
[ 3],
[ 4],
[ 5]])
Dies sieht bereits nach Koordinaten aus, insbesondere den x- und y-Linien für 2D-Diagramme.
Visualisiert:
yy, xx = np.ogrid[-5:6, -5:6]
plt.figure()
plt.title('ogrid (sparse meshgrid)')
plt.grid()
plt.xticks(xx.ravel())
plt.yticks(yy.ravel())
plt.scatter(xx, np.zeros_like(xx), color="blue", marker="*")
plt.scatter(np.zeros_like(yy), yy, color="red", marker="x")
np.mgrid
und dichte/ausgebildete Gitter>>> yy, xx = np.mgrid[-5:6, -5:6]
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
Gleiches gilt hier: Die Ausgabe ist umgekehrt zu np.meshgrid
:
>>> xx, yy = np.meshgrid(np.arange(-5, 6), np.arange(-5, 6))
>>> xx
array([[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]])
>>> yy
array([[-5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5],
[-4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4],
[-3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]])
Im Gegensatz zu ogrid
enthalten diese Arrays alle xx
und yy
Koordinaten in den -5 <= xx <= 5; -5 <= yy <= 5 grid.
yy, xx = np.mgrid[-5:6, -5:6]
plt.figure()
plt.title('mgrid (dense meshgrid)')
plt.grid()
plt.xticks(xx[0])
plt.yticks(yy[:, 0])
plt.scatter(xx, yy, color="red", marker="x")
Es ist nicht nur auf 2D beschränkt, diese Funktionen funktionieren für beliebige Dimensionen (nun, es gibt eine maximale Anzahl von Argumenten für die Funktion in Python und eine maximale Anzahl von Dimensionen, die NumPy zulässt):
>>> x1, x2, x3, x4 = np.ogrid[:3, 1:4, 2:5, 3:6]
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
x1
array([[[[0]]],
[[[1]]],
[[[2]]]])
x2
array([[[[1]],
[[2]],
[[3]]]])
x3
array([[[[2],
[3],
[4]]]])
x4
array([[[[3, 4, 5]]]])
>>> # equivalent meshgrid output, note how the first two arguments are reversed and the unpacking
>>> x2, x1, x3, x4 = np.meshgrid(np.arange(1,4), np.arange(3), np.arange(2, 5), np.arange(3, 6), sparse=True)
>>> for i, x in enumerate([x1, x2, x3, x4]):
... print('x{}'.format(i+1))
... print(repr(x))
# Identical output so it's omitted here.
Auch wenn diese auch für 1D funktionieren, gibt es zwei (viel häufigere) Funktionen zur Erstellung von 1D-Gittern:
Neben den Argumenten start
und stop
wird auch das Argument step
unterstützt (auch komplexe Schritte, die die Anzahl der Schritte darstellen):
>>> x1, x2 = np.mgrid[1:10:2, 1:10:4j]
>>> x1 # The dimension with the explicit step width of 2
array([[1., 1., 1., 1.],
[3., 3., 3., 3.],
[5., 5., 5., 5.],
[7., 7., 7., 7.],
[9., 9., 9., 9.]])
>>> x2 # The dimension with the "number of steps"
array([[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.],
[ 1., 4., 7., 10.]])
Sie haben speziell nach dem Zweck gefragt, und tatsächlich sind diese Gitter äußerst nützlich, wenn Sie ein Koordinatensystem benötigen.
Wenn Sie beispielsweise eine NumPy-Funktion haben, die den Abstand in zwei Dimensionen berechnet:
def distance_2d(x_point, y_point, x, y):
return np.hypot(x-x_point, y-y_point)
Und Sie möchten die Entfernung von jedem Punkt wissen:
>>> ys, xs = np.ogrid[-5:5, -5:5]
>>> distances = distance_2d(1, 2, xs, ys) # distance to point (1, 2)
>>> distances
array([[9.21954446, 8.60232527, 8.06225775, 7.61577311, 7.28010989,
7.07106781, 7. , 7.07106781, 7.28010989, 7.61577311],
[8.48528137, 7.81024968, 7.21110255, 6.70820393, 6.32455532,
6.08276253, 6. , 6.08276253, 6.32455532, 6.70820393],
[7.81024968, 7.07106781, 6.40312424, 5.83095189, 5.38516481,
5.09901951, 5. , 5.09901951, 5.38516481, 5.83095189],
[7.21110255, 6.40312424, 5.65685425, 5. , 4.47213595,
4.12310563, 4. , 4.12310563, 4.47213595, 5. ],
[6.70820393, 5.83095189, 5. , 4.24264069, 3.60555128,
3.16227766, 3. , 3.16227766, 3.60555128, 4.24264069],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6. , 5. , 4. , 3. , 2. ,
1. , 0. , 1. , 2. , 3. ],
[6.08276253, 5.09901951, 4.12310563, 3.16227766, 2.23606798,
1.41421356, 1. , 1.41421356, 2.23606798, 3.16227766],
[6.32455532, 5.38516481, 4.47213595, 3.60555128, 2.82842712,
2.23606798, 2. , 2.23606798, 2.82842712, 3.60555128]])
Die Ausgabe wäre identisch, wenn man ein dichtes Gitter anstelle eines offenen Gitters übergeben würde. NumPys Broadcasting macht es möglich!
Lassen Sie uns das Ergebnis visualisieren:
plt.figure()
plt.title('distance to point (1, 2)')
plt.imshow(distances, Origin='lower', interpolation="none")
plt.xticks(np.arange(xs.shape[1]), xs.ravel()) # need to set the ticks manually
plt.yticks(np.arange(ys.shape[0]), ys.ravel())
plt.colorbar()
Und dies ist auch der Fall, wenn NumPys mgrid
und ogrid
sehr praktisch werden, da Sie damit die Auflösung Ihrer Gitter leicht ändern können:
ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above
Da jedoch imshow
die Eingaben x
und y
nicht unterstützt, müssen die Häkchen manuell geändert werden. Es wäre wirklich praktisch, wenn die Koordinaten x
und y
akzeptiert würden, oder?
Mit NumPy ist es einfach, Funktionen zu schreiben, die sich auf natürliche Weise mit Rastern befassen. Darüber hinaus gibt es in NumPy, SciPy und matplotlib mehrere Funktionen, die erwarten, dass Sie das Raster passieren.
Ich mag Bilder, also lasst uns untersuchen matplotlib.pyplot.contour
:
ys, xs = np.mgrid[-5:5:200j, -5:5:200j]
density = np.sin(ys)-np.cos(xs)
plt.figure()
plt.contour(xs, ys, density)
Beachten Sie, wie die Koordinaten bereits richtig eingestellt sind! Das wäre nicht der Fall, wenn Sie gerade density
übergeben hätten.
Oder um ein weiteres lustiges Beispiel mit Astropiemodelle zu geben (diesmal interessieren mich die Koordinaten nicht so sehr, ich erstelle mit ihnen einfach einige Gitter):
from astropy.modeling import models
z = np.zeros((100, 100))
y, x = np.mgrid[0:100, 0:100]
for _ in range(10):
g2d = models.Gaussian2D(amplitude=100,
x_mean=np.random.randint(0, 100),
y_mean=np.random.randint(0, 100),
x_stddev=3,
y_stddev=3)
z += g2d(x, y)
a2d = models.AiryDisk2D(amplitude=70,
x_0=np.random.randint(0, 100),
y_0=np.random.randint(0, 100),
radius=5)
z += a2d(x, y)
Obwohl dies nur "für das Aussehen" ist, zeigen einige Funktionen, die sich auf Funktionsmodelle und die Anpassung beziehen (zum Beispiel scipy.interpolate.interp2d
, scipy.interpolate.griddata
sogar Beispiele mit np.mgrid
) In Scipy usw. benötigen Gitter. Die meisten arbeiten mit offenen Gittern und dichten Gittern, einige arbeiten jedoch nur mit einem von ihnen.
Angenommen, Sie haben eine Funktion:
def sinus2d(x, y):
return np.sin(x) + np.sin(y)
und Sie möchten zum Beispiel sehen, wie es im Bereich von 0 bis 2 * pi aussieht. Wie würdest du es machen? Dort kommt np.meshgrid
:
xx, yy = np.meshgrid(np.linspace(0,2*np.pi,100), np.linspace(0,2*np.pi,100))
z = sinus2d(xx, yy) # Create the image on this grid
und eine solche Verschwörung würde wie folgt aussehen:
import matplotlib.pyplot as plt
plt.imshow(z, Origin='lower', interpolation='none')
plt.show()
np.meshgrid
ist also nur eine Annehmlichkeit. Das Gleiche könnte im Prinzip durch:
z2 = sinus2d(np.linspace(0,2*np.pi,100)[:,None], np.linspace(0,2*np.pi,100)[None,:])
aber dort müssen Sie sich Ihrer Abmessungen bewusst sein (vorausgesetzt, Sie haben mehr als zwei ...) und die richtige Übertragung. np.meshgrid
erledigt all dies für Sie.
Mit meshgrid können Sie auch Koordinaten zusammen mit den Daten löschen, wenn Sie beispielsweise eine Interpolation durchführen möchten, jedoch bestimmte Werte ausschließen möchten:
condition = z>0.6
z_new = z[condition] # This will make your array 1D
wie würden Sie jetzt die Interpolation durchführen? Sie können x
und y
einer Interpolationsfunktion wie scipy.interpolate.interp2d
zuweisen, damit Sie wissen, welche Koordinaten gelöscht wurden:
x_new = xx[condition]
y_new = yy[condition]
und dann können Sie immer noch mit den "richtigen" Koordinaten interpolieren (versuchen Sie es ohne das Mesh-Grid und Sie haben viel zusätzlichen Code):
from scipy.interpolate import interp2d
interpolated = interp2(x_new, y_new, z_new)
und das ursprüngliche Maschennetz ermöglicht es Ihnen, die Interpolation wieder im ursprünglichen Gitter zu erhalten:
interpolated_grid = interpolated(xx, yy)
Dies sind nur einige Beispiele, bei denen ich meshgrid
verwendet habe. Es könnte viel mehr sein.
meshgrid hilft beim Erstellen eines rechteckigen Gitters aus zwei 1-D-Arrays aller Punktpaare aus den zwei Arrays.
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 1, 2, 3, 4])
Wenn Sie nun eine Funktion f (x, y) definiert haben und diese Funktion auf alle möglichen Kombinationen von Punkten aus den Arrays 'x' und 'y' anwenden möchten, können Sie Folgendes tun:
f(*np.meshgrid(x, y))
Wenn Ihre Funktion nur aus zwei Elementen besteht, kann so ein kartesisches Produkt effizient für große Arrays erreicht werden.
Empfohlen von hier