【问题标题】:Numpy matrix of coordinates坐标的numpy矩阵
【发布时间】:2026-01-02 05:40:01
【问题描述】:

我正在尝试获取坐标数组矩阵。这与 numpy.meshgrid 不同。例如,对于 2x2 尺寸,我想要 2x2x2 输出

[[[0,0],[0,1]],
 [[1,0],[1,1]]]

作为一个 numpy 数组。这可能看起来和读取更清晰的 2x2 元组矩阵:

[[(0,0),(0,1)],
 [(1,0),(1,1)]]

(除了我认为你不能在 numpy 数组中包含元组,这不是重点)

这个简单的例子可以通过切换 numpy-meshgrid 输出的轴来完成(具体来说,将第一个轴移动到最后一个):

np.array(np.meshgrid([0,1],[0,1])).transpose([1,2,0])

这可以很容易地推广到任意维度,但对于超过 2 个输入,meshgrid 的行为不像我预期的那样。具体来说,返回的矩阵具有沿轴以奇数顺序变化的坐标值:

In [627]: np.meshgrid([0,1],[0,1],[0,1])
Out[627]:
[array([[[0, 0],
        [1, 1]],

       [[0, 0],
        [1, 1]]]),
 array([[[0, 0],
        [0, 0]],

       [[1, 1],
        [1, 1]]]),
 array([[[0, 1],
        [0, 1]],

       [[0, 1],
        [0, 1]]])]

请注意,此输出的元素分别沿轴 1、0 和 2 变化。这将建立一个不正确的坐标矩阵;我需要输出按该顺序沿轴 0、1 和 2 变化。所以我可以做

In [642]: np.array(np.meshgrid([0,1],[0,1],[0,1])).swapaxes(1,2)
Out[642]:
array([[[[0, 0],
         [0, 0]],

        [[1, 1],
         [1, 1]]],


       [[[0, 0],
         [1, 1]],

        [[0, 0],
         [1, 1]]],


       [[[0, 1],
         [0, 1]],

        [[0, 1],
         [0, 1]]]])

但这开始变得非常棘手,我不知道我是否可以在更高维度的网格输出中依靠这个顺序。 numpy.mgrid 给出了正确的顺序,但似乎不允许任意值,这是我需要的。所以这归结为两个问题:

1) 有没有一种更简洁的方法,可能是我缺少的 numpy 中的某些函数,它会生成所描述的坐标向量矩阵? 2)这种奇怪的排序真的是我们对网格网格的期望吗?有没有我可以信赖的规范?

[编辑] 跟进 Jaime 的解决方案,这里有一个更通用的函数,可以为任何感兴趣的人更明确地构建它:[编辑 2,修复了一个错误,可能是另一个错误,不能在这个权利上花费更多时间现在,这确实需要一个更常见的功能...]

def build_coords(*vecs):
    coords = numpy.empty(map(len,vecs)+[len(vecs)])
    for ii in xrange(len(vecs)):
        s = np.hstack((len(vecs[ii]), np.ones(len(vecs)-ii-1)))
        v = vecs[ii].reshape(s)
        coords[...,ii] = v
    return coords

【问题讨论】:

  • 我喜欢做的是保留两个数组:一个用于 x 坐标,另一个用于 y 坐标。然后,您可以通过访问两个数组中具有相同索引的元素来创建坐标对。不确定这是否适合你,但这是我对这些情况的看法。
  • 我喜欢做保罗方法...但是对于我把 x 和 y 压缩在一起的点
  • 在这种情况下,我实际上需要整个矩阵;目标是在指定的坐标网格处评估多元函数。也许解决方案是重写函数以接受 (x, y, z, ...) 值的元组而不是坐标向量矩阵,但是我仍然遇到以正确方向生成这些值的问题,由于某种原因,哪个网格网格似乎不这样做。我真的觉得这是meshgrid中的一个错误,不是吗?

标签: python arrays numpy matrix coordinates


