2015-09-22 49 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 

一个重要的注意 - 这些方案正在与非重叠片测试。有些可能与重叠一起工作,有些可能不会。