2011-04-16 113 views
9

什么是在python中遍历n维数组的所有一维子数组的最快方法。通过多维数组的所有1维子阵列进行迭代

例如,考虑3-d数组:

import numpy as np 
a = np.arange(24) 
a = a.reshape(2,3,4) 

从迭代器的产率的期望的顺序是:

a[:,0,0] 
a[:,0,1] 
.. 
a[:,2,3] 
a[0,:,0] 
.. 
a[1,:,3] 
a[0,0,:] 
.. 
a[1,2,:] 

回答

10

这里是一个紧凑的实现这样一个迭代器:

def iter1d(a): 
    return itertools.chain.from_iterable(
     numpy.rollaxis(a, axis, a.ndim).reshape(-1, dim) 
     for axis, dim in enumerate(a.shape)) 

这将产生在您在您的文章一声令子阵:

for x in iter1d(a): 
    print x 

打印

[ 0 12] 
[ 1 13] 
[ 2 14] 
[ 3 15] 
[ 4 16] 
[ 5 17] 
[ 6 18] 
[ 7 19] 
[ 8 20] 
[ 9 21] 
[10 22] 
[11 23] 
[0 4 8] 
[1 5 9] 
[ 2 6 10] 
[ 3 7 11] 
[12 16 20] 
[13 17 21] 
[14 18 22] 
[15 19 23] 
[0 1 2 3] 
[4 5 6 7] 
[ 8 9 10 11] 
[12 13 14 15] 
[16 17 18 19] 
[20 21 22 23] 

这里的窍门是遍历所有轴,并且对于每个轴重塑阵列的二维阵列的行,其中在期望的一维子阵列。

+0

非常好!比我的解决方案更优雅(更高效)! – 2011-04-16 19:24:26

+0

真棒解决方案! – fodon 2011-04-16 22:24:29

+0

我试图向您发送一封电子邮件给您的个人资料上列出的.net网址的root用户。如果你不想连接,那很好。 – fodon 2011-04-17 16:40:24

0

你的朋友都是slice()对象,numpy的的ndarray.__getitem__()方法,以及可能itertools.chain.from_iterable

5

有可能是一个更有效的方式,但是这应该工作...

import itertools 
import numpy as np 

a = np.arange(24) 
a = a.reshape(2,3,4) 

colon = slice(None) 
dimensions = [range(dim) + [colon] for dim in a.shape] 

for dim in itertools.product(*dimensions): 
    if dim.count(colon) == 1: 
     print a[dim] 

这个收益率(我要离开了代码琐碎位来打印这左边... ):

a[0,0,:] --> [0 1 2 3] 
a[0,1,:] --> [4 5 6 7] 
a[0,2,:] --> [ 8 9 10 11] 
a[0,:,0] --> [0 4 8] 
a[0,:,1] --> [1 5 9] 
a[0,:,2] --> [ 2 6 10] 
a[0,:,3] --> [ 3 7 11] 
a[1,0,:] --> [12 13 14 15] 
a[1,1,:] --> [16 17 18 19] 
a[1,2,:] --> [20 21 22 23] 
a[1,:,0] --> [12 16 20] 
a[1,:,1] --> [13 17 21] 
a[1,:,2] --> [14 18 22] 
a[1,:,3] --> [15 19 23] 
a[:,0,0] --> [ 0 12] 
a[:,0,1] --> [ 1 13] 
a[:,0,2] --> [ 2 14] 
a[:,0,3] --> [ 3 15] 
a[:,1,0] --> [ 4 16] 
a[:,1,1] --> [ 5 17] 
a[:,1,2] --> [ 6 18] 
a[:,1,3] --> [ 7 19] 
a[:,2,0] --> [ 8 20] 
a[:,2,1] --> [ 9 21] 
a[:,2,2] --> [10 22] 
a[:,2,3] --> [11 23] 

这里的关键是,索引a与(例如)a[0,0,:]等同于用a[(0,0,slice(None))]索引一个。 (这只是一般的python切片,没有任何特定的numpy,为了向你自己证明,你可以编写一个虚拟类,只需要一个__getitem__,并打印当你索引虚拟类的实例时传入的内容。

所以,我们想要的是每个轴的0到nx,0到ny,0到nz等等和None的每种可能组合。

但是,我们希望一维数组,所以我们需要过滤掉任何与多于或少于一个None(即我们不想a[:,:,:]a[0,:,:]a[0,0,0]等)。

希望这有一定道理,反正...

编辑:我假设的确切顺序并不重要...如果你需要的确切命令你在你的问题一一列出,你会需要修改这个...

+0

@FM - 好点,这更可读。谢谢! – 2011-04-16 18:15:53

+1

@FM:实际上'dim.count(无)'看起来比'总和(如果物品为无,则为暗物品1)'' – 2011-04-16 19:26:29

+0

@Sven - 再一次,优点!我忽略了显而易见的,那里... – 2011-04-16 19:34:13