【解决方案1】:

numpy 函数indices 也可用于此效果,其功能从其名称也可以清楚地看出。

>>> import numpy as np
>>> np.indices((2,3))
array([[[0, 0, 0],
        [1, 1, 1]],

       [[0, 1, 2],
        [0, 1, 2]]])

可以认为是一个 2×3 的 y 坐标矩阵和一个 2×3 的 x 坐标矩阵 (y,x = np.indices((2,3)))。它可以通过转置轴重铸成 Jaime 提出的形式:

>>> np.indices((2,3)).transpose((1,2,0))

它在功能上等同于the meshgrid solution,使用indexing='ij',但不需要您提供坐标数组,这在您有多个维度时会很有用。

>>> def f1(shape):
...     return np.array(np.meshgrid(*(np.arange(s) for s in shape), indexing='ij'))
...
>>> shape = (200, 31, 15, 4)
>>> np.all(f1(shape) == np.indices(shape))
True

在时间方面,这些解决方案是相似的,当您考虑到生成 meshgrid 操作的一维数组所需的时间时,但 meshgrid 返回一个(数组)列表,而不是 nd 数组喜欢indices。通过像上面的f1 那样添加对np.array 的额外调用,indicesmeshgrid 具有明显的优势:

In [14]: %timeit f1(shape)
100 loops, best of 3: 14 ms per loop

In [15]: %timeit np.indices(shape)
100 loops, best of 3: 5.77 ms per loop

无需额外调用array

In [16]: def f2(shape):
    return np.meshgrid(*(np.arange(s) for s in shape), indexing='ij')
   .....: 

In [17]: %timeit f2(shape)
100 loops, best of 3: 5.78 ms per loop

不过,请务必小心解释时间安排。这可能不会成为您解决任何问题的瓶颈。

在任何情况下,meshgrid 可以比indices 做更多的事情,例如生成更通用的rectilinear grid 而不是笛卡尔网格,因此请在适当的时候使用它们。在这种情况下,我会使用更具描述性的命名indices

【讨论】:

  • 看起来昨天有人很沮丧,以至于在同一时间段内对这个(还不错的)答案和我的另一个答案投了反对票。太糟糕了,他/她有这样的心态,对体面的答案感到沮丧,没有它,* 会更好。无论如何,对于未来的读者:不要让下面的零分影响你的答案:np.indices 工作并且正是为了这个目标而制作的。
【解决方案2】:

给定一维坐标:

rows = np.arange(2)
cols = np.arange(3)

我希望这样可以解决问题:

np.dstack((rows[:, None, None], cols[:, None]))

但显然dstack之类的需要完全匹配的尺寸,他们不会广播它们,我认为这是一种耻辱。

所以这个替代方案有点长,但显式比隐式好,你总是可以把它全部包装成一个小函数:

>>> coords = np.empty((len(rows), len(cols), 2), dtype=np.intp)
>>> coords[..., 0] = rows[:, None]
>>> coords[..., 1] = cols

>>> coords
array([[[0, 0],
        [0, 1],
        [0, 2]],

       [[1, 0],
        [1, 1],
        [1, 2]]])

【讨论】:

  • 这很棒。我仍然真的希望我的网格单线能够工作!但是对于任何有兴趣的人,[编辑,我猜 cmets 中的代码是不行的],[第二次编辑,我想我也不想点击“回答你的问题”] 我已将其添加到问题描述中
【解决方案3】:

试试np.meshgrid([0, 1], [0, 1], [0, 1], indexing="ij")meshgrid 文档实际上非常明确地说明了默认 indexing="xy" 与非默认 indexing="ij" 相比如何产生有趣的轴排序,因此您可以查看更多详细信息。 (他们不清楚为什么它会这样工作,唉......)

