2016-02-19 85 views
1

我想通過指數,如第三陣列使用來自另一數組的值來改變在一個陣列中的值使用來自不同陣列的值:與numpy的陣列改變特定值+ =通過索引列表

import numpy as np 
F = np.zeros((4,3)) # array I wish to change 
f = np.array([[3,4,0],[0,0,1]]) # values I wish to add to F 
i = np.array([2, 2]) # indices in F I wish to affect 

允許使用該數據在f

for id in xrange(len(i)): 
    F[i[id]] += f[id] 

# F[2] is now equal to np.array([ 3., 4., 1.]) because 
# both values in f have been correctly added to F[2] 

+=操作上F上的每個索引使用值i我假定我可以做同樣的操作在一行像這樣:

F[i] += f 
# F[2] is now equal to np.array([ 0., 0., 1.]) 
# i expected np.array([ 3., 4., 1.]) 

但是這個失敗。我希望結果是np.array([ 3., 4., 1.])

如果i過不同的指數(例如:array([0, 2]))的列表,然後F[0]F[2]會在f被設置到適當的項目,但在這種情況下,我希望做一個+=操作,當指標重複時,我希望結果是累積的。

在簡單的一行操作中沒有辦法做到這一點嗎?

+0

您可以添加預期的輸出嗎? – Cleb

+0

@Cleb,第三個Python代碼片段:「#我期待np.array([3.,4.,1。])」......但我應該在我的問題中做得更清楚。謝謝! – Fnord

+1

@Kevin在這種情況下是的,我想要的是在F [2]上執行兩次+ =。 – Fnord

回答

2

您正在查找的操作是numpy.add.at。至關重要的是,這是無緩衝添加在指定的指示,而F[i] += f使用內部緩衝區。

但是,ufunc.at是非常優秀的臭名昭着的。如果您的陣列足夠大並且長方形,則可能需要做一個小循環並使用bincount。示例時間:

In [43]: n = 10**5 
    ...: m = 10**6 
    ...: I = np.random.randint(n, size=m) 
    ...: f = np.random.rand(m, 3) 

In [44]: %%time 
    ...: F = np.zeros((n, 3)) 
    ...: np.add.at(F, I, f) 
Wall time: 624 ms 

In [45]: %%time 
    ...: F2 = np.zeros((n, 3)) 
    ...: for dim in range(3): 
    ...:  F2[:,dim] += np.bincount(I, f[:,dim], n)t 
Wall time: 94 ms 

In [46]: np.allclose(F, F2) 
Out[46]: True 
+0

是否存在'add.at'比'bincount'解決方案更受歡迎的情況?後者+1;看起來比我想出來的要好。 – Cleb

+0

@Cleb - 是的:帶重量的計數總是返回float64,而add.at則支持所有的numpy類型。另外,add.at需要一個axis參數,而使用bincount則需要手動循環並採用一維切片。如果你需要經常調用bincount,相對於數據的大小,在某些時候add.at會更快。 – 2016-02-20 22:18:01

+0

好,知道;感謝您的詳細解釋。 – Cleb

1

在這種特殊情況下(i僅包含一個唯一的號碼),你可以通過避免for循環:

F[i] += sum(f) 

array([[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 3., 4., 1.], 
     [ 0., 0., 0.]]) 

如果i包含幾個數字那麼下面就很好地工作:

F2 = np.zeros((4,3)) 
i2 = np.array([2, 3]) 
F2[i2] += f 

Then F2 is:

array([[ 0., 0., 0.], 
     [ 0., 0., 0.], 
     [ 3., 4., 0.], 
     [ 0., 0., 1.]]) 

您可以使用set(i)檢查i中不同號碼的數量,然後根據set(i)的長度將第一個或第二個選項應用於F