努比·恩达雷在适当的维度子集上枚举?

2024-04-26 12:27:38 发布

您现在位置:Python中文网/ 问答频道 /正文

(在本文中,让npnumpy的简写。)

假设a是一个(n+k)维np.ndarray对象,对于一些整数n>;1和k>;1。(如下,n+k>;3是a.ndim的值)。我想在第一个n维度上枚举a;这意味着,在每次迭代中,枚举器/迭代器生成一对元素,其第一个元素是索引为n的元组ii,第二个元素是位于a[ii]k多维子ndarray。在

当然,编写一个函数来实现这一点并不困难(事实上,我在下面给出了这样一个函数的例子),但我想知道:

does numpy provide any special syntax or functions for carrying out this type of "partial" enumeration?

(通常,当我想迭代多维np.ndarray对象时,我使用np.ndenumerate,但在这里没有帮助,因为(据我所知,np.ndenumerate将迭代所有n+k维度。)

假设上述问题的答案是肯定的,那么接下来就是:

what about the case where the n dimensions to iterate over are not contiguous?

(在这种情况下,枚举器/迭代器在每次迭代时返回的对的第一个元素将是r>;n元素的元组,其中一些元素将是表示“all”的特殊值,例如slice(None);这对元素对的第二个元素仍然是长度为kndarray

谢谢!在


下面的代码希望能澄清问题说明。函数partial_enumerate使用任何特殊的numpy构造来完成我想做的事情。在partial_enumerate的定义之后,是一个简单的例子,适用于n=k=2。在

import numpy as np
import itertools as it
def partial_enumerate(nda, n):
  """Enumerate over the first N dimensions of the numpy.ndarray NDA.

  Returns an iterator of pairs.  The first element of each pair is a tuple 
  of N integers, corresponding to a partial index I into NDA; the second element
  is the subarray of NDA at I.
  """

  # ERROR CHECKING & HANDLING OMITTED
  for ii in it.product(*[range(d) for d in nda.shape[:n]]):
    yield ii, nda[ii]

a = np.zeros((2, 3, 4, 5))
for ii, vv in partial_enumerate(a, 2):
    print ii, vv.shape

输出的每一行都是一个“元组对”,其中第一个元组表示a中的一组部分n坐标,第二个元组表示{}中{k维子数组的形状;(第二对的值对于所有行都是相同的,从数组的规则性可以看出):

^{pr2}$

相反,在这种情况下,迭代np.ndenumerate(a)将导致a.size迭代,每个迭代访问{}的单个单元格。在


Tags: ofthe函数gtnumpy元素fornp
2条回答

我想你在找numpy中的函数ndindex。只需从您想要的子阵列中取一片:

from numpy import *

# Create the array
A = zeros((2,3,4,5))

# Identify the subindex you're looking for
idx = ndindex(A.shape[:2])

# Iterate through the array
[(x, A[x].shape) for x in idx]

这将产生预期结果:

^{pr2}$

可以使用numpy广播规则生成笛卡尔积。numpy.ix_函数创建适当数组的列表。相当于:

>>> def pseudo_ix_gen(*arrays):
...     base_shape = [1 for arr in arrays]
...     for dim, arr in enumerate(arrays):
...         shape = base_shape[:]
...         shape[dim] = len(arr)
...         yield numpy.array(arr).reshape(shape)
... 
>>> def pseudo_ix_(*arrays):
...     return list(pseudo_ix_gen(*arrays))

或者,更简洁地说:

^{pr2}$

结果是可广播数组的列表:

>>> numpy.ix_(*[[2, 4], [1, 3], [0, 2]])
[array([[[2]],

       [[4]]]), array([[[1],
        [3]]]), array([[[0, 2]]])]

将此结果与numpy.ogrid的结果进行比较:

>>> numpy.ogrid[0:2, 0:2, 0:2]
[array([[[0]],

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

如您所见,它是相同的,但是numpy.ix_允许您使用非连续索引。现在,当我们应用numpy广播规则时,我们得到一个笛卡尔积:

>>> list(numpy.broadcast(*numpy.ix_(*[[2, 4], [1, 3], [0, 2]])))
[(2, 1, 0), (2, 1, 2), (2, 3, 0), (2, 3, 2), 
 (4, 1, 0), (4, 1, 2), (4, 3, 0), (4, 3, 2)]

如果不是将numpy.ix_的结果传递给numpy.broadcast,而是用它来索引一个数组,我们得到:

>>> a = numpy.arange(6 ** 4).reshape((6, 6, 6, 6))
>>> a[numpy.ix_(*[[2, 4], [1, 3], [0, 2]])]
array([[[[468, 469, 470, 471, 472, 473],
         [480, 481, 482, 483, 484, 485]],

        [[540, 541, 542, 543, 544, 545],
         [552, 553, 554, 555, 556, 557]]],


       [[[900, 901, 902, 903, 904, 905],
         [912, 913, 914, 915, 916, 917]],

        [[972, 973, 974, 975, 976, 977],
         [984, 985, 986, 987, 988, 989]]]])

但是,提醒清空者。可广播数组对于索引非常有用,但是如果您确实想枚举值,则最好使用itertools.product

>>> %timeit list(itertools.product(range(5), repeat=5))
10000 loops, best of 3: 196 us per loop
>>> %timeit list(numpy.broadcast(*numpy.ix_(*([range(5)] * 5))))
100 loops, best of 3: 2.74 ms per loop

因此,如果您要合并for循环,那么itertools.product可能会更快。不过,您可以使用上述方法在纯numpy中获得一些类似的数据结构:

>> pgrid_idx = numpy.ix_(*[[2, 4], [1, 3], [0, 2]])
>>> sub_indices = numpy.rec.fromarrays(numpy.indices((6, 6, 6)))
>>> a[pgrid_idx].reshape((8, 6))
array([[468, 469, 470, 471, 472, 473],
       [480, 481, 482, 483, 484, 485],
       [540, 541, 542, 543, 544, 545],
       [552, 553, 554, 555, 556, 557],
       [900, 901, 902, 903, 904, 905],
       [912, 913, 914, 915, 916, 917],
       [972, 973, 974, 975, 976, 977],
       [984, 985, 986, 987, 988, 989]])
>>> sub_indices[pgrid_idx].reshape((8,))
rec.array([(2, 1, 0), (2, 1, 2), (2, 3, 0), (2, 3, 2), 
           (4, 1, 0), (4, 1, 2), (4, 3, 0), (4, 3, 2)], 
          dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8')])

相关问题 更多 >