Was ist der Zweck von meshgrid in Python / NumPy?

302

Kann mir jemand erklären, was der Zweck der meshgridFunktion in Numpy ist? Ich weiß, dass dadurch eine Art Koordinatengitter zum Zeichnen erstellt wird, aber ich kann den direkten Nutzen davon nicht wirklich erkennen.

Ich studiere "Python Machine Learning" von Sebastian Raschka und er verwendet es zum Zeichnen der Entscheidungsgrenzen. Siehe Eingabe 11 hier .

Ich habe diesen Code auch aus der offiziellen Dokumentation ausprobiert, aber auch hier macht die Ausgabe für mich keinen Sinn.

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 Praxis.

HonzaB
quelle

Antworten:

389

Der Zweck von meshgridbesteht darin, ein rechteckiges Gitter aus einem Array von x-Werten und einem Array von y-Werten zu erstellen.

Wenn wir zum Beispiel ein Gitter erstellen möchten, bei dem wir bei jedem ganzzahligen Wert einen Punkt zwischen 0 und 4 sowohl in x- als auch in y-Richtung haben. Um ein rechteckiges Gitter zu erstellen, benötigen wir jede Kombination der Punkte xund y.

Das werden 25 Punkte sein, oder? Wenn wir also eine x- und y - Array für alle diese Punkte schaffen wollte, wir könnten die folgende tun.

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 Folgendem xund yMatrizen 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')

Geben Sie hier die Bildbeschreibung ein

Offensichtlich wird dies besonders für große Bereiche von xund sehr mühsam y. Stattdessen meshgridkann dies tatsächlich für uns generieren: Alles, was wir angeben müssen, sind die eindeutigen xund yWerte.

xvalues = np.array([0, 1, 2, 3, 4]);
yvalues = np.array([0, 1, 2, 3, 4]);

Wenn wir jetzt anrufen meshgrid, erhalten wir automatisch die vorherige Ausgabe.

xx, yy = np.meshgrid(xvalues, yvalues)

plt.plot(xx, yy, marker='.', color='k', linestyle='none')

Geben Sie hier die Bildbeschreibung ein

Die Erstellung dieser rechteckigen Gitter ist für eine Reihe von Aufgaben nützlich. In dem Beispiel, das Sie in Ihrem Beitrag angegeben haben, können Sie einfach eine Funktion ( sin(x**2 + y**2) / (x**2 + y**2)) über einen Wertebereich für xund abtasten y.

Da diese Funktion in einem rechteckigen Raster abgetastet wurde, kann die Funktion jetzt als "Bild" dargestellt werden.

Geben Sie hier die Bildbeschreibung ein

Zusätzlich kann das Ergebnis jetzt an Funktionen übergeben werden, die Daten auf einem rechteckigen Raster erwarten (dh contourf)

Suever
quelle
10
Sie haben die Rückgabewerte xxund nicht erklärt yy. Der mysteriöse Teil für mich war, warum es diese beiden Ergebnisse zurückgibt und wie sie aussehen. Hai Phans Antwort ist dafür praktisch. Ich denke, das macht es der Einfachheit halber, da die Handlung zwei solche Parameter will.
Nealmcb
2
Ich weiß es nicht - deshalb suche ich diese Informationen nach;) Also sage ich nicht, dass sie etwas anderes zurückgeben sollten. Ich rate nur nach einer fehlenden Information für diejenigen, die gerade die akzeptierte Antwort gelesen haben. Und wenn Sie möchten, schlage ich vor, dass Ihre Antwort (die bereits sehr nett ist - danke!) Etwas vollständiger wäre, wenn Sie die Rückgabewerte (wie Hai) für diejenigen von uns erklären würden, die immer noch verwirrt sind.
Nealmcb
1
Um die Werte von xx und yy besser zu verstehen, betrachten Sie die Behauptung, dass der folgende Code das gleiche Ergebnis wie np.meshgrid liefert:xx = [xvalues for y in yvalues] yy = [[y for x in xvalues] for y in yvalues]
Matt Kleinsmith
1
Diese Antwort ist verwirrend. Ist Ihre erste Illustration nicht xund yrückwärts? Wenn Sie dies tun xx, yy = np.meshgrid(np.arange(4), np.arange(4)), ist es das Gegenteil von dem, was Sie haben, xund yim ersten Teil der Antwort. Es entspricht der Reihenfolge der Ausgaben für mgrid, jedoch nicht dem Meshgrid. Die xxsollte in x-Richtung zunehmen, Ihre jedoch in y-Richtung.
Scott Staniewicz
1
@ScottStaniewicz Danke, dass du darauf hingewiesen hast, dass wir jetzt sicher sind, wie ich das vermasselt habe ... Aktualisiert!
Suever
249

