it-swarm.com.de

Was ist der Zweck von meshgrid in Python/NumPy?

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.

181
HonzaB

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

 enter image description here

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

 enter image description here

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.

 enter image description here

Außerdem kann das Ergebnis jetzt an Funktionen übergeben werden, die Daten im Rechteckraster erwarten (d. H. contourf).

250
Suever

Mit freundlicher Genehmigung von Microsoft Excelle:

enter image description here

136
Hai Phan

Tatsächlich ist der Zweck von np.meshgrid Bereits in der Dokumentation erwähnt:

np.meshgrid

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:

Warum müssen wir Koordinatenmatrizen erstellen?

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.

Eine etwas längere Erklärung

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

enter image description here

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

enter image description here

Funktionalität

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

Anwendungen

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

enter image description here

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

enter image description here

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)

enter image description here

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)

enter image description here

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.

30
MSeifert

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

 enter image description here

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.

30
MSeifert

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

0
Narasimhan