2014-03-13 262 views
2

我需要在兩個維度上切分中等大小的2d Numpy陣列。作爲實例,加速Numpy陣列切片

import numpy as np 
X = np.random.normal(loc=0, scale=1, size=(3000, 100)) 

從該陣列中,我需要選擇大量的行和相當小數量的列,例如

row_idx = np.random.random_integers(0, 2999, 2500) 
col_idx = np.random.random_integers(0, 99, 10) 

現在,我這樣做是通過以下命令:

X.take(col_idx, axis=1).take(row_idx, axis=0) 

這需要我的電腦上大約115μs。問題是我需要每次運行數百萬次執行此步驟。

你是否看到有機會加速這個速度?

編輯(附加信息): 我有一個矩陣X是nxk。這n行包含1xk向量。 有三組:活動組(V),左組(L)和右組(R)。此外,還有係數v0和v。我需要計算此數量:http://goo.gl/KNoSl3(對不起,我無法發佈圖像)。問題中的公式選擇左(右)集中的所有X行以及活動集中的所有列。

編輯2

我發現了另一個小的改進。

X.take(col_idx, axis=1, mode='clip').take(row_idx, axis=0, mode='clip') 

有點快(我的機器上大概是25%)。

+0

'take()'方法需要將所選行復制一列。你應該調整你的算法來製作這個不需要的東西。我們無法告訴你如何在沒有進一步的背景下做到這一點。 –

+0

你的指數多久改變一次? – Daniel

+0

對於幾十個觀察值,行索引保持不變(更確切地說:我有k個變量,這些變量分爲活動集和非活動集,我需要檢查哪個變量是非活動集最合適 - 即行索引保持不變不變,只要我檢查非活動集中的變量) – BayerSe

回答

0

你可以使用二維看中索引:

X[row_idx,col_idx[:,None]] 

但是,使用你的方法需要1毫秒〜我的機器上,VS〜300US。

除非您有關於row_idxcol_idx中的值的其他信息,否則似乎您的方法是您可以做的最好的方法。

1

讓我們做一些事情,我們做一個指數的一維數組,滿足我們的n維網格的條件。

def make_multi_index(arr, *inds): 
    tmp = np.meshgrid(*inds, indexing='ij') 
    idx = np.vstack([x.ravel() for x in tmp]) 
    return np.ravel_multi_index(idx, X.shape) 

使用您的測試陣列和原來的情況下,以供參考:

%timeit X.take(col_idx, axis=1).take(row_idx, axis=0) 
10000 loops, best of 3: 95.4 µs per loop 

讓我們使用這個功能來構建指數,追究他們,然後用取來回報您所需的輸出:

inds = make_multi_index(X, row_idx, col_idx) 
tmp = np.take(X,inds).reshape(row_idx.shape[0], col_idx.shape[0]) 

np.allclose(tmp, X.take(col_idx, axis=1).take(row_idx, axis=0)) 
Out[128]: True 

因此,建立我們的指數,並保持它們似乎工作,現在的時機:

%timeit make_multi_index(X, row_idx, col_idx) 
1000 loops, best of 3: 356 µs per loop 

%timeit np.take(X,inds).reshape(row_idx.shape[0], col_idx.shape[0]) 
10000 loops, best of 3: 59.9 µs per loop 

因此,它發生的並不是非常好 - 這可能會得到更好的維度,你想從中取得更好。無論如何,如果您保留這些索引超過10-15次迭代,它可以幫助一些或如果您添加一個額外的維度,並同時採取所有非活動的數據集。

+0

這聽起來很有希望。我看我是否可以利用這種方法,也許有一些方法可以最小化索引更改的數量。謝謝! – BayerSe