簡體   English   中英

如何一次從numpy數組中排除幾個范圍?

[英]How to exclude few ranges from numpy array at once?

說,有一個以下 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] ?

您可以使用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)

然后使用~反轉布爾數組:

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 為何使用半開區間的解釋。

要獲得結果[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])

你可以使用這樣的東西:

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]

在對@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有不同的策略,這可能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 ,當給定要刪除的切片時,將切片復制到結果數組(刪除塊之前和之后的塊)。 我可以通過連接幾個切片來近似。 我在這里通過對第一個塊使用刪除來作弊,而不是花時間寫一個純副本。 它仍然比最好的布爾掩碼表達式要快。

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

一個重要的警告 - 這些替代品正在使用非重疊切片進行測試。 有些可能會重疊,有些可能不會。

只需根據您要保留的間隔組合 X..

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

您可以調用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])

不確定這是否有幫助,但如果每個范圍的輸出都是唯一的,您可以按范圍計數進行索引。

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

A = np.unique(X)

Out[79]: array([1, 2, 3, 4, 5])

在這里,我們希望保持第二和第四范圍。

X = X[(X==A[1])|(X==A[3])]  

Out[82]: array([2, 2, 2, 4, 4, 4])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM