And*_*rtz 7 python arrays numpy matrix coordinates
我正在尝试获得一个坐标数组矩阵.这与numpy.meshgrid不同.例如,对于2x2尺寸,我想要2x2x2输出
[[[0,0],[0,1]],
[[1,0],[1,1]]]
Run Code Online (Sandbox Code Playgroud)
作为一个numpy数组.这可能看起来和读取更清晰的2x2元组矩阵:
[[(0,0),(0,1)],
[(1,0),(1,1)]]
Run Code Online (Sandbox Code Playgroud)
(除了我不认为你可以在一个numpy数组中有元组,这不是重点)
这个简单的例子可以通过切换numpy-meshgrid输出的轴来完成(具体来说,将第一个轴移动到最后):
np.array(np.meshgrid([0,1],[0,1])).transpose([1,2,0])
Run Code Online (Sandbox Code Playgroud)
这可以很容易地推广到任意维度,除了meshgrid不像我期望的那样超过2个输入.具体来说,返回的矩阵具有沿奇数顺序的轴变化的坐标值:
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]]])]
Run Code Online (Sandbox Code Playgroud)
请注意,此输出的元素分别沿轴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]]]])
Run Code Online (Sandbox Code Playgroud)
但这开始变得非常hacky,我不知道我是否可以依靠高维网格网格输出中的这个顺序.numpy.mgrid给出正确的顺序,但似乎不允许任意值,我将需要.所以这归结为两个问题:
1)是否有一种更清洁的方式,也许是我缺少的numpy中的某些功能,它会生成如上所述的坐标向量矩阵?2)这个奇怪的排序真的是我们对meshgrid的期望吗?这一点是否有我可以指望的规格?
[编辑]关注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
Run Code Online (Sandbox Code Playgroud)
鉴于1D coords:
rows = np.arange(2)
cols = np.arange(3)
Run Code Online (Sandbox Code Playgroud)
我希望这可以解决这个问题:
np.dstack((rows[:, None, None], cols[:, None]))
Run Code Online (Sandbox Code Playgroud)
但显然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]]])
Run Code Online (Sandbox Code Playgroud)
numpy函数indices也可以用于此目的,其功能也可以从其名称中清楚看出。
>>> import numpy as np
>>> np.indices((2,3))
array([[[0, 0, 0],
[1, 1, 1]],
[[0, 1, 2],
[0, 1, 2]]])
Run Code Online (Sandbox Code Playgroud)
可以认为是y坐标的2 x 3矩阵和x坐标(y,x = np.indices((2,3)))的2 x 3矩阵。可以通过移置轴将其重铸为Jaime提出的形式:
>>> np.indices((2,3)).transpose((1,2,0))
Run Code Online (Sandbox Code Playgroud)
它在功能上等同于该meshgrid解决方案,使用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
Run Code Online (Sandbox Code Playgroud)
在时间上明智的做法是,当考虑生成在其上进行meshgrid操作的一维数组所需的时间时,这些解决方案是相似的,但是meshgrid返回一个(数组)列表,而不是像这样的nd数组indices。通过np.array像f1上面那样添加一个额外的调用,indices相对于meshgrid:具有明显的优势:
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
Run Code Online (Sandbox Code Playgroud)
无需额外致电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
Run Code Online (Sandbox Code Playgroud)
不过,在解释时间时请务必小心。这可能不会成为您解决任何问题的瓶颈。
无论如何,meshgrid可以做的事情比做的更多indices,例如生成更通用的直线网格而不是笛卡尔网格,因此在适当时使用它们。在这种情况下,我将使用命名方式更具描述性indices。
尝试np.meshgrid([0, 1], [0, 1], [0, 1], indexing="ij")。这些meshgrid文档实际上非常明确地说明了默认值indexing="xy"与非默认值相比如何产生有趣的轴排序indexing="ij",因此您可以检查它以获取更多详细信息。(他们不太清楚为什么会这样,唉......)