2015-04-08 123 views
2

我正在嘗試更新一組特定的行和列的numpy矩陣。這裏有一個例子:Numpy矩陣的複合索引更新

import numpy as np 
A=np.zeros((8,8)) 
rows=[0, 1, 5] 
columns=[2, 3] 
#(What I am trying to achieve) The following does not update A 
A[rows][:,columns]+=1 
#while this just does 
for i in rows: 
    A[i][columns]+=1 

我期待的輸出爲:

In [1]:print(A) 
Out[1]: 
    array([[ 0., 0., 1., 1., 0., 0., 0., 0.], 
      [ 0., 0., 1., 1., 0., 0., 0., 0.], 
      [ 0., 0., 0., 0., 0., 0., 0., 0.], 
      [ 0., 0., 0., 0., 0., 0., 0., 0.], 
      [ 0., 0., 0., 0., 0., 0., 0., 0.], 
      [ 0., 0., 1., 1., 0., 0., 0., 0.], 
      [ 0., 0., 0., 0., 0., 0., 0., 0.], 
      [ 0., 0., 0., 0., 0., 0., 0., 0.]]) 

是否有不執行的循環多縱列和-rowwise更新在同一時間的方法嗎?

回答

3

索引與陣列或索引的列表的fancy indexing類別下下降,總是的列表(或發電機)產生的一個拷貝數組的相關部分,而不是讓您查看原始數據。

分配或就地修改單個結果花式索引操作正常工作(例如A[rows] += 1)。然而,修改鏈接索引表達式的結果,例如, A[rows][:, columns],將而不是如果第一個表達式使用奇特索引,則工作。原因是A[rows]生成副本,因此將A[rows][:, columns]加1不會影響A

如果您一次完成所有索引,則可以避免此問題。在某些時候,你可能嘗試過這樣的事情:

In [38]: A[rows, columns] += 1 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-38-7d2300f59d51> in <module>() 
----> 1 A[rows, columns] += 1 

ValueError: shape mismatch: objects cannot be broadcast to a single shape 

這裏numpy的蒙上你的指標到數組列表,然後嘗試broadcast他們到相同的形狀,因爲他們有不兼容的尺寸,其失敗。爲了使它成功,您可以將rows設置爲(n, 1)陣列,並將columns設置爲陣列,其中mn是單個行/列索引的數量。這樣,他們可以沿着尺寸1種尺寸擴大到大小(n, m),並用於索引A

索引與 None
r = np.array(rows) 
c = np.array(columns) 
A[r[:, None], c[None, :]] += 1 
print(A) 
# [[ 0. 0. 1. 1. 0. 0. 0. 0.] 
# [ 0. 0. 1. 1. 0. 0. 0. 0.] 
# [ 0. 0. 0. 0. 0. 0. 0. 0.] 
# [ 0. 0. 0. 0. 0. 0. 0. 0.] 
# [ 0. 0. 0. 0. 0. 0. 0. 0.] 
# [ 0. 0. 1. 1. 0. 0. 0. 0.] 
# [ 0. 0. 0. 0. 0. 0. 0. 0.] 
# [ 0. 0. 0. 0. 0. 0. 0. 0.]] 

是同樣的事情用np.newaxis - 它有插入的一個新的層面的影響尺寸1.

其實是有一個方便的功能,np.ix_,從一維的指標序列生成多維指標:

A = np.zeros((8, 8)) 
A[np.ix_(rows, columns)] += 1 
+0

我同意你的結果肯定比我更ele elegent ...但是,我想指出一個_can_使用高級索引更改'A'的元素請參閱[這裏](http://stackoverflow.com/a/15692289/4367286) – plonser

+0

@plonser這是真的,但只有當分配給單個索引表達式的結果時。如果第一組索引是一個切片或一個整數(即非花式索引),那麼賦值給鏈接索引的結果(例如'A [x] [y] = ...)。我會編輯我的答案,使區分更清晰。 –

0

您可以先使用itertool.product

import itertools 
coord = np.array(list(itertools.product(rows,columns))) 

讓所有的座標,然後採用先進的索引

A[tuple(coord.T)] += 1 

在其他的答案高級索引提到通常給出一個副本做到這一點。但是,如果正確處理它仍然有爭議here

+0

我同意,一個人必須小心advanc ed索引和副本...但是我的代碼工作正常,這就是爲什麼我不明白我已downvoted – plonser

4

rows需要是'列'向量,例如,

rows=[[0],[1],[5]] 
cols=[2,3] 
A[rows,cols]+=1 

有時候2階段的索引工作,A[rows][:,cols],但並非總是如此。特別是在這種情況下,rows不是切片。 A[rows]現在是副本,所以更改它不會更改A

索引這個塊有很多種方法。 plonser's使用product作品,雖然我很少看到它與numpy一起使用。

np.ix_是這樣一個方便的工具:

In [70]: np.ix_([0,1,5],[2,3]) 
Out[70]: 
(array([[0], 
     [1], 
     [5]]), array([[2, 3]])) 

np.newaxis也把一個行向量爲列:

rows=np.array([0,1,5]) 
cols=np.array([2,3]) 
A[rows[:,None],cols] 

列和行向量的這種配對工作,因爲numpy他們廣播給產生(3,2)指數數組。

itertools.product產生相同組索引,但作爲元組

In [80]: list(itertools.product([0,1,5],[2,3])) 
Out[80]: [(0, 2), (0, 3), (1, 2), (1, 3), (5, 2), (5, 3)] 
In [84]: tuple(np.array(list(itertools.product([0,1,5],[2,3]))).T) 
Out[84]: (array([0, 0, 1, 1, 5, 5]), array([2, 3, 2, 3, 2, 3]))