我正在使用python 3 我想从3个维度的节点列表开始,并构建一个网格。 我想避免构造
import numpy as np
l = np.zeros(len(xv)*len(yv)*len(zv))
for (i,x) in zip(range(len(xv)),xv):
for (j,y) in zip(range(len(yv)),yv):
for (k,z) in zip(range(len(zv)),zv):
l[i,j,k] = func(x,y,z)
我正在寻找上述系列的更紧凑版本。像zip
这样的迭代器,但会遍历网格中所有可能的元组
答案 0 :(得分:4)
您可以使用类似np.meshgrid
的内容来构建网格。假设func
被正确地向量化,那应该足以构造l
X, Y, Z = np.meshgrid(xv, yv, zv)
l = func(X, Y, Z)
如果func
没有矢量化,您可以使用np.vectorize
构建矢量化版本。
另请注意,通过明智地使用np.meshgrid
,您甚至可以在不使用np.newaxis
的情况下离开:
>>> x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> y
array([0, 1, 2])
>>> z
array([0, 1])
>>> def func(x, y, z):
... return x + y + z
...
>>> vfunc = np.vectorize(func)
>>> vfunc(x[:, np.newaxis, np.newaxis], y[np.newaxis, :, np.newaxis], z[np.newaxis, np.newaxis, :])
array([[[ 0, 1],
[ 1, 2],
[ 2, 3]],
[[ 1, 2],
[ 2, 3],
[ 3, 4]],
[[ 2, 3],
[ 3, 4],
[ 4, 5]],
[[ 3, 4],
[ 4, 5],
[ 5, 6]],
[[ 4, 5],
[ 5, 6],
[ 6, 7]],
[[ 5, 6],
[ 6, 7],
[ 7, 8]],
[[ 6, 7],
[ 7, 8],
[ 8, 9]],
[[ 7, 8],
[ 8, 9],
[ 9, 10]],
[[ 8, 9],
[ 9, 10],
[10, 11]],
[[ 9, 10],
[10, 11],
[11, 12]]])
正如评论中所指出的,np.ix_
可以用作快捷方式,而不是np.newaxis
:
vfunc(*np.ix_(xv, yv, zv))
还要注意,使用这个愚蠢的简单函数,np.vectorize
是不必要的,实际上会损害我们的表现......
答案 1 :(得分:1)
说你的功能就像
def func(x,y,z,indices):
xv, yv, zv = [i[j] for i,j in zip((x,y,z),indices)]
#do a calc with the value for the specific x,y,z points
通过
使用partial挂钩您想要的列表from functools import partial
f = partial(func, x=xv, y=yv, z=zv)
现在只需要提供一个提供索引的地图就可以了!
l = list(map(lambda x: f(indices=x), itertools.product(x,y,z)))
答案 2 :(得分:0)
功能简单:
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
数组,包含和不包含sparse
。
还有其他工具可用于生成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)