Mit freundlicher Genehmigung von Microsoft Excel: 

Geben Sie hier die Bildbeschreibung ein

Sarsaparille
quelle
6
Nett. Fwiw, wenn Sie ein 2 x 12 Array der Paare in der Mitte wollen:XYpairs = np.vstack([ XX.reshape(-1), YY.reshape(-1) ])
Denis
5
und wenn Sie eine 12 x 2 Anordnung der Paare in der Mitte wollen:XYpairs = np.dstack([XX, YY]).reshape(-1, 2)
barlaensdoonn
2
Gute Antwort. Der Zweck von meshgrid besteht darin, ein Gitter unter Verwendung der Koordinate jedes Dim zu erstellen.
Guter Junge
1
Was ich etwas seltsam finde, ist, dass die x- und y-Werte separat zurückgegeben werden, anstatt bereits in einem Array kombiniert zu sein. Wenn ich sie in einem Array haben möchte, muss ich np.vstack([XX.ravel(), YY.ravel()]).T
Folgendes
64

Eigentlich ist der Zweck von np.meshgridbereits in der Dokumentation erwähnt:

np.meshgrid

Koordinatenmatrizen von Koordinatenvektoren zurückgeben.

Erstellen Sie ND-Koordinatenarrays für vektorisierte Auswertungen von ND-Skalar- / Vektorfeldern über ND-Gitter mit gegebenen eindimensionalen Koordinatenarrays x1, x2, ..., xn.

Der Hauptzweck besteht also darin, Koordinatenmatrizen zu erstellen.

Sie haben sich wahrscheinlich gerade gefragt:

Warum müssen wir Koordinatenmatrizen erstellen?

Der Grund, warum Sie Koordinatenmatrizen mit Python / NumPy benötigen, ist, dass es keine direkte Beziehung von Koordinaten zu 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 die Koordinaten neben Ihren Daten speichern. Hier kommen Gitter ins Spiel.

Angenommen, Ihre Daten sind:

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 ist die obere linke 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:

array([[0, 0, 0],
       [2, 2, 2],
       [4, 4, 4]])

und h:

array([[0, 3, 6],
       [0, 3, 6],
       [0, 3, 6]])

Wenn Sie also zwei Indizes haben, sagen wir xund y(deshalb ist der Rückgabewert von meshgridnormalerweise xxoder xsanstelle von xin diesem Fall hhorizontal gewählt!), Können Sie die x-Koordinate des Punkts, die y-Koordinate des Punkts und die erhalten Wert an diesem Punkt durch Verwendung von:

h[x, y]    # horizontal coordinate
v[x, y]    # vertical coordinate
data[x, y]  # value

Das macht es viel einfacher, die Koordinaten zu verfolgen, und (was noch wichtiger ist) Sie können sie an Funktionen übergeben, die die Koordinaten kennen müssen.

Eine etwas längere Erklärung

