用另一个数组切片numpy数组

use*_*315 9 python arrays numpy slice

我有一个大的一维整数数组,我需要取下切片.这是微不足道的,我只是这样做a[start:end].问题是我需要更多这些切片.a[start:end]如果start和end是数组,则不起作用.For循环可以用于此,但我需要它尽可能快(这是一个瓶颈),所以欢迎本地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)
Run Code Online (Sandbox Code Playgroud)

并需要以某种方式使它成为这个:

[[1], [5, 6, 7, 8, 9], [7, 8]] 
Run Code Online (Sandbox Code Playgroud)

sen*_*rle 7

这可以(几乎?)纯粹numpy使用蒙面数组和步长技巧完成.首先,我们创建我们的面具:

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

或者更简单:

>>> mask = (indices < start[:,None]) | (indices >= end[:,None])
Run Code Online (Sandbox Code Playgroud)

False对于那些>=指向起始值和<结束值的索引,掩码(即未屏蔽的值).(使用None(aka 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)
Run Code Online (Sandbox Code Playgroud)

现在我们必须使用以下方法拉伸数组以适合蒙版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)
Run Code Online (Sandbox Code Playgroud)

这看起来像一个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)
Run Code Online (Sandbox Code Playgroud)

这与你要求的不完全相同,但它应该表现得相似.


seb*_*erg 5

没有numpy方法来做到这一点.请注意,由于它是不规则的,所以它只是一个数组/切片列表.但是我想为所有(二进制)添加ufuncs几乎所有函数都在numpy中(或者它们至少基于它们),有一个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. ])
Run Code Online (Sandbox Code Playgroud)

编辑:由于你的切片重叠,我会补充说这也没关系:

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

这里[::2]应该没什么大不了的,因为重叠切片没有真正的额外工作.

此处还有一个问题就是切片stop==len(a).必须避免这种情况.如果你只有一个切片,你可以做reductions = reductions[:-1](如果它是最后一个),但否则你只需要附加一个值a来欺骗reduceat:

 a = np.concatenate((a, [0]))
Run Code Online (Sandbox Code Playgroud)

因为在末尾添加一个值无关紧要,因为无论如何都要处理切片.


tim*_*day 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))
Run Code Online (Sandbox Code Playgroud)

让你:

[array([1], dtype=int16), array([5, 6, 7, 8, 9], dtype=int16),  array([7, 8], dtype=int16)]
Run Code Online (Sandbox Code Playgroud)

按要求。