(在这篇文章中,让我们np简写一下numpy.)
假设a是(n + k)维np.ndarray对象,对于一些整数n > 1且k > 1.(IOW,n + k > 3是值a.ndim).我想列举a它的前n个维度; 这意味着,在每一次迭代,枚举/迭代器产生一对,其第一个元素是一个元组ii的Ñ指数,以及第二个元素是ķ维子ndarray在a[ii].
当然,编写一个函数来做这个并不困难(事实上,我在下面给出了这样一个函数的例子),但我想知道这个:
是否
numpy提供了执行此类"部分"枚举的特殊语法或函数?
(通常,当我想迭代一个多维np.ndarray对象时,我会使用np.ndenumerate,但在这里没有用,因为(据我所知)np.ndenumerate会迭代所有 n + k维度.)
假设上述问题的答案是肯定的,那么就是这样的后续行动:
那些迭代的n维不连续的情况怎么样?
(在这种情况下,枚举器/迭代器在每次迭代时返回的对的第一个元素将是r > n个元素的元组,其中一些元素将是表示"全部"的特殊值,例如slice(None);第二个元素对仍然是ndarray长度k.)
谢谢!
下面的代码有希望澄清问题规范.该函数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
Run Code Online (Sandbox Code Playgroud)
输出的每一行是"一对元组",其中第一个元组表示n个坐标的部分集合,第二个元组表示这些部分坐标处a的k维子阵列的形状a; (第二对的值对于所有行都是相同的,正如数组的规律性所预期的那样):
(0, 0) (4, 5)
(0, 1) (4, 5)
(0, 2) (4, 5)
(1, 0) (4, 5)
(1, 1) (4, 5)
(1, 2) (4, 5)
Run Code Online (Sandbox Code Playgroud)
相反,np.ndenumerate(a)在这种情况下a.size迭代将导致迭代,每次迭代访问单个单元格a.
您可以使用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))
Run Code Online (Sandbox Code Playgroud)
或者,更简洁地说:
>>> def pseudo_ix_(*arrays):
... shapes = numpy.diagflat([len(a) - 1 for a in arrays]) + 1
... return [numpy.array(a).reshape(s) for a, s in zip(arrays, shapes)]
Run Code Online (Sandbox Code Playgroud)
结果是可广播数组的列表:
>>> numpy.ix_(*[[2, 4], [1, 3], [0, 2]])
[array([[[2]],
[[4]]]), array([[[1],
[3]]]), array([[[0, 2]]])]
Run Code Online (Sandbox Code Playgroud)
将此与以下结果进行比较numpy.ogrid:
>>> numpy.ogrid[0:2, 0:2, 0:2]
[array([[[0]],
[[1]]]), array([[[0],
[1]]]), array([[[0, 1]]])]
Run Code Online (Sandbox Code Playgroud)
如您所见,它是相同的,但是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)]
Run Code Online (Sandbox Code Playgroud)
如果不是将结果传递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]]]])
Run Code Online (Sandbox Code Playgroud)
但是,请警告。可广播的数组对于建立索引很有用,但是如果您确实想枚举值,则最好使用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
Run Code Online (Sandbox Code Playgroud)
因此,如果您仍然合并了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')])
Run Code Online (Sandbox Code Playgroud)
我认为您正在寻找ndindex函数numpy。只需取您想要的子数组的一部分即可:
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]
Run Code Online (Sandbox Code Playgroud)
这给出了预期的结果:
[((0, 0), (4, 5)), ((0, 1), (4, 5)), ((0, 2), (4, 5)), ((1, 0), (4, 5)), ((1, 1), (4, 5)), ((1, 2), (4, 5))]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1292 次 |
| 最近记录: |