Python / NumPy中meshgrid的目的是什么?

时间:2016-03-15 13:43:44

标签: python numpy multidimensional-array mesh numpy-ndarray

有人可以向我解释一下Numpy中meshgrid功能的用途是什么?我知道它会为绘图创建某种坐标网格,但我无法真正看到它的直接好处。

我正在学习Sebastian Raschka的“Python机器学习”,他正在使用它来绘制决策边界。请参阅输入11 here

我也从官方文档中尝试过这段代码,但是,输出对我来说并没有多大意义。

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)

如果可能的话,请向我展示很多现实世界的例子。

6 个答案:

答案 0 :(得分:277)

meshgrid的目的是用x值数组和y值数组创建一个矩形网格。

因此,例如,如果我们想要创建一个网格,我们在x和y方向上的每个整数值都在0到4之间。要创建矩形网格,我们需要xy点的每个组合。

这将是25分,对吧?因此,如果我们想为所有这些点创建一个x和y数组,我们可以执行以下操作。

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

这会产生以下xy矩阵,这样每个矩阵中相应元素的配对就会给出网格中某点的x和y坐标。

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

然后我们可以绘制这些图来验证它们是网格:

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

enter image description here

显然,这对于大范围的xy来说非常繁琐。相反,meshgrid实际上可以为我们生成此内容:我们必须指定的是唯一的xy值。

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

现在,当我们调用meshgrid时,我们会自动获得上一个输出。

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

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

enter image description here

创建这些矩形网格对于许多任务都很有用。在您在帖子中提供的示例中,它只是一种在sin(x**2 + y**2) / (x**2 + y**2)x的值范围内对函数(y)进行抽样的方法。

由于此功能已在矩形网格上采样,因此该功能现在可以显示为"图像"。

enter image description here

此外,结果现在可以传递给期望矩形网格上的数据的函数(即contourf

答案 1 :(得分:161)

由微软凯越提供:

enter image description here

答案 2 :(得分:33)

假设你有一个功能:

def sinus2d(x, y):
    return np.sin(x) + np.sin(y)
例如,你希望在0到2 * pi的范围内看到它的样子。你会怎么做? 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

这样的情节看起来像:

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

enter image description here

所以np.meshgrid只是一种便利。原则上可以通过以下方式完成:

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

但是你需要注意你的尺寸(假设你有两个......)和正确的广播。 np.meshgrid为您完成所有这些。

如果您想要进行插值但排除某些值,则meshgrid还允许您将坐标与数据一起删除:

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

那你现在怎么做插值?您可以将xy提供给scipy.interpolate.interp2d这样的插值函数,这样您就可以知道删除了哪些坐标:

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

然后您仍然可以使用“正确”坐标进行插值(在没有meshgrid的情况下尝试它,您将获得大量额外代码):

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

并且原始的meshgrid允许您再次在原始网格上进行插值:

interpolated_grid = interpolated(xx, yy)

这些只是我使用meshgrid的一些例子,可能会有更多。

答案 3 :(得分:24)

实际上文档中已经提到了np.meshgrid的目的:

  

np.meshgrid

     

从坐标向量返回坐标矩阵。

     

在给定一维坐标数组x1,x2,...,xn的情况下,为N-D网格上的N-D标量/矢量场的矢量化评估制作N-D坐标数组。

因此,它的主要目的是创建一个坐标矩阵。

你可能只是问自己:

为什么我们需要创建坐标矩阵?

您需要使用Python / NumPy的坐标矩阵的原因是,从坐标到值没有直接关系,除非您的坐标从零开始并且是纯正整数。然后你可以使用数组的索引作为索引。 但是,如果情况并非如此,那么您需要在数据旁边存储坐标。这就是网格进来的地方。

假设您的数据是:

1  2  1
2  5  2
1  2  1

但是,每个值代表水平2公里宽的区域和垂直3公里。假设您的原点位于左上角,并且您需要表示可以使用的距离的数组:

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

其中v是:

0  2  4
0  2  4
0  2  4

和h:

0  0  0
3  3  3
6  6  6

因此,如果您有两个索引,请说xy(这就是meshgrid的返回值通常为xx的原因或者xs而不是x在这种情况下,我选择h水平!)然后你可以获得点的x坐标,点的y坐标和该点的值使用:

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

这样可以更容易地跟踪坐标(更重要的是),您可以将它们传递给需要知道坐标的函数。

稍长的解释

但是,np.meshgrid本身并不经常直接使用,大多数人只使用类似对象np.mgridnp.ogrid中的一个。 此处np.mgrid代表sparse=Falsenp.ogrid sparse=True案例(我引用sparse的{​​{1}}参数)。请注意,两者之间存在显着差异 np.meshgridnp.meshgrid以及np.ogrid:前两个返回值(如果有两个或更多)被反转。通常情况并不重要,但您应根据具体情况提供有意义的变量名称。

例如,对于2D网格和np.mgrid,将matplotlib.pyplot.imshow np.meshgrid和第二个x的第一个返回项命名为#{1}}是有意义的39; S 反过来ynp.mgrid

np.ogrid和稀疏网格

np.ogrid

如前所述,与>>> 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]]) 相比,输出相反,这就是为什么我将其解压缩为np.meshgrid而不是yy, xx的原因:

