2015-09-22 77 views
3

說,一個有以下numpy的數組:如何一次從numpy數組中排除幾個範圍?

X = numpy.array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5]) 

現在,一個如何從X範圍X[0:2]X[6:8]X[12:14]一次,所以人會在結果X= [2, 2, 2, 4, 4, 4]獲取數組排除?

+0

這些範圍如何/在哪裏存儲? – Divakar

+1

我認爲你的意思是'X [0:3],X [6:9] .x [12:15]'? –

+0

您需要循環切片的其中一種方法。一種解決方案可以讓'np.r_'做到這一點,另一種解決方案重複使用'delete',另一種解決方案組合切片。 – hpaulj

回答

0

正是基於要保持間隔組成X ..

X = np.array(list(X[3:6]) + list(X[9:12])) 
+0

是你的'+'數組加入還是列表級聯? – hpaulj

+0

list concatenation。 –

+0

在這個問題中'X'是一個'numpy'數組,其中'+'是加法的。 – hpaulj

4

你可以使用np.r_到的範圍,組合成一維數組:

In [18]: np.r_[0:2,6:8,12:14] 
Out[18]: array([ 0, 1, 6, 7, 12, 13]) 

然後使用np.in1d創建在這些索引位置爲True的布爾數組:

In [19]: np.in1d(np.arange(len(X)), (np.r_[0:2,6:8,12:14])) 
Out[19]: 
array([ True, True, False, False, False, False, True, True, False, 
     False, False, False, True, True, False], dtype=bool) 

然後用~ to invert布爾數組:

In [11]: X = np.array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5]) 

In [12]: X[~np.in1d(np.arange(len(X)), (np.r_[0:2,6:8,12:14]))] 
Out[12]: array([1, 2, 2, 2, 3, 4, 4, 4, 5]) 

注意X[12:14]捕獲只有前兩個5的。剩下一個5,所以結果是array([1, 2, 2, 2, 3, 4, 4, 4, 5]),而不是array([1, 2, 2, 2, 3, 4, 4, 4])

Python中的切片範圍是半開間隔。包含左側索引,但正確的索引不包含。所以X[12:14]選擇X[12]X[13],但不是X[14]。有關Guido van Rossum對Python爲何使用半開區間的解釋,請參閱this post

要得到的結果[2, 2, 2, 4, 4, 4]你需要添加一個到右側(結尾)指數爲每個切片:

In [17]: X[~np.in1d(np.arange(len(X)), (np.r_[0:3,6:9,12:15]))] 
Out[17]: array([2, 2, 2, 4, 4, 4]) 
+0

除非我錯過了一些東西,我想你可以只寫'np.r_ [0:2,6:8,12:14]而不是'np.r_ [np.s_ [0:2,6:8] ,12:14]]'。 –

+0

@ajcr:哦!感謝您的改進。 – unutbu

+1

或者你可以讓'delete'爲你構建掩碼:'np.delete(X,np。r_ [0:3,6:9,12:15])' – hpaulj

1

您可以使用這樣的事情:

numbers = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5] 
exclude = set(range(0,2) + range(6,8) + range(12,14)) 
[n for n in numbers if n not in exclude] 

或:

[i for i in nums if i not in xrange(0,2) and i not in xrange(6,8) and i not in xrange(12,14)] 

結果:

[2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5] 
0

您可以撥打np.delete 3次,自@nneonneo在評論中表示,它不需要計算範圍偏移就可以反轉。 :

>>> np.delete(np.delete(np.delete(X,np.s_[12:14]),np.s_[6:8]),np.s_[0:2]) 
array([1, 2, 2, 2, 3, 4, 4, 4, 5]) 
+1

或者您可以從結尾開始刪除範圍,從而不需要計算範圍偏移量。 – nneonneo

+0

@nneonneo事實上,不錯的技巧,謝謝;-) – Kasramvd

+0

當給定切片(來自's_')時'刪除'只是將它想要保留的切片複製到新陣列。有效地,你的表達式連接'X [2:6],X [8:12],X [14:]'。 – hpaulj

1

在以@unutbu的答案,我建議np.delete評論。這裏有幾個計時

更大的測試序列:

In [445]: A=np.arange(1000) 

@ unutbu的回答是:

In [446]: timeit A[~np.in1d(np.arange(len(A)), (np.r_[10:50:3,100:200,300:350]))].shape 
1000 loops, best of 3: 454 µs per loop 

相同的索引列表,但使用np.delete - 大約3倍提速

In [447]: timeit np.delete(A,np.r_[10:50:3,100:200,300:350]).shape 
10000 loops, best of 3: 166 µs per loop 

但做一個簡單的布爾掩模更快。早些時候,我推斷,np.delete基本上做到這一點,但它必須有一些額外的開銷(包括用於處理多個維度的能力):

In [448]: %%timeit 
ind=np.ones_like(A,bool) 
ind[np.r_[10:50:3,100:200,300:350]]=False 
A[ind].shape 
    .....: 
10000 loops, best of 3: 71.5 µs per loop 

np.delete具有當輸入爲片,這可能比快了不同的策略布爾索引。但它一次只處理一個切片,因此@ Kasramvd顯示的嵌套刪除。我打算增加這個時間。

連接多個切片是另一種選擇。

np.r_也涉及到一個循環,但它只是在切片上。基本上它迭代切片,擴展每個作爲範圍,並連接它們。在我的最快的情況下,它的運行時間的2/3負責:

In [451]: timeit np.r_[10:50:3,100:200,300:350] 
10000 loops, best of 3: 41 µs per loop 
In [453]: %%timeit x=np.r_[10:50:3,100:200,300:350] 
ind=np.ones_like(A,bool) 
ind[x]=False 
A[ind].shape 
    .....: 
10000 loops, best of 3: 24.2 µs per loop 

嵌套刪除有相當不錯的表現:

In [457]: timeit np.delete(np.delete(np.delete(A,slice(300,350)), 
    slice(100,200)),slice(10,50,3)).shape 
10000 loops, best of 3: 108 µs per loop 

np.delete,當給定切片刪除,將slice複製到結果數組(delete塊之前和之後的塊)。我可以通過連接幾個切片來近似。我在這裏使用第一塊的刪除操作,而不是花時間寫一個純副本。它仍然比最好的布爾掩碼錶達式更快。

In [460]: timeit np.concatenate([np.delete(A[:100],slice(10,50,3)), 
    A[200:300],A[350:]]).shape 
10000 loops, best of 3: 65.7 µs per loop 

我可以用這個切片取下delete,雖然10:50範圍內的順序弄亂了。我懷疑這是,理論上,最快:

In [480]: timeit np.concatenate([A[:10], A[11:50:3], A[12:50:3], 
    A[50:100], A[200:300], A[350:]]).shape 
100000 loops, best of 3: 16.1 µs per loop 

一個重要的注意 - 這些方案正在與非重疊片測試。有些可能與重疊一起工作,有些可能不會。