meshgrid python numpy multidimensional-array mesh numpy-ndarray

¿Cuál es el propósito de meshgrid en Python/NumPy?



numpy meshgrid (5)

¿Alguien puede explicarme cuál es el propósito de la función meshgrid en Numpy? Sé que crea algún tipo de cuadrícula de coordenadas para trazar, pero realmente no puedo ver el beneficio directo de ello.

Estoy estudiando "Python Machine Learning" de Sebastian Raschka, y él lo está usando para trazar los límites de decisión. Vea la entrada 11 here .

También probé este código de la documentación oficial, pero, una vez más, el resultado realmente no tiene sentido para mí.

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)

Por favor, si es posible, muéstrame muchos ejemplos del mundo real.


Cortesía de Microsoft Excel:


El propósito de meshgrid es crear una cuadrícula rectangular a partir de una matriz de valores xy una matriz de valores y.

Entonces, por ejemplo, si queremos crear una cuadrícula donde tengamos un punto en cada valor entero entre 0 y 4 en las direcciones x e y. Para crear una cuadrícula rectangular, necesitamos todas las combinaciones de los puntos x e y .

Esto va a ser 25 puntos, ¿verdad? Entonces, si quisiéramos crear una matriz x e y para todos estos puntos, podríamos hacer lo siguiente.

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

Esto daría como resultado las siguientes matrices x e y , de modo que el emparejamiento del elemento correspondiente en cada matriz da las coordenadas x e y de un punto en la cuadrícula.

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

Luego podemos trazar estos para verificar que son una cuadrícula:

plt.plot(x,y, marker=''.'', color=''k'', linestyle=''none'')

Obviamente, esto se vuelve muy tedioso, especialmente para grandes rangos de x e y . En cambio, meshgrid puede generar esto para nosotros: todo lo que tenemos que especificar son los valores únicos de x e y .

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

Ahora, cuando llamamos meshgrid , obtenemos la salida anterior automáticamente.

xx, yy = np.meshgrid(xvalues, yvalues) plt.plot(xx, yy, marker=''.'', color=''k'', linestyle=''none'')

La creación de estas cuadrículas rectangulares es útil para una serie de tareas. En el ejemplo que ha proporcionado en su publicación, es simplemente una forma de muestrear una función ( sin(x**2 + y**2) / (x**2 + y**2) ) en un rango de valores para x e y .

Debido a que esta función se ha muestreado en una cuadrícula rectangular, ahora se puede visualizar como una "imagen".

Además, el resultado ahora se puede pasar a funciones que esperan datos en una cuadrícula rectangular (es decir, contourf )


En realidad, el propósito de np.meshgrid ya se menciona en la documentación:

np.meshgrid

Devuelve matrices de coordenadas de vectores de coordenadas.

Realice matrices de coordenadas ND para evaluaciones vectorizadas de campos escalares / vectoriales ND sobre cuadrículas ND, dados los conjuntos de coordenadas unidimensionales x1, x2, ..., xn.

Por lo tanto, su objetivo principal es crear matrices de coordenadas.

Probablemente te hayas preguntado a ti mismo:

¿Por qué necesitamos crear matrices de coordenadas?

La razón por la que necesita matrices de coordenadas con Python / NumPy es que no hay una relación directa de coordenadas a valores, excepto cuando sus coordenadas comienzan con cero y son enteros puramente positivos. Entonces puede usar los índices de una matriz como índice. Sin embargo, cuando ese no es el caso, de alguna manera necesita almacenar coordenadas junto con sus datos. Ahí es donde entran las cuadrículas.

Supongamos que sus datos son:

1 2 1 2 5 2 1 2 1

Sin embargo, cada valor representa una región de 2 kilómetros de ancho horizontalmente y 3 kilómetros verticalmente. Suponga que su origen es la esquina superior izquierda y desea matrices que representen la distancia que podría usar:

import numpy as np h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2)

donde v es:

0 2 4 0 2 4 0 2 4

y h:

0 0 0 3 3 3 6 6 6

Entonces, si tiene dos índices, digamos x e y (es por eso que el valor de retorno de meshgrid generalmente es xx o xs lugar de x en este caso, ¡elegí h horizontalmente!), Entonces puede obtener la coordenada x del punto, el coordenada y del punto y el valor en ese punto usando:

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

Eso hace que sea mucho más fácil hacer un seguimiento de las coordenadas y (aún más importante) puede pasarlas a funciones que necesitan conocer las coordenadas.

Una explicación un poco más larga.

Sin embargo, np.meshgrid sí no se usa directamente, generalmente uno solo usa uno de los objetos similares np.mgrid o np.ogrid . Aquí np.mgrid representa sparse=False y np.ogrid el caso sparse=True (me refiero al argumento sparse de np.meshgrid ). Tenga en cuenta que existe una diferencia significativa entre np.meshgrid y np.ogrid y np.mgrid : los dos primeros valores devueltos (si hay dos o más) se invierten. A menudo, esto no importa, pero debe dar nombres de variables significativos según el contexto.