xx, yy

这看起来像坐标,特别是2D图的x和y线。

可视化:

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

enter image description here

np.mgrid和密集/充实的网格

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

这同样适用:与>>> 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]])

相比,输出相反
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]]) 不同,这些数组在-5< = xx< = 5;中包含所有 ogridxx坐标。 -5< = yy< = 5网格。

yy

enter image description here

功能

它不仅限于2D,这些函数适用于任意维度(嗯,Python中函数的最大参数数量和NumPy允许的最大维数):

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

即使这些也适用于1D,也有两种(更常见的)1D网格创建功能:

>>> 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. start参数外,它还支持stop参数(甚至表示步骤数的复杂步骤):

step

应用

您特别询问了目的,事实上,如果您需要坐标系,这些网格非常有用。

例如,如果你有一个NumPy函数来计算二维距离:

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

你想知道每个点的距离:

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

如果在密集网格而不是开放网格中传递,则输出将是相同的。 NumPys广播使它成为可能!

让我们看看结果:

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

enter image description here

这也是NumPys 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() mgrid变得非常方便的原因,因为它可以让您轻松更改网格的分辨率:

ogrid

enter image description here

但是,由于ys, xs = np.ogrid[-5:5:200j, -5:5:200j] # otherwise same code as above 不支持imshowx输入,因此必须手动更改刻度。如果能接受yx坐标,对吧?

会非常方便

使用NumPy轻松编写可以自然处理网格的功能。此外,NumPy,SciPy,matplotlib中有几个函数可以让你传入网格。

我喜欢图片,所以让我们探索matplotlib.pyplot.contour

y

enter image description here

注意坐标是如何正确设置的!如果您只是传递了ys, xs = np.mgrid[-5:5:200j, -5:5:200j] density = np.sin(ys)-np.cos(xs) plt.figure() plt.contour(xs, ys, density)

,情况就不会如此

或者使用astropy models给出另一个有趣的示例(这次我不太关心坐标,我只是用它们来创建一些网格):

density

enter image description here

虽然这只是外观"与功能模型和拟合相关的几个函数(例如scipy.interpolate.interp2dscipy.interpolate.griddata甚至在Scipy中使用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) )显示示例等。要求网格。其中大多数使用开放式网格和密集网格,但有些只能与其中一个一起使用。

答案 4 :(得分:1)

基本思想

给出可能的x值xs(将其视为图的x轴上的刻度线)和可能的y值ysmeshgrid生成(x,y)网格点的对应集合-与set((x, y) for x in xs for y in yx)类似。例如,如果xs=[1,2,3]ys=[4,5,6],我们将得到一组坐标{(1,4), (2,4), (3,4), (1,5), (2,5), (3,5), (1,6), (2,6), (3,6)}

返回值的形式

但是,meshgrid返回的表示形式与上述表达式在两个方面有所不同:

First meshgrid在2d数组中布置网格点:行对应于不同的y值,列对应于不同的x值-如{{1 }},它将提供以下数组:

list(list((x, y) for x in xs) for y in ys)

