通过一个简单的函数:
def foo(x,y,z):
return x**2 + y*2 + z
并由空格定义:
In [328]: xv, yv, zv = [np.arange(i) for i in [2,3,4]]
这个迭代速度和任何一个一样快,尽管有点啰嗦:
In [329]: res = np.zeros((xv.shape[0], yv.shape[0], zv.shape[0]), dtype=int)
In [330]: for i,x in enumerate(xv):
...: for j,y in enumerate(yv):
...: for k,z in enumerate(zv):
...: res[i,j,k] = foo(x,y,z)
In [331]: res
Out[331]:
array([[[0, 1, 2, 3],
[2, 3, 4, 5],
[4, 5, 6, 7]],
[[1, 2, 3, 4],
[3, 4, 5, 6],
[5, 6, 7, 8]]])
正如 @mgilson 所解释的那样,您可以生成3个数组来定义3D空间:
In [332]: I,J,K = np.meshgrid(xv,yv,zv,indexing='ij',sparse=True)
In [333]: I.shape
Out[333]: (2, 1, 1)
In [334]: J.shape
Out[334]: (1, 3, 1)
In [335]: I,J,K = np.ix_(xv,yv,zv) # equivalently
In [336]: I.shape
Out[336]: (2, 1, 1)
foo
被编写成可以与数组一样良好地工作,因此:
In [337]: res1 = foo(I,J,K)
In [338]: res1
Out[338]:
array([[[0, 1, 2, 3],
...
[5, 6, 7, 8]]])
如果您的函数符合这种模式,请使用它。看看那些带有和不带有稀疏属性的 I,J,K
数组。
还有其他工具可以生成 i,j,k
集。例如:
for i,j,k in np.ndindex(res.shape):
res[i,j,k] = foo(xv[i], yv[j], zv[k])
for i,j,k in itertools.product(range(2),range(3),range(4)):
res[i,j,k] = foo(xv[i], yv[j], zv[k])
itertools.product
是快速的,特别是当用作 list(product(...))
时。但迭代机制并不那么重要。最耗时间的是对 foo
的重复调用。
ndindex
实际上使用了 nditer
,可以直接在以下情况下使用:
it = np.nditer([I,J,K,None],flags=['external_loop','buffered'])
for x,y,z,r in it:
r[...] = foo(x,y,z)
it.operands[-1]
nditer
最好的描述在于:https://docs.scipy.org/doc/numpy/reference/arrays.nditer.html。它最好用作迈向Cython版本的垫脚石。否则它没有任何速度优势。(虽然使用这个foo
和'external_loop'与foo(I,J,K)
一样快)。请注意,这不需要索引(但请参见'multi_index')。
是的,还有vectorize
。方便,但不是一个快速的解决方案。
vfoo=np.vectorize(foo, otypes=['int'])
vfoo(I,J,K)
itertools.product
? - juanpa.arrivillagafor i,x in enumerate(xv):
- hpauljfunc
的信息。它只能处理标量x,y,z
值吗?还是可以接受数组?如果可以接受数组,那么有多少维度? - hpaulj