Es wird jedoch np.meshgridnicht oft direkt verwendet, meistens verwendet man nur eines von ähnlichen Objekten np.mgridoder np.ogrid. Hier np.mgridstellt der sparse=Falseund np.ogridder sparse=TrueFall dar (ich beziehe mich auf das sparseArgument von np.meshgrid). Beachten Sie, dass zwischen np.meshgridund np.ogridund ein signifikanter Unterschied besteht np.mgrid: Die ersten beiden zurückgegebenen Werte (wenn zwei oder mehr vorhanden sind) werden umgekehrt. Oft spielt dies keine Rolle, aber Sie sollten je nach Kontext aussagekräftige Variablennamen angeben.

Zum Beispiel im Fall eines 2D-Gitters und matplotlib.pyplot.imshowes ist sinnvoll, das erste zurückgegebene Element np.meshgrid xund das zweite Element zu benennen, ywährend es für np.mgridund umgekehrt ist 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 gesagt, ist die Ausgabe im Vergleich zu umgekehrt np.meshgrid, deshalb habe ich sie entpackt als yy, xxstatt xx, yy:

>>> 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 nach 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")

Geben Sie hier die Bildbeschreibung ein

np.mgrid und dichte / ausgearbeitete 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 im Vergleich 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 ogriddiesen Arrays enthalten alle xx und yyKoordinaten in -5 <= xx <= 5; -5 <= yy <= 5 Gitter.

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")

Geben Sie hier die Bildbeschreibung ein

Funktionalität

Diese Funktionen sind nicht nur auf 2D beschränkt, sondern funktionieren auch für beliebige Dimensionen (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 (weitaus häufigere) Funktionen zur Erstellung von 1D-Gittern:

Neben dem startund stopArgumente unterstützt es auch das stepArgument (auch komplexe Schritte , die die Anzahl der Schritte dar):

>>> 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.]])

Anwendungen

Sie haben speziell nach dem Zweck gefragt, und tatsächlich sind diese Gitter äußerst nützlich, wenn Sie ein Koordinatensystem benötigen.

Zum Beispiel, wenn Sie 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 jedes Punktes 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 in einem dichten Gitter anstelle eines offenen Gitters passieren 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()

Geben Sie hier die Bildbeschreibung ein

Und dies ist auch bei NumPys der Fall mgridund ogridwird sehr praktisch, da Sie damit die Auflösung Ihrer Gitter einfach ändern können:

ys, xs = np.ogrid[-5:5:200j, -5:5:200j]
# otherwise same code as above

Geben Sie hier die Bildbeschreibung ein

Da dies imshowjedoch nicht unterstützt xund yeingegeben wird, müssen die Ticks von Hand geändert werden. Es wäre wirklich praktisch, wenn es die xund yKoordinaten akzeptieren würde , oder?

Mit NumPy ist es einfach, Funktionen zu schreiben, die sich auf natürliche Weise mit Gittern 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 Folgendes erkunden 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)

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, wie die Koordinaten bereits richtig eingestellt sind! Das wäre nicht der Fall, wenn Sie nur in der density.

Oder um ein weiteres lustiges Beispiel mit Astropiemodellen zu geben (diesmal interessieren mich die Koordinaten nicht sonderlich, ich verwende sie nur, um ein Raster zu erstellen ):

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)

Geben Sie hier die Bildbeschreibung ein

Obwohl das ist nur „für die Looks“ mehr Funktionen im Zusammenhang mit Funktionsmodellen und Einpassen (zum Beispiel scipy.interpolate.interp2d, scipy.interpolate.griddatazeigt auch Beispiele unter Verwendung np.mgrid) in Scipy usw. erfordern Gitter. Die meisten davon arbeiten mit offenen und dichten Gittern, einige arbeiten jedoch nur mit einem von ihnen.

