【问题标题】:What is the purpose of meshgrid in Python / NumPy?Python / NumPy中meshgrid的目的是什么?
【发布时间】:2016-06-30 23:57:09
【问题描述】:

有人可以向我解释一下 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)

如果可能的话,请给我展示很多真实的例子。

【问题讨论】:

  • 注意如果x = np.arange(n)y = np.arange(m),可以直接用np.indices((m, n))代替np.stack(np.meshgrid(x, y, indexing="ij"))

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


【解决方案1】:

大多数时候你只需要list(zip(X,Y)) 其中X = np.linspace(x)Y = np.linspace(y)

【讨论】:

    【解决方案2】:

    简答

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

    借自this site

    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 方向上以 0.25 为增量。然后使用每对坐标从中找到 R 和 Z。这种准备“网格”坐标的方法经常用于绘制 3D 表面或为 2D 表面着色。


    详情:Python for 循环 vs 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

    起源

    numpy.meshgridfrom MATLAB 一样,与许多其他 NumPy 函数一样。因此,您也可以研究 MATLAB 中的示例以查看使用中的 meshgrid,3D 绘图的代码看起来像 the same in MATLAB

    【讨论】:

    • 我对这种向量化计算的 matlab/numpy 方式很陌生。我来这里是因为我想知道表演。在较低级别的编程语言(如 C)中,您永远不会浪费时间和内存来分配和填充 ij 数组,只是为了再次读取它们以准备结果 c。关于 python 是否使用策略来优化它的任何信息?换种方式问:ij 数组真的占用物理内存吗?更极端:表达式np.sqrt(i*i + j*j) 是否分配了另外两个额外的临时数组,从/向 RAM 读取和写入临时数组?
    • @fieres。我不是专家,但我知道 NumPy 使用巧妙的数组内部描述来优化操作,特别是防止无用的重复(查找“数组步幅”和“稀疏矩阵”)。数组上的常用函数已重新实现到数组类(如ufunc)中,以利用许多数组优化。 Some info.
    • 我查看了文档。据我了解,ufunc 不会使用延迟评估或结果对象来优化计算。所以你需要大量的内存。但是,您可以通过不使用 pyton 运算符 (* / - +) 而是使用显式函数 (np.multiply 等) 并传递可选的 out 参数来手动优化内存使用。
    【解决方案3】:

    其实np.meshgrid的用途在文档中已经提到了:

    np.meshgrid

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

    在给定一维坐标数组 x1、x2、...、xn 的情况下,为 N 维网格上的 N 维标量/向量场的矢量化评估创建 N 维坐标数组。

    所以它的主要目的是创建一个坐标矩阵。

    您可能只是问自己:

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

    您需要 Python/NumPy 坐标矩阵的原因是坐标与值之间没有直接关系,除非您的坐标从零开始并且是纯正整数。然后你可以只使用数组的索引作为索引。 但是,如果不是这种情况,您需要以某种方式将坐标与数据一起存储。这就是网格的用武之地。

    假设您的数据是:

    1  2  1
    2  5  2
    1  2  1
    

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

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

    v 在哪里:

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

    和h:

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

    所以如果你有两个索引,比如说xy(这就是为什么meshgrid 的返回值通常是xxxs 而不是x 在这种情况下我选择了@987654354 @ 表示水平!)然后您可以使用以下方法获取该点的 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.ogridsparse=True的情况(我指的是np.meshgridsparse参数)。请注意,两者之间存在显着差异 np.meshgridnp.ogridnp.mgrid:前两个返回值(如果有两个或更多)颠倒。通常这无关紧要,但您应该根据上下文给出有意义的变量名称。

    例如,在二维网格和matplotlib.pyplot.imshow 的情况下,将第一个返回的项目命名为np.meshgrid x 和第二个返回的项目y 是有意义的,而它是 np.mgridnp.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

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

    这已经看起来像坐标了,特别是二维绘图的 x 和 y 线。

    可视化:

    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 和密集/充实的网格

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

    ogrid 不同,这些数组包含所有 xxyy 在-5

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

    功能

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

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

    即使这些也适用于一维,也有两个(更常见的)一维网格创建函数:

    除了startstop 参数,它还支持step 参数(甚至是表示步数的复杂步骤):

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

    应用程序

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

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

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

    而你想知道每个点的距离:

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

    如果通过密集网格而不是开放网格,输出将是相同的。 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()
    

    这也是 NumPys mgridogrid 变得非常方便的时候,因为它允许您轻松更改网格的分辨率:

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

    但是,由于imshow 不支持xy 输入,因此必须手动更改刻度。如果它接受xy 坐标,那真的很方便,对吧?

    使用 NumPy 编写自然处理网格的函数很容易。此外,在 NumPy、SciPy、matplotlib 中有几个函数希望你在网格中传递。

    我喜欢图片,所以让我们探索一下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)
    

    注意坐标是如何正确设置的!如果您只是传入density,则情况并非如此。

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

    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)
        
    

    虽然这只是“外观”,但与功能模型和拟合相关的几个功能(例如scipy.interpolate.interp2dscipy.interpolate.griddata 甚至显示在 Scipy 等中使用 np.mgrid) 的示例需要网格。其中大多数适用于开放网格和密集网格,但有些仅适用于其中一种。

    【讨论】:

    • 我只想对这个非常详细的答案表示非常感谢。这让我很开心。
    • 回答问题的方式多么美妙……如此详细。谢谢
    • h, v = np.meshgrid(np.arange(3)*3, np.arange(3)*2) - 因为它的水平2公里和垂直3公里,第一个范围不应该乘以2,第二个范围不应该乘以3吗?
    • @Nixt 不幸的是,事情没有那么简单。我可能不得不再次检查答案的那部分。这是矩阵的转置显示和反向索引之间的权衡 - 通常您希望第一个索引是水平的,第二个是垂直的,但随后显示会被转置。然而,这主要是一个细节,希望不会使旨在说明网格原因的答案的本质无效。但我会在以后尝试修改它。
    • @MSeifert 我实际上发现numpy 的文档简洁得令人沮丧。当我第一次阅读meshgrid 时,我问自己“坐标矩阵到底是什么?”对于外行来说,这没有任何意义。不过,您的解释很有道理。我希望numpy 文档以“愚蠢”的解释开始,然后转向更具技术性的解释。我知道数学的目标是尽可能明确,numpy 很好地遵循了这一点,但它是以理解为代价的,而且感觉完全不是 Python 的。
    【解决方案4】:

    假设你有一个函数:

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

    所以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]
    

    然后您仍然可以使用“正确”坐标进行插值(尝试不使用网格网格,您将获得大量额外代码):

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

    原来的meshgrid可以让你再次在原来的网格上得到插值:

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

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

    【讨论】:

    • 感谢您的回答!对我来说最令人困惑的时刻是返回值xxyy。很难理解它们是什么以及我们为什么使用它们来计算函数。看来,我明白了。我们想根据坐标计算一些函数。我们可以这样写:for x=1:10: for y=1:10: z[x,y]=sin(x)+sin(y) 相反,我们以不同的方式计算z z=sin([x,x,...,x]) + sin([y,y,..y])。如果我错了,请纠正我!
    • 这不是 100% 正确的伪代码,但我希望你能明白我的意思)
    • 实际上你总是需要双循环(你的第一个代码)。但是有不同的方法可以使用numpy 归档它:meshgrid 或广播。如果您不丢弃积分(请参阅我的答案的最后一部分),两者实际上在功能上是等效的。广播只是跨越待广播维度的隐式循环。请注意,我使用了[:,None][None, :] 来包含额外的维度,以便正确广播结果。你的第二个例子更像是:sin([[y],[y],..[y]])
    • 一个非常好的插图。感谢您付出如此多的努力。
    • interpolated_grid = interpolated(xx, yy) - 这对我不起作用,错误:x and y should both be 1-D arrays
    【解决方案5】:

    基本思路

    给定可能的 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 返回的表示与上述表达式有两点不同:

    首先meshgrid 在二维数组中布置网格点:行对应不同的 y 值,列对应不同的 x 值——如 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)]]
    

    第二meshgrid 分别返回 x 和 y 坐标(即在两个不同的 numpy 2d 数组中):

       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
    

    注意,np.meshgrid 也可以生成更高维度的网格。给定 xs、ys 和 zs,您将返回 xcoords、ycoords、zcoords 作为 3d 数组。 meshgrid 还支持维度的逆序以及结果的稀疏表示。

    应用程序

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

    在网格的每个点上应用一个函数: 一个动机是像 (+, -, *, /, **) 这样的二元运算符被重载为 numpy 数组作为元素操作。这意味着如果我有一个适用于两个标量的函数 def f(x, y): return (x - y) ** 2,我也可以将它应用于两个 numpy 数组以获得元素结果数组:例如f(xcoords, ycoords)f(*np.meshgrid(xs, ys)) 在上述示例中给出以下内容:

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

    高维外积:我不确定这有多有效,但你可以通过这种方式获得高维外积:np.prod(np.meshgrid([1,2,3], [1,2], [1,2,3,4]), axis=0)

    matplotlib 中的等高线图: 我在调查 drawing contour plots with matplotlibplotting decision boundaries 时遇到了 meshgrid。为此,您使用meshgrid 生成一个网格,在每个网格点评估函数(例如,如上所示),然后将 xcoords、ycoords 和计算的 f 值(即 zcoords)传递给 contourf 函数。

    【讨论】:

    • 由于某种原因,numpy 中 nd 外积的上述表达式导致形状为 (2, 3, 4) 而不是 (3, 2, 4)。这个 pytorch 版本给出了正确的形状:torch.stack(torch.meshgrid(*map(torch.tensor, [[1,2,3], [1,2], [1,2,3,4]]))).prod(0)
    【解决方案6】:

    由 Microsoft Excel 提供:

    【讨论】:

    • 不错。 Fwiw,如果您想要中间的 2 x 12 数组对:XYpairs = np.vstack([ XX.reshape(-1), YY.reshape(-1) ])
    • 如果你想要一个 12 x 2 的中间对数组:XYpairs = np.dstack([XX, YY]).reshape(-1, 2)
    • 不错的答案。 meshgrid 的目的是利用每个dim的坐标创建一个网格。
    • 我觉得有点奇怪的是 x 和 y 值是分开返回的,而不是已经合并到一个数组中。如果我希望它们在一个数组中,我需要这样做:np.vstack([XX.ravel(), YY.ravel()]).T
    • 感谢使用 7 6 5 而不是 0 1 2 3 4
    【解决方案7】:

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

    显然,这变得非常乏味,尤其是对于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')
    

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

    由于此函数已在矩形网格上进行采样,因此该函数现在可以可视化为“图像”。

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

    【讨论】:

    • 你还没有解释返回值xxyy。对我来说神秘的部分是为什么它会返回这对结果,以及它们的样子。海潘的回答很方便。我想这样做是为了方便,因为 plot 需要两个这样的参数。
    • 我不知道——这就是我查找这些信息的原因;)所以我并不是说它应该返回不同的东西。我只是为那些刚刚阅读已接受答案的人提供我对缺失信息的最佳猜测。如果您愿意,我建议您的答案(已经非常好 - 谢谢!)如果您解释返回值(就像 Hai 所做的那样),对于我们这些仍然感到困惑的人来说,会更加完整。
    • 为了更好地理解 xx 和 yy 的值,请考虑以下代码得到与 np.meshgrid 相同的结果的说法:xx = [xvalues for y in yvalues]yy = [[y for x in xvalues] for y in yvalues]
    • 这个答案令人困惑——你对xy 的第一个插图不是倒过来的吗?当您执行xx, yy = np.meshgrid(np.arange(4), np.arange(4)) 时,它与答案第一部分中的xy 正好相反。它匹配mgrid 的输出顺序,但不匹配meshgrid。 xx 应该在 x 方向上增加,但你的在 y 方向上增加。
    • @ScottStaniewicz 感谢您指出我们的,现在确定我是如何搞砸的...更新了!
    【解决方案8】:

    meshgrid 有助于从两个数组中所有点对的两个一维数组创建一个矩形网格。

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

    现在,如果您已经定义了一个函数 f(x,y),并且您想将该函数应用于数组“x”和“y”中所有可能的点组合,那么您可以这样做:

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

    说,如果您的函数只产生两个元素的乘积,那么这就是可以实现笛卡尔积的方式,对于大型数组来说是有效的。

    转自here

    【讨论】:

      猜你喜欢
      • 2020-12-04
      • 1970-01-01
      • 2018-10-21
      • 1970-01-01
      • 2013-08-14
      • 2017-04-17
      • 2012-09-26
      • 1970-01-01
      相关资源
      最近更新 更多