python:从网格节点在网格上构建迭代器

时间:2016-12-21 17:23:51

标签: python python-3.x numpy iterator

我正在使用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这样的迭代器,但会遍历网格中所有可能的元组

3 个答案:

答案 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)