2016-03-30 173 views
2

我得到了一個嚴格增加長度爲m的「截斷」值和一個熊貓系列值的一個numpy數組(認爲索引並不重要,這可以被轉換爲長度爲n的值的數組)。 我需要想出一個有效的方式來吐出一個長度爲m的向量,這個向量的數量是熊貓系列中元素數量少於「截斷」數組的第j個元素的數量。數組元素的數組少於Python中每個元素的截斷數組

我可以通過列表迭代器做到這一點:

output = array([(pan_series < cutoff_val).sum() for cutoff_val in cutoff_ar]) 

,但是,我想知道是否有任何的方式來做到這一點,利用更多numpy的的神奇速度,因爲我必須這樣做了好幾次在多個循環內部,它使我的電腦不斷變化。

謝謝!

回答

2

這是你在找什麼?

In [36]: a = np.random.random(20) 

In [37]: a 
Out[37]: 
array([ 0.68574307, 0.15743428, 0.68006876, 0.63572484, 0.26279663, 
     0.14346269, 0.56267286, 0.47250091, 0.91168387, 0.98915746, 
     0.22174062, 0.11930722, 0.30848231, 0.1550406 , 0.60717858, 
     0.23805205, 0.57718675, 0.78075297, 0.17083826, 0.87301963]) 

In [38]: b = np.array((0.3,0.7)) 

In [39]: np.sum(a[:,None]<b[None,:], axis=0) 
Out[39]: array([ 8, 16]) 

In [40]: np.sum(a[:,None]<b, axis=0) # b's new axis above is unnecessary... 
Out[40]: array([ 8, 16]) 

In [41]: (a[:,None]<b).sum(axis=0) # even simpler 
Out[41]: array([ 8, 16]) 

時序總是好評(爲一個稍長,2E6元件陣列)

In [47]: a = np.random.random(2000000) 

In [48]: %timeit (a[:,None]<b).sum(axis=0) 
10 loops, best of 3: 78.2 ms per loop 

In [49]: %timeit np.searchsorted(a, b, 'right',sorter=a.argsort()) 
1 loop, best of 3: 448 ms per loop 

對於較小的陣列

In [50]: a = np.random.random(2000) 

In [51]: %timeit (a[:,None]<b).sum(axis=0) 
10000 loops, best of 3: 89 µs per loop 

In [52]: %timeit np.searchsorted(a, b, 'right',sorter=a.argsort()) 
The slowest run took 4.86 times longer than the fastest. This could mean that an intermediate result is being cached. 
10000 loops, best of 3: 141 µs per loop 

編輯

Divakar說,事情可能是lenghty b期不同,讓我們來看看

In [71]: a = np.random.random(2000) 

In [72]: b =np.random.random(200) 

In [73]: %timeit (a[:,None]<b).sum(axis=0) 
1000 loops, best of 3: 1.44 ms per loop 

In [74]: %timeit np.searchsorted(a, b, 'right',sorter=a.argsort()) 
10000 loops, best of 3: 172 µs per loop 

確實完全不同!謝謝你提醒我的好奇心。

可能OP應該測試他的使用案例,關於截斷序列還是非常長的樣本?哪裏有餘額?


編輯#2

我在時機做了一個軼事,我忘了axis=0參數.sum() ...

我編輯的時序與更正聲明,並且,當然,更正的時機。我很抱歉。

+0

廣播魔術 – gboffi

+1

我愛廣播呢!但是,你必須嘗試一個更大的'b',而不是僅僅考慮2個元素。 – Divakar

+0

@Divakar你是對的!我對我的帖子做了修改。 – gboffi

2

您可以使用np.searchsorted一些NumPy magic -

# Convert to numpy array for some "magic" 
pan_series_arr = np.array(pan_series) 

# Let the magic begin! 
sortidx = pan_series_arr.argsort() 
out = np.searchsorted(pan_series_arr,cutoff_ar,'right',sorter=sortidx) 

說明

您爲每個 元素cutoff_ar執行[(pan_series < cutoff_val).sum() for cutoff_val in cutoff_ar]即我們數是比較小pan_series元素的數量它。現在np.searchsorted,我們正在尋找cutoff_ar被放入排序pan_series_arr,並獲得這樣的位置的指數,與cutoff_ar中的當前元素位於'right'的位置相比較。這些指數基本上代表當前cutoff_ar元素以下的pan_series元素的數量,因此給我們提供了我們期望的輸出。

採樣運行

In [302]: cutoff_ar 
Out[302]: array([ 1, 3, 9, 44, 63, 90]) 

In [303]: pan_series_arr 
Out[303]: array([ 2, 8, 69, 55, 97]) 

In [304]: [(pan_series_arr < cutoff_val).sum() for cutoff_val in cutoff_ar] 
Out[304]: [0, 1, 2, 2, 3, 4] 

In [305]: sortidx = pan_series_arr.argsort() 
    ...: out = np.searchsorted(pan_series_arr,cutoff_ar,'right',sorter=sortidx) 
    ...: 

In [306]: out 
Out[306]: array([0, 1, 2, 2, 3, 4]) 
+0

這很好,我現在在我的代碼中多次使用了搜索排序。但是,對於問題中引用的任務,我還需要爲逆向排序的數組做類似的操作。很顯然,這可以使用分類器arg來完成,但是在這種情況下,只需使用gboffi的解決方案就可以實現更清潔。無論哪種方式,謝謝一噸! – MHankin