Por ejemplo, en el caso de una cuadrícula 2D y matplotlib.pyplot.imshow , tiene sentido nombrar el primer elemento devuelto de np.meshgrid x y el segundo y mientras que es al revés para np.mgrid y np.ogrid .

np.ogrid y rejillas dispersas

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

Como ya se dijo, la salida se invierte en comparación con np.meshgrid , por eso lo desempaqué como yy, xx lugar de 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]])

Esto ya parece coordenadas, específicamente las líneas x e y para gráficos 2D.

Visualizado:

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 y np.mgrid densas / desarrolladas

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

Lo mismo se aplica aquí: la salida se invierte en comparación con 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]])

A diferencia de ogrid estas matrices contienen todas las coordenadas xx e yy en -5 <= xx <= 5; -5 <= aa <= 5 cuadrícula.

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

Funcionalidad

No solo se limita a 2D, estas funciones funcionan para dimensiones arbitrarias (bueno, hay un número máximo de argumentos dados para funcionar en Python y un número máximo de dimensiones que NumPy permite):

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

Incluso si estos también funcionan para 1D, hay dos funciones de creación de cuadrícula 1D (mucho más comunes):

Además del argumento de start y stop , también admite el argumento de step (incluso pasos complejos que representan el número de pasos):

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

Aplicaciones

Usted preguntó específicamente sobre el propósito y, de hecho, estas cuadrículas son extremadamente útiles si necesita un sistema de coordenadas.

Por ejemplo, si tiene una función NumPy que calcula la distancia en dos dimensiones:

def distance_2d(x_point, y_point, x, y): return np.hypot(x-x_point, y-y_point)

Y quieres saber la distancia de cada punto:

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

El resultado sería idéntico si uno pasara en una grilla densa en lugar de una grilla abierta. ¡La transmisión de NumPys lo hace posible!

Visualicemos el resultado:

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

Y esto también es cuando NumPys mgrid y ogrid vuelven muy convenientes porque le permite cambiar fácilmente la resolución de sus cuadrículas:

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

Sin embargo, dado que imshow no admite entradas x e y uno tiene que cambiar los ticks a mano. Sería realmente conveniente si aceptara las coordenadas y , ¿verdad?

Es fácil escribir funciones con NumPy que tratan naturalmente con cuadrículas. Además, hay varias funciones en NumPy, SciPy, matplotlib que esperan que pase en la cuadrícula.

Me gustan las imágenes, así que exploremos 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)

¡Observe cómo las coordenadas ya están configuradas correctamente! Ese no sería el caso si solo pasaras la density .

O para dar otro ejemplo divertido usando modelos de astropía (esta vez no me importan mucho las coordenadas, solo las uso para crear una cuadrícula):

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)

Aunque eso es solo "para el aspecto", varias funciones relacionadas con modelos funcionales y ajuste (por ejemplo, scipy.interpolate.griddata , scipy.interpolate.griddata incluso muestran ejemplos usando np.mgrid ) en Scipy, etc. requieren cuadrículas. La mayoría de estos funcionan con rejillas abiertas y rejillas densas, sin embargo, algunos solo funcionan con uno de ellos.


Supongamos que tiene una función:

def sinus2d(x, y): return np.sin(x) + np.sin(y)

y desea, por ejemplo, ver cómo se ve en el rango de 0 a 2 * pi. ¿Como lo harias? Allí entra 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

y esa trama se vería así:

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

Entonces np.meshgrid es solo una conveniencia. En principio, lo mismo podría hacerse mediante:

z2 = sinus2d(np.linspace(0,2*np.pi,100)[:,None], np.linspace(0,2*np.pi,100)[None,:])

pero allí debe conocer sus dimensiones (suponga que tiene más de dos ...) y la transmisión correcta. np.meshgrid hace todo esto por ti.

También meshgrid le permite eliminar coordenadas junto con los datos si, por ejemplo, desea hacer una interpolación pero excluye ciertos valores:

condition = z>0.6 z_new = z[condition] # This will make your array 1D

Entonces, ¿cómo harías la interpolación ahora? Puede scipy.interpolate.interp2d x e y a una función de interpolación como scipy.interpolate.interp2d por lo que necesita una forma de saber qué coordenadas se eliminaron:

x_new = xx[condition] y_new = yy[condition]

y aún puede interpolar con las coordenadas "correctas" (pruébelo sin la malla y tendrá un montón de código adicional):

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

y el meshgrid original le permite obtener la interpolación en el grid original nuevamente:

interpolated_grid = interpolated(xx, yy)

Estos son solo algunos ejemplos en los que utilicé la meshgrid podría haber muchos más.


meshgrid ayuda a crear una cuadrícula rectangular a partir de dos matrices 1-D de todos los pares de puntos de las dos matrices.

x = np.array([0, 1, 2, 3, 4]) y = np.array([0, 1, 2, 3, 4])

Ahora, si ha definido una función f (x, y) y desea aplicar esta función a todas las combinaciones posibles de puntos de las matrices ''x'' e ''y'', puede hacer esto:

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

Digamos, si su función solo produce el producto de dos elementos, entonces así es como se puede lograr un producto cartesiano, de manera eficiente para matrices grandes.

Referido desde here