MSeifert
quelle
Ich möchte mich nur ganz herzlich für diese äußerst detaillierte Antwort bedanken. Das machte meinen Tag.
Jlanger
Was für eine schöne Art, eine Frage zu beantworten ... so detailliert. Vielen Dank
Bipin
h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)- Sollte der erste Bereich nicht mit 2 und der zweite mit 3 multipliziert werden, da er 2 km horizontal und 3 km vertikal ist?
Nixt
@Nixt Leider ist es nicht so einfach. Möglicherweise muss ich diesen Teil der Antwort noch einmal überprüfen. Es ist ein Kompromiss zwischen der transponierten Anzeige der Matrix und der umgekehrten Indizierung - normalerweise erwarten Sie, dass der erste Index horizontal und der zweite vertikal ist, aber dann wird die Anzeige transponiert. Dies ist jedoch meistens ein Detail, das hoffentlich nicht das Wesentliche der Antwort ungültig macht, die den Grund für Gitter veranschaulichen soll. Aber ich werde versuchen, dies zu einem späteren Zeitpunkt zu überarbeiten.
MSeifert
36

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? Da np.meshgridkommt rein:

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 Handlung würde aussehen wie:

import matplotlib.pyplot as plt
plt.imshow(z, origin='lower', interpolation='none')
plt.show()

Geben Sie hier die Bildbeschreibung ein

Ist np.meshgridalso nur eine Annehmlichkeit. Im Prinzip könnte das Gleiche getan werden 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 Dimensionen bewusst sein (nehmen wir an, Sie haben mehr als zwei ...) und der richtigen Sendung. np.meshgriderledigt das alles für dich.

Mit meshgrid können Sie auch Koordinaten zusammen mit den Daten löschen, wenn Sie beispielsweise eine Interpolation durchführen möchten, aber 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 geben xund yzu einer Interpolationsfunktion wie scipy.interpolate.interp2dso dass Sie einen Weg , müssen zu 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 Meshgrid und Sie werden viel zusätzlichen Code haben):

from scipy.interpolate import interp2d
interpolated = interp2d(x_new, y_new, z_new)

Mit dem ursprünglichen Netzgitter können Sie die Interpolation für das ursprüngliche Gitter erneut abrufen:

interpolated_grid = interpolated(xx[0], yy[:, 0]).reshape(xx.shape)

Dies sind nur einige Beispiele, bei denen ich das verwendet habe, meshgridda es möglicherweise noch viel mehr gibt.

MSeifert
quelle
1
Vielen Dank für Ihre Antwort! Der verwirrende Moment für mich Werte zurückgegeben xx, yy. Es war schwer zu verstehen, was sie sind und warum wir sie zur Berechnung der Funktion verwenden. Scheint, ich habe es verstanden. Wir wollen einige Funktionen basierend auf Koordinaten berechnen. Wir können so etwas schreiben: for x=1:10: for y=1:10: z[x,y]=sin(x)+sin(y)Stattdessen berechnen wir zanders z=sin([x,x,...,x]) + sin([y,y,..y]). Korrigiere mich, wenn ich falsch liege!
Alena Kastsiukavets
Es ist nicht 100% korrekter Pseudocode, aber ich hoffe, Sie sehen meinen Standpunkt)
Alena Kastsiukavets
Eigentlich brauchst du immer die Doppelschleife (deinen ersten Code). Es gibt jedoch verschiedene Möglichkeiten, dies zu erreichen numpy: Meshgrid oder Broadcasting. Wenn Sie keine Punkte verwerfen (siehe letzter Teil meiner Antwort), sind beide tatsächlich funktional gleichwertig. Broadcasting ist nur eine implizite Schleife über die zu sendende Dimension. Beachten Sie, dass ich zusätzliche Dimensionen verwendet [:,None]und [None, :]eingefügt habe, damit das Ergebnis korrekt übertragen wird. Ihr zweites Beispiel ist eher wie sin([[y],[y],..[y]])
folgt
Eine wirklich schöne Illustration. Vielen Dank, dass Sie sich so viel Mühe gegeben haben.
Natersoz
interpolated_grid = interpolated(xx, yy)- das funktioniert bei mir nicht, Fehler:x and y should both be 1-D arrays
Nixt
4

Meshgrid hilft beim Erstellen eines rechteckigen Gitters aus zwei 1-D-Arrays aller Punktpaare aus den beiden 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 Punktkombinationen aus den Arrays 'x' und 'y' anwenden möchten, können Sie dies tun:

