2011-03-24 192 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