【讨论】:

    【解决方案4】:

    我使用的一种简单方法如下-

    x,y = np.mgrid[-10:10:0.1, -10:10:0.1]
    pos = np.empty(x.shape + (2,))
    pos[:, :, 0] = x; pos[:, :, 1] = y
    pos = np.reshape(pos, (x.shape[0]*x.shape[1], 2))
    

    pos 是所需的坐标数组。

    【讨论】:

      【解决方案5】:

      最初的问题是六年前发布的,但我发现自己反复寻找解决这个问题的好方法,并多次来到这里。通过查看 Numpy 文档,我最近整理了一种用于生成 n 维坐标的直观且动态的方法,并希望将其发布在此处,以供那些仍在回答此问题的人使用。

      我们使用numpy.ndindex()

      给定数组的形状,ndindex 实例迭代数组的 N 维索引。每次迭代都会返回一个索引元组,最后一个维度首先被迭代。

      最好的理解方法是看一个例子:

      In [100]: for index in np.ndindex(2,2,2):
                    print(index)
      (0, 0, 0)
      (0, 0, 1)
      (0, 1, 0)
      (0, 1, 1)
      (1, 0, 0)
      (1, 0, 1)
      (1, 1, 0)
      (1, 1, 1)
      

      这正是我们正在寻找的,那么我们如何将其转换为 numpy 数组格式或列表?

      如果我们想要将坐标作为列表,我们可以使用:

      In [103]: coordList = [x for x in np.ndindex(2,2,2)]
      In [104]: print(coordList)
      [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
      

      如果我们想要将坐标作为一个 numpy 数组,我们可以使用:

      In [105]: coordArray = np.stack([x for x in np.ndindex(2,2,2)])
      In [106]: print(coordArray)
      [[0 0 0]
       [0 0 1]
       [0 1 0]
       [0 1 1]
       [1 0 0]
       [1 0 1]
       [1 1 0]
       [1 1 1]]
      

      这种方法很容易随着不同的尺寸和大小进行缩放,并且使用numpy.reshape(),我们可以准确地获得 OP 正在寻找的格式:

      In [117]: answer = np.stack([x for x in np.ndindex(2,2)]).reshape(2,2,2)
      In [118]: print(answer)
      [[[0 0]
        [0 1]]
      
       [[1 0]
        [1 1]]]
      

      同样,这很容易扩展到更大的维度:

      In [120]: example = np.stack([x for x in np.ndindex(3,3,3)]).reshape(3,3,3,3)
      In [121]: print(example)
      [[[[0 0 0]
         [0 0 1]
         [0 0 2]]
      
        [[0 1 0]
         [0 1 1]
         [0 1 2]]
      
        [[0 2 0]
         [0 2 1]
         [0 2 2]]]
      
      
       [[[1 0 0]
         [1 0 1]
         [1 0 2]]
      
        [[1 1 0]
         [1 1 1]
         [1 1 2]]
      
        [[1 2 0]
         [1 2 1]
         [1 2 2]]]
      
      
       [[[2 0 0]
         [2 0 1]
         [2 0 2]]
      
        [[2 1 0]
         [2 1 1]
         [2 1 2]]
      
        [[2 2 0]
         [2 2 1]
         [2 2 2]]]]
      

      【讨论】:

        【解决方案6】:

        到目前为止我发现的最简单的方法:

        height = 2
        width = 4
        t = np.mgrid[:height, :width]
        t = np.stack((t[0], t[1]), axis=2)
        
        >>> t
        array([
         [[0, 0], [0, 1], [0, 2], [0, 3]],
         [[1, 0], [1, 1], [1, 2], [1, 3]]
        ])
        

        如果你想在 tensorflow 中做同样的事情:

        rows = tf.range(0, img0.shape[1]) # generate row numbers
        cols = tf.range(0, img0.shape[2]) # generate col numbers
        cols, rows = tf.meshgrid(cols, rows) # expend them to a grid
        z = tf.stack((cols, rows), axis=2) # stack them together
        z = tf.stack([z]*img0.shape[0], axis=0) # stack up to number of batches
        

        【讨论】: