2017-09-08 114 views
2

我有一個尺寸爲N的任意數量的ndarray A。我想創建一個數組B的元組(數組或列表),其中每個元組中的第一個N元素是索引,最後一個元素是A中該索引的值。獲取NumPy中的ndarray索引和值

例如:

A = array([[1, 2, 3], [4, 5, 6]]) 

然後

B = [(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)] 

什麼是爲此在與NumPy沒有for循環最好的/最快的方法是什麼?

回答

2

如果你有Python 3的一個非常簡單的(和適度快速)的方法是(使用np.ndenumerate):

>>> import numpy as np 
>>> A = np.array([[1, 2, 3], [4, 5, 6]]) 
>>> [(*idx, val) for idx, val in np.ndenumerate(A)] 
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)] 

,如果你希望它爲Python 3和Python兩種工作這將是一個有點不同2,因爲Python 2不允許在元組文字內部進行迭代解包。但是你可以使用元組串聯(加):

>>> [idx + (val,) for idx, val in np.ndenumerate(A)] 
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)] 

如果你想要從NumPy的完全留倒不如用np.mgrid創建索引:

>>> grid = np.mgrid[:A.shape[0], :A.shape[1]] # indices! 
>>> np.stack([grid[0], grid[1], A]).reshape(3, -1).T 
array([[0, 0, 1], 
     [0, 1, 2], 
     [0, 2, 3], 
     [1, 0, 4], 
     [1, 1, 5], 
     [1, 2, 6]]) 

然而這將需要一個循環將其轉換爲一個元組列表... ...但它會很容易將其轉換爲列表清單:

>>> np.stack([grid[0], grid[1], A]).reshape(3, -1).T.tolist() 
[[0, 0, 1], [0, 1, 2], [0, 2, 3], [1, 0, 4], [1, 1, 5], [1, 2, 6]] 

元組的列表,也可以不可見for -loop:

>>> list(map(tuple, np.stack([grid[0], grid[1], A]).reshape(3, -1).T.tolist())) 
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)] 

即使沒有明顯的for -loop的tolistlisttuplemap都隱藏在一個for -loop Python層。


對於你需要改變後者的做法有點arbitary維數組:

coords = tuple(map(slice, A.shape)) 
grid = np.mgrid[coords] 

# array version 
np.stack(list(grid) + [A]).reshape(A.ndim+1, -1).T 
# list of list version 
np.stack(list(grid) + [A]).reshape(A.ndim+1, -1).T.tolist() 
# list of tuple version 
list(map(tuple, np.stack(list(grid) + [A]).reshape(A.ndim+1, -1).T.tolist())) 

ndenumerate方法將任何尺寸的陣列,而變化,並根據我的計時只有2-3倍慢。

+0

你剛剛加入到我的知識銀行 – piRSquared

+0

@MSeifert感謝,但我尋找的東西沒有一個for循環。因爲這些矩陣可能會很大,Python的for循環很慢。你認爲這是可能的嗎? (只有Python3需要工作) –

+0

@SiaRezaei如果你想要一個元組列表,請不要使用。如果一個數組沒有問題,那麼看看我的答案的第二部分('mgrid')。 – MSeifert

1

你也可以用np.ndindex來做到這一點,儘管@ Mseifert的方法在時間和簡潔性上是無與倫比的。這裏唯一的循環是用實際值壓縮座標發生器。 (同對方的回答。)

def tuple_index(a): 
    indices = np.ndindex(*a.shape) 
    return [(*i, j) for i, j in zip(indices, a.flatten())] 

print(tuple_index(a)) 
[(0, 0, 1), (0, 1, 2), (0, 2, 3), (1, 0, 4), (1, 1, 5), (1, 2, 6)]