第二 [[(1,4), (2,4), (3,4)], [(1,5), (2,5), (3,5)], [(1,6), (2,6), (3,6)]] 分别返回x和y坐标(即在两个不同的numpy 2d数组中):

meshgrid

请注意, 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 也可以生成更大尺寸的网格。给定xs,ys和zs,您将把xcoords,ycoords,zcoords作为3d数组取回来。 np.meshgrid还支持维度的逆序以及结果的稀疏表示。

应用程序

我们为什么要这种形式的输出?

在网格上的每个点应用一个函数: 一种动机是像(+,-,*,/,**)这样的二进制运算符对于numpy数组作为元素操作进行了重载。这意味着,如果我有一个可以在两个标量上使用的函数meshgrid,我还可以将其应用于两个numpy数组,以获得一个按元素排列的结果数组: def f(x, y): return (x - y) ** 2f(xcoords, ycoords)在以上示例中给出了以下内容:

f(*np.meshgrid(xs, ys))

高维外部产品:我不确定这有多有效,但是您可以通过以下方式获得高维外部产品:array([[ 9, 4, 1], [16, 9, 4], [25, 16, 9]])

matplotlib中的轮廓图:在调查drawing contour plots with matplotlib中的plotting decision boundaries时遇到了np.prod(np.meshgrid([1,2,3], [1,2], [1,2,3,4]), axis=0)。为此,您使用meshgrid生成一个网格,在每个网格点上评估函数(例如,如上所示),然后将xcoords,ycoords和计算出的f值(即zcoords)传递给contourf函数。

答案 5 :(得分:1)

简短答案

meshgrid的目的是通过C NumPy库中的矢量化操作来帮助remplace Python loops(缓慢的解释代码)。

this site借来的。

enter image description here

x = np.arange(-4, 4, 0.25)
y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

meshgrid用于创建在-4和+4之间的坐标对,在X和Y的每个方向上的增量为.25。然后,每对坐标用于从中找到R和Z。这种准备坐标“网格”的方法经常用于绘制3D曲面或为2D曲面着色。


详细信息:Python for循环与NumPy向量操作

举一个更简单的例子,假设我们有两个值序列,

a = [2,7,9,20]    
b = [1,6,7,9]    ​

,我们想对每个可能的值对执行一个操作,一个取自第一个列表,一个取自第二个列表。我们还想存储结果。例如,假设我们要获取每个可能对的值的总和。

缓慢而费力的方法

c = []    
for i in range(len(b)):    
    row = []    
    for j in range(len(a)):    
        row.append (a[j] + b[i])
    c.append (row)    
print (c)

结果:

[[3, 8, 10, 21],
 [8, 13, 15, 26],
 [9, 14, 16, 27],
 [11, 16, 18, 29]]

解释了Python,这些循环执行起来相对较慢。

快速简便的方法

meshgrid旨在从代码中删除循环。它返回两个数组(下面的i和j),可以将它们组合起来以扫描所有现有的对:

i,j = np.meshgrid (a,b)    
c = i + j    
print (c)

结果:

[[ 3  8 10 21]
 [ 8 13 15 26]
 [ 9 14 16 27]
 [11 16 18 29]]

引擎盖下的网格

meshgrid准备的两个数组是:

(array([[ 2,  7,  9, 20],
        [ 2,  7,  9, 20],
        [ 2,  7,  9, 20],
        [ 2,  7,  9, 20]]),

 array([[1, 1, 1, 1],
        [6, 6, 6, 6],
        [7, 7, 7, 7],
        [9, 9, 9, 9]]))

这些数组是通过重复提供的值来创建的。一个包含相同行中的值,另一个包含相同列中的其他值。行数和列数由另一个序列中的元素数确定。

因此,meshgrid创建的两个数组在形状上可用于矢量运算。想象一下页面顶部代码中的x和y序列具有不同数量的元素,无论如何,得到的X和Y数组都是形状兼容的,不需要任何broadcast

来源

与其他许多from MATLAB函数一样,

numpy.meshgrid来自NumPy。因此,您还可以研究MATLAB中的示例,以查看正在使用的meshgrid,用于3D绘图的代码看起来the same in MATLAB