2011-03-24 155 views
2

我读一个供应商提供的大的二进制阵列成2D numpy的阵列tempfid的复杂重塑的执行效率(M,N)numpy的:阵列

# load data 
data=numpy.fromfile(file=dirname+'/fid', dtype=numpy.dtype('i4')) 

# convert to complex data 
fid=data[::2]+1j*data[1::2] 

tempfid=fid.reshape(I*J*K, N) 

,然后我需要将其重新成形到使用指数的非平凡映射的4D阵列有用4d(N,I,J,K)。我这样做有用于大致如下循环:

for idx in range(M): 
    i=f1(idx) # f1, f2, and f3 are functions involving/and % as well as some lookups 
    j=f2(idx) 
    k=f3(idx) 
    newfid[:,i,j,k] = tempfid[idx,:] #SLOW! CAN WE IMPROVE THIS? 

转换为复杂的花费33%的时间,而这些切片m个切片的复制操作的其余66%。计算指数是快速的,而不管我是在一个循环中如图所示一个接一个地做,还是通过numpy.vector操作并将其应用到arange(M)。

有没有办法加快速度?任何帮助更有效的切片,复制(或不)等赞赏。

编辑: 正如在回答学会了提问"What's the fastest way to convert an interleaved NumPy integer array to complex64?"转化为复杂的可以通过6的一个因素,如果一个视图来代替被加速:

fid = data.astype(numpy.float32).view(numpy.complex64) 
+2

您是否尝试过向量化i,j,k的计算,然后使用生成的数组在一行中创建副本? – 2011-03-24 16:26:55

+0

@Winston Ewert:这是我可能失败的地方。我能够矢量化i,j,k的计算并创建vec_f1 = numpy.vectorize(lambda x:f1(x))并获得i_idx = vec_f1(idx)等等。但是,我无法想出一个数组的行操作:vec_assign = vectorize(lambda idx:newfid [***] = tempfid [***])给出错误,因为'lambda不能包含赋值' – DrSAR 2011-03-24 16:36:14

+0

如果您使用的是Python 2.x,并且M很大,如果你打算循环,你应该考虑使用'xrange'而不是'range',就像一般规则一样。 – JoshAdel 2011-03-24 16:59:21

回答

2
idx = numpy.arange(M) 
i = numpy.vectorize(f1)(idx) 
j = numpy.vectorize(f2)(idx) 
k = numpy.vectorize(f3)(idx) 

# you can index arrays with other arrays 
# that lets you specify this operation in one line.  
newfid[:, i,j,k] = tempfid.T 

我从来没有使用numpy的矢量化。 Vectorize只是意味着numpy会多次调用你的python函数。为了获得速度,你需要使用像我在这里展示的那样的数组操作,并且你曾经获得复数。

EDIT

的问题是,尺寸128的尺寸为在第一newfid,但最后在tempfid。这很容易通过使用.T来进行转置。

+1

我不认为最后一行会起作用。例如'i = [1,0]; j = [0,1]; b = np.zeros((2,2)); a = np.arange(4); b [i,j] = a [a]'给你一个广播错误。 – JoshAdel 2011-03-24 17:10:55

+0

@Winston Ewert:使用这个,我得到一个'ValueError:数组不能广播以纠正形状'。请注意,idx,i,j,k都具有相同的一维长度和(对我的眼睛)正确地处理它们各自的尺寸。 – DrSAR 2011-03-24 17:12:06

+0

@JoshAdel,失败,因为len(i)!= len(a) – 2011-03-24 17:22:45

2

这个怎么样。用F1,F2,F3的矢量版本(不一定使用np.vectorize,但也许只是写一个函数,它接受一个数组,并返回一个数组)设置我们您indicies,然后使用np.ix_

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ix_.html

获取索引数组。然后将tempfid重塑为与newfid相同的形状,然后使用np.ix_的结果来设置值。例如:

tempfid = np.arange(10) 
i = f1(idx) # i = [4,3,2,1,0] 
j = f2(idx) # j = [1,0] 
ii = np.ix_(i,j) 
newfid = tempfid.reshape((5,2))[ii] 

这将映射的tempfid到一个新的形状具有不同的排序的元素。

+0

@JoshAdel:这看起来很有希望,但是我得到一个'ValueError:广播尺寸太大。'这是否表明我搞砸了np.ix_业务还是有限制?我正在处理复杂数字的128 x 64 x 1 x 1200阵列 – DrSAR 2011-03-24 17:40:17

+0

@DrSAR:我可以非常轻松地在我的机器上创建大小为空的复杂数组。然后,如果我做'h = np。空((128,64,1,1200),D型细胞=配合物); a = np.arange(h.size); a = a + 1j * a; ii = np.ix_(范围(128),范围(64),范围(1),范围(1200)); h = a.reshape(h.shape)[ii]'一切正常(对不起,这是连续的干扰)。你可能会犯'np.ix_'错误 – JoshAdel 2011-03-24 17:53:44

+0

@JoshAdel:我可能是。您评论中的版本适用于我。但是,当我让我的ix_的实现在128 x 64 x 1 x 1的情况下丢失时,它的工作原理没有ValueError,但与直接循环相比,它的速度惊人地慢。事实上,大约是3000倍。我还注意到,我的机器在我的机器上花费了大约1.2秒(没有ValueError,我同意),其中大部分花费在使用索引的数组赋值中。 ix_应该是方便还是快速?或者两者兼得? – DrSAR 2011-03-24 18:05:08