f(*np.meshgrid(x, y))

Wenn Ihre Funktion nur das Produkt aus zwei Elementen erzeugt, kann auf diese Weise ein kartesisches Produkt effizient für große Arrays erzielt werden.

Von hier verwiesen

Narasimhan
quelle
1

Die Grundidee

Angesichts möglicher Werte x, xs, (man denke an die sie als zeckenMarkierungen auf der X-Achse eines Diagramms) und möglichen y Werte ys, meshgriderzeugt die entsprechende Menge von (x, y) Gitterpunkte --- analog set((x, y) for x in xs for y in yx). Wenn zum Beispiel xs=[1,2,3]und ys=[4,5,6], würden wir den Satz von Koordinaten erhalten {(1,4), (2,4), (3,4), (1,5), (2,5), (3,5), (1,6), (2,6), (3,6)}.

Form des Rückgabewerts

Die zurückgegebene Darstellung meshgridunterscheidet sich jedoch in zweierlei Hinsicht vom obigen Ausdruck:

Zuerst , um meshgriddie Gitterpunkte in einem 2D - Array aus legt: Reihen an unterschiedlichen y-Werten entsprechen, entsprechen Spalten verschiedene x-Werten --- wie in list(list((x, y) for x in xs) for y in ys), der der folgende Array geben würde:

   [[(1,4), (2,4), (3,4)],
    [(1,5), (2,5), (3,5)],
    [(1,6), (2,6), (3,6)]]

Zweitens werden meshgriddie x- und y-Koordinaten getrennt zurückgegeben (dh in zwei verschiedenen numpy 2d-Arrays):

   xcoords, ycoords = (
       array([[1, 2, 3],
              [1, 2, 3],
              [1, 2, 3]]),
       array([[4, 4, 4],
              [5, 5, 5],
              [6, 6, 6]]))
   # same thing using np.meshgrid:
   xcoords, ycoords = np.meshgrid([1,2,3], [4,5,6])
   # same thing without meshgrid:
   xcoords = np.array([xs] * len(ys)
   ycoords = np.array([ys] * len(xs)).T

Beachten Sie, dass np.meshgridauch Gitter für höhere Dimensionen generiert werden können. Bei xs, ys und zs erhalten Sie xcoords, ycoords, zcoords als 3D-Arrays zurück. meshgridunterstützt auch die umgekehrte Reihenfolge der Dimensionen sowie die spärliche Darstellung des Ergebnisses.

Anwendungen

Warum sollten wir diese Form der Ausgabe wollen?

Wenden Sie an jedem Punkt eines Rasters eine Funktion an: Eine Motivation ist, dass binäre Operatoren wie (+, -, *, /, **) für numpy-Arrays als elementweise Operationen überladen werden. Das heißt, wenn ich eine Funktion habe def f(x, y): return (x - y) ** 2, die auf zwei Skalaren funktioniert , kann ich sie auch auf zwei Numpy-Arrays anwenden, um ein Array mit elementweisen Ergebnissen zu erhalten: z. B. f(xcoords, ycoords)oder f(*np.meshgrid(xs, ys))gibt im obigen Beispiel Folgendes an:

array([[ 9,  4,  1],
       [16,  9,  4],
       [25, 16,  9]])

Höherdimensionales Außenprodukt: Ich bin mir nicht sicher, wie effizient dies ist, aber Sie können hochdimensionale Außenprodukte auf diese Weise erhalten : np.prod(np.meshgrid([1,2,3], [1,2], [1,2,3,4]), axis=0).

Konturdiagramme in matplotlib: Ich habe dies meshgridbei der Untersuchung von Konturplots mit matplotlib Zeichnung für Grenzen Entscheidung Plotten . Dazu generieren Sie ein Raster mit meshgrid, werten die Funktion an jedem Rasterpunkt aus (z. B. wie oben gezeigt) und übergeben dann die x-, y- und berechneten f-Werte (dh zcoords) an die Konturfunktion.

user3780389
quelle