2017-02-22 92 views
0

這是靈感來自this的帖子。numpy高級索引:透明地優化範圍?

考慮一個函數f,該函數返回用戶通常用來索引其他數組的索引的第一個np.ndarrayidx。進一步假定f經常出現的結果是歸還全部法律索引。在鏈接的帖子中,建議這是由f返回slice(None)而不是np.arange(maxind)

由於高級索引是有代價的

>>> a = np.arange(1_000_000) 
>>> direct = lambda: np.sum(a[:]) 
>>> indirect = lambda: np.sum(a[a]) 
>>> timeit(direct, number=100) 
0.07656216900795698 
>>> timeit(indirect, number=100) 
0.2885982050211169 

這看起來像是一見鍾情合理的優化。

不幸的是,它不是「正確的」。想象一下,例如,用戶想要創建idx的單熱表示。要去這樣做的一個簡單的方法是

result = np.zeros((k, maxind), dtype=int) 
result[np.arange(k), idx] = 1 

這打破如果np.arange(maxind)slice(None)取代(這將填補result與那些整)。

所以我的問題是:一,可以有自己的蛋糕,在這裏吃,即:

有什麼f可以返回忠實模仿的np.arange(maxind)語義,同時避免可能的高級索引在哪裏?

由於我差點辭職,答案是沒有:

什麼是未來最好的事情?

也許會返回一個「增強np.s_」,即一個工程__getitem__

class smart_idx: 
    def __init__(self, n): 
     self.n = n 
    def __getitem__(self, idx): 
     idx = idx if isinstance(idx, tuple) else (idx,) 
     if idx: 
      count = idx.count('X') 
      need_adv = count > 1 
      if count == 1: 
       for i in idx: 
        if not isinstance(i, slice) and i != Ellipsis: 
         need_adv = True 
         break 
      repl = np.arange(self.n) if need_adv else slice(None) 
      return tuple(repl if i == 'X' else i for i in idx) 
     return slice(None) 

的用戶將不得不使用它像

data[idx[3, 4:9, 'X', [1,3,2,6]]] 
data[idx['X', ..., :4:-1]] 
data[idx[]] 

__getitem__,檢測所述先進索引將決定在其他兩個實施例與第一np.arange(4)並用slice(None)替換「X」。

但是這相當笨拙,更不用說增加的開銷可能會吃掉我們獲得的任何速度。

是否有簡單的策略?

+2

描述如果'idx'是一個列表/數組你是否要使用要得到高級索引,不管切片或arange爲其他索引。在'[arange ...,idx]'索引中,它從每一行中選取一個項目。在扁平數組上索引更快,但是通過計算扁平索引的成本來平衡。 – hpaulj

+0

@hpaulj「如果idx是一個列表/數組,您將獲得高級索引,無論」。這就是爲什麼我們試圖在有意義的特殊情況下(基本上'idx == np.arange(maxind)'+沒有其他高級索引)用'slice(None)'替換'idx'。 –

+0

@hpaulj試圖說的是,無論「idx」是什麼,當您爲> 1D(例如2D中的任意位置)編制索引時,例如, '[something ...,idx]'無論'idx'可能是什麼,它都是高級索引,除非'something'和'idx'都是'slice'對象,但這種情況永遠不會模仿你想要的行爲。 –

回答

0
In [104]: x=np.arange(12).reshape(4,3) 

這些看起來是一樣的,雖然一個是一個副本,另一種觀點:

In [107]: x[np.arange(0,4,2),:] 
Out[107]: 
array([[0, 1, 2], 
     [6, 7, 8]]) 
In [108]: x[0:4:2,:] 
Out[108]: 
array([[0, 1, 2], 
     [6, 7, 8]]) 

但是,如果第二個指標是一個數組,該arangeslice是不可替代的。

In [109]: idx=np.array([0,2]) 
In [110]: x[np.arange(0,4,2),idx] 
Out[110]: array([0, 8]) 
In [111]: x[0:4:2,idx] 
Out[111]: 
array([[0, 2], 
     [6, 8]]) 

要匹配切片版本,我必須添加一個維度到arange

In [113]: x[np.ix_(np.arange(0,4,2),idx)] 
Out[113]: 
array([[0, 2], 
     [6, 8]]) 
In [114]: x[np.arange(0,4,2)[:,None],idx] 
Out[114]: 
array([[0, 2], 
     [6, 8]]) 

我不知道產生Out[110]的片段表達式。

所以除了用slice替換arange之外,我們需要注意高級索引數組是如何相互廣播的,以及切片意味着什麼廣播。

有了3個或更多的維度,混合切片和高級索引會變得更加複雜,因爲在https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#combining-advanced-and-basic-indexing