2012-09-25 34 views
9

我有一个大的一维整数数组,我需要切片。这是微不足道的,我只是做a[start:end]。问题是我需要更多这些切片。如果开始和结束是数组,则a[start:end]不起作用。 For循环可以用于此,但我需要它尽可能快(这是一个瓶颈),所以本地numpy解决方案将受到欢迎。用另一个数组切片numpy数组

为了进一步说明,我有这样的:

a = numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], numpy.int16) 
start = numpy.array([1, 5, 7], numpy.int16) 
end = numpy.array([2, 10, 9], numpy.int16) 

而且需要以某种方式使之变成这样:

[[1], [5, 6, 7, 8, 9], [7, 8]] 
+0

我有一个很难理解什么'start'和'end'有与此相关。另外,我不认为你可以完全用numpy做这个,因为numpy数组需要是矩形的。 – mgilson

+0

YOu可能会尝试将起始值作为列表中的元组。 – Keith

+0

因为在这里似乎没有规范的numpy解决方案,所以如果您需要更多的想法,您可能希望事后添加您实际做的事情,以及切片是否具有某些特殊属性。 – seberg

回答

1

这不是一个“纯” numpy的解决方案(尽管@ mgilson的评论笔记,很难看到不规则的输出如何能成为一个numpy的阵列),但:

a = numpy.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], numpy.int16) 
start = numpy.array([1, 5, 7], numpy.int16) 
end = numpy.array([2, 10, 9], numpy.int16) 

map(lambda range: a[range[0]:range[1]],zip(start,end)) 

让你:

[array([1], dtype=int16), array([5, 6, 7, 8, 9], dtype=int16), array([7, 8], dtype=int16)] 

根据需要。

5

没有numpy的方法来做到这一点。请注意,由于它是不规则的,它只会是数组/片的列表。不过,我想补充一点,对于几乎所有numpy函数(二进制)ufuncs(或者至少基于它们),都有reduceat方法,这可能会帮助您避免实际创建切片列表,因而,如果片为小,加快计算过:

In [1]: a = np.arange(10) 

In [2]: np.add.reduceat(a, [0,4,7]) # add up 0:4, 4:7 and 7:end 
Out[2]: array([ 6, 15, 24]) 

In [3]: np.maximum.reduceat(a, [0,4,7]) # maximum of each of those slices 
Out[3]: array([3, 6, 9]) 

In [4]: w = np.asarray([0,4,7,10]) # 10 for the total length 

In [5]: np.add.reduceat(a, w[:-1]).astype(float)/np.diff(w) # equivalent to mean 
Out[5]: array([ 1.5, 5. , 8. ]) 

编辑:既然你的片重叠,我会补充说,这是太正常:

# I assume that start is sorted for performance reasons. 
reductions = np.column_stack((start, end)).ravel() 
sums = np.add.reduceat(a, reductions)[::2] 

[::2]应该没有大通常在这里处理,因为重叠切片没有真正的额外工作。

此外还有一个问题,其中stop==len(a)切片。这必须避免。如果你恰好有一个切片有了它,你可以只是做reductions = reductions[:-1](如果它的最后一个),但除此之外,你只需要一个值追加到a诱骗reduceat

a = np.concatenate((a, [0])) 

由于增加一个价值无论如何,由于你在切片上工作,最后并不重要。

7

这可以(几乎?)在纯numpy中使用掩码数组和步进技巧完成。首先,我们创建面膜:

>>> indices = numpy.arange(a.size) 
>>> mask = ~((indices >= start[:,None]) & (indices < end[:,None])) 

或者更简单地说:

>>> mask = (indices < start[:,None]) | (indices >= end[:,None]) 

的掩码False(即值没有被屏蔽),对于那些>=的起始值和<年底价值指数。 (切片None(又名numpy.newaxis)增加了一个新的维度,使广播。)现在我们的面具看起来是这样的:

>>> mask 
array([[ True, False, True, True, True, True, True, True, True, 
     True, True, True], 
     [ True, True, True, True, True, False, False, False, False, 
     False, True, True], 
     [ True, True, True, True, True, True, True, False, False, 
     True, True, True]], dtype=bool) 

现在我们要舒展阵列使用stride_tricks以适应面具:

>>> as_strided = numpy.lib.stride_tricks.as_strided 
>>> strided = as_strided(a, mask.shape, (0, a.strides[0])) 
>>> strided 
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 
     [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 
     [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]], dtype=int16) 

这看起来像一个3x12阵列,但同时每一行分记忆。现在,我们可以将它们组合成一个屏蔽数组:

>>> numpy.ma.array(strided, mask=mask) 
masked_array(data = 
[[-- 1 -- -- -- -- -- -- -- -- -- --] 
[-- -- -- -- -- 5 6 7 8 9 -- --] 
[-- -- -- -- -- -- -- 7 8 -- -- --]], 
      mask = 
[[ True False True True True True True True True True True True] 
[ True True True True True False False False False False True True] 
[ True True True True True True True False False True True True]], 
     fill_value = 999999) 

这是不太一样的,你问什么,但它应该表现相似。

+0

很酷的想法,知道这种方法是否适用于他的用例(在较新的numpy版本上)会很有趣。目前的那个缺少''where''关键字到'ufunc's(1.7也没有它的缩减)。这意味着你的步幅技巧阵列将被复制到完整版本中,几乎可以处理任何事情... – seberg

+0

Mmh,'ufunc'中'where'缺少*无法解决手头的问题,和'np.ma'通常会避免副本......这实际上并不是使用困扰我的'np.ma'(很酷的想法本身)的问题,而是它可能无法通过循环或列表理解来构建幻灯片(仅仅是因为数组大小加倍)......不过,这很有趣,+1 –

+0

@PierreGM,是的,我只是想到了那里的还原函数,但是在某些时候这些可能会被想要...... – seberg

0

类似的解决方案,如timday。类似的速度:

a = np.random.randint(0,20,1e6) 
start = np.random.randint(0,20,1e4) 
end = np.random.randint(0,20,1e4) 

def my_fun(arr,start,end): 
     return arr[start:end] 

%timeit [my_fun(a,i[0],i[1]) for i in zip(start,end)] 
%timeit map(lambda range: a[range[0]:range[1]],zip(start,end)) 

100 loops, best of 3: 7.06 ms per loop 100 loops, best of 3: 6.87 ms per loop

0

如果你想在一个行,这将是:

x=[list(a[s:e]) for (s,e) in zip(start,end)] 
相关问题