2014-10-07 67 views
3

我正在使用numpy 1.9來處理一組數組。假設我有類似的東西我有兩個二維數組AB和一個1-d陣列C,這看起來像:非對齊元素在numpy數組中的插入

>>> A 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.]]) 
>>> B 
array([[-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.]]) 
>>> C 
array([1, 3, 2, 4, 0]) 

我的目標是在從B A的所有元素插入,根據C.更具體地說,如果位置0處的C具有1,則應當在A [0,1]之後插入B [0,1]。

這裏的預期結果:

array([[ 1, 1, -1, 1, 1, 1], 
     [ 1, 1, 1, 1, -1, 1], 
     [ 1, 1, 1, -1, 1, 1], 
     [ 1, 1, 1, 1, 1, -1], 
     [ 1, -1, 1, 1, 1, 1]]) 

我試圖實現它這樣的,但它不是非常快:

for i in xrange(size(C, 0)): 
    j = C[i] 
    A[i, :] = numpy.insert(A[i], j, B[i, j]) 

有一種方法,使其更快? (做一個單一的numpy操作,如口罩或類似的東西)

+2

你是一個錯誤的例子結果(你不能將一個6元素數組賦給'A [i,:]',它只有5個元素的空間)。 – 2014-10-07 03:57:43

+0

@WarrenWeckesser對不起,你是對的,我寫下了示例矩陣,並沒有多想太多。我正在修復:) – ProGM 2014-10-07 04:49:36

+1

我調整了你的迭代工作。 – hpaulj 2014-10-07 06:56:27

回答

5

如何一個討厭的單線?

一,數據;數組的形狀與您的形狀相同,但我使用整數使示例更易於閱讀。

In [81]: A 
Out[81]: 
array([[ 0, 1, 2, 3, 4], 
     [ 5, 6, 7, 8, 9], 
     [10, 11, 12, 13, 14], 
     [15, 16, 17, 18, 19], 
     [20, 21, 22, 23, 24]]) 

In [82]: B 
Out[82]: 
array([[ 0, 100, 200, 300, 400], 
     [ 500, 600, 700, 800, 900], 
     [1000, 1100, 1200, 1300, 1400], 
     [1500, 1600, 1700, 1800, 1900], 
     [2000, 2100, 2200, 2300, 2400]]) 

In [83]: C 
Out[83]: array([1, 3, 2, 4, 0]) 

而這裏的骯髒的一行:

In [84]: np.insert(A.ravel(), np.ravel_multi_index((range(A.shape[0]), C), A.shape) + 1, B[range(B.shape[0]), C]).reshape(A.shape[0], A.shape[1]+1) 
Out[84]: 
array([[ 0, 1, 100, 2, 3, 4], 
     [ 5, 6, 7, 8, 800, 9], 
     [ 10, 11, 12, 1200, 13, 14], 
     [ 15, 16, 17, 18, 19, 1900], 
     [ 20, 2000, 21, 22, 23, 24]]) 

這裏是破舊的版本:

A.ravel()變平A成1-d陣列,我會打電話給F

In [87]: F = A.ravel() 

In [88]: F 
Out[88]: 
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 
     17, 18, 19, 20, 21, 22, 23, 24]) 

(編輯:原來這第一步 - 展平A - 沒有必要。正如@hpaulj在他的回答中指出的那樣,np.insert會默認將該陣列展平。)

np.ravel_multi_index用於將所需的二維位置轉換爲摺疊數組中的索引。

In [89]: insert_indices = np.ravel_multi_index((range(A.shape[0]), C), A.shape) + 1 

In [90]: insert_indices 
Out[90]: array([ 2, 9, 13, 20, 21]) 

B[range(B.shape[0]), C]拉期望值出B

In [91]: values = B[range(B.shape[0]), C] 

In [92]: values 
Out[92]: array([ 100, 800, 1200, 1900, 2000]) 

np.insert進行實際的+ 1末,因爲你想後插入的元素C給出的指標是必要的插入並創建一個新陣列:

In [93]: np.insert(F, insert_indices, values) 
Out[93]: 
array([ 0, 1, 100, 2, 3, 4, 5, 6, 7, 8, 800, 
      9, 10, 11, 12, 1200, 13, 14, 15, 16, 17, 18, 
     19, 1900, 20, 2000, 21, 22, 23, 24]) 

現在只是重塑,要得到最終的結果是:

In [94]: np.insert(F, insert_indices, values).reshape(A.shape[0], A.shape[1]+1) 
Out[94]: 
array([[ 0, 1, 100, 2, 3, 4], 
     [ 5, 6, 7, 8, 800, 9], 
     [ 10, 11, 12, 1200, 13, 14], 
     [ 15, 16, 17, 18, 19, 1900], 
     [ 20, 2000, 21, 22, 23, 24]]) 
+1

有用的解決方案!它也可以用於三維矩陣嗎?我嘗試了一個小時,但我找不到正確的方式來實現您的解決方案,而不使用800 * 600 * 6矩陣的任何循環。根據這個例子,我想從B完全插入第三維元素。你可以寫一個3維版本嗎?謝謝! – Rowandish 2014-10-07 08:35:55

3

首先,一些稍微清晰陣列:

>>> A 
array([[ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.], 
     [ 1., 1., 1., 1., 1.]]) 
>>> B 
array([[-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.], 
     [-1., -1., -1., -1., -1.]]) 
>>> C 
array([1, 3, 2, 4, 0]) 

下,一些面膜詭計:

>>> ge_mask = C.reshape(-1, 1) >= numpy.arange(5) 
>>> eq_mask = C.reshape(-1, 1) == numpy.arange(5) 
>>> lt_mask = C.reshape(-1, 1) < numpy.arange(5) 

而且政變degrâce:

>>> result = numpy.zeros((A.shape[0], A.shape[1] + 1)) 
>>> result[:,0:5][ge_mask] = A[ge_mask] 
>>> result[:,1:6][eq_mask] = B[eq_mask] 
>>> result[:,1:6][lt_mask] = A[lt_mask] 
>>> result 
array([[ 1., 1., -1., 1., 1., 1.], 
     [ 1., 1., 1., 1., -1., 1.], 
     [ 1., 1., 1., -1., 1., 1.], 
     [ 1., 1., 1., 1., 1., -1.], 
     [ 1., -1., 1., 1., 1., 1.]]) 

Warren's剛剛發佈的答案好像從記憶的角度來看可能會更好。不知道速度。 (我認爲上面是有點更清晰!)

+0

肯定更清晰。 :) – 2014-10-07 04:22:19

+0

謝謝!我會嘗試兩種方法。也許我必須編輯我的文章,以添加一個更可讀的示例矩陣,就像你的;) – ProGM 2014-10-07 04:48:06

3

我相信這是修正迭代:

A=np.arange(25).reshape(5,5) 
B=np.arange(25).reshape(5,5)*-1 
C=np.array([1,3,2,4,0]) 

A2=np.zeros((5,6),dtype=int) 
for i,c in enumerate(C): 
    A2[i,:]=np.insert(A[i],c+1,B[i,c]) 

生產:

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

這可以變成一個班輪爲:

np.array([np.insert(a, c+1, b[c]) for a,b,c in zip(A,B,C)]) 

在沃倫的回答等效範圍是:

c <=> c = np.ravel_multi_index((range(5), C), (5,5)) 
b <=> B.ravel()[c] 
np.insert(A, c+1, B.ravel()[c]).reshape(5,6) 

np.insert ravels A作爲默認值。對於這個小例子,這個ravel_multi_index比行迭代快兩倍。