我有一个numpy数组:
ar = np.array([True, False, True, True, True])
如果最后一个元素为True,我想删除数组末尾的所有连续true元素。例如,
magic_func(ar) => [True, False]
如果ar = [True, False, True, False, True]
。然后
magic_func(ar) => [True, False, True, False]
如果ar = [True, False, False]
,则该函数不执行任何操作,因为最后一个元素为False
python中是否有一个内衬来执行此操作?使用numpy库或其他东西
答案 0 :(得分:1)
这一行函数应该可以工作,但看起来很讨厌,可能效率不高哈哈。基本上,我们的目标是找到最合适的False
并在False
def magic_func(a):
return a[:len(a)-np.where(a[::-1]==False)[0][0]] if np.where(a[::-1]==False)[0].size>0 else a[:0]
>>> a = np.array([False, True, True, True, True])
>>> magic_func(a)
array([False], dtype=bool)
答案 1 :(得分:1)
这对我来说有点太神奇了,但它似乎确实很有效:
>>> ar = np.array([True, False, True, True, True])
>>> ar[np.bitwise_or.accumulate(~ar[::-1])[::-1]]
array([ True, False], dtype=bool)
要理解发生了什么,首先我们否定数组,将True
转换为False
s而反之,然后我们反转顺序,然后我们累积OR的结果-ing数组:这将是False
直到第一个True
,之后将保持True
。反转这个数组,我们有一个布尔索引数组,可以摆脱所有尾随的True
。
答案 2 :(得分:1)
像这样使用itertools.dropwhile
和np.fromiter
。
from itertools import dropwhile
np.fromiter(dropwhile(lambda x: x, ar[::-1]), dtype=bool)[::-1]
修改强>
这是更快的方法。(只需使用itertools.takewhile
)
from itertools import takewhile
ar[:-sum(1 for i in takewhile(lambda x: x, reversed(ar)))]
时间:
ar = np.array([True, False, True, True, True])
#mine
%timeit ar[:-sum(1 for i in takewhile(lambda x: x, reversed(ar)))]
1000000 loops, best of 3: 1.84 us per loop
#mine
%timeit np.fromiter(dropwhile(lambda x: x, ar[::-1]), dtype=bool)[::-1]
100000 loops, best of 3: 2.93 us per loop
#@Jaime
%timeit ar[np.bitwise_or.accumulate(~ar[::-1])[::-1]]
100000 loops, best of 3: 3.63 us per loop
#@askewchan
%timeit ar[:len(ar)-np.argmin(ar[::-1])]
100000 loops, best of 3: 6.24 us per loop
#@xbb
%timeit ar[:len(ar)-np.where(ar[::-1]==False)[0][0]] if np.where(ar[::-1]==False)[0].size>0 else ar[:0]
100000 loops, best of 3: 7.61 us per loop
PS:
这是无魔法的功能。
def no_magic_func(ar):
for i in xrange(ar.size-1, -1, -1):
if not ar[i]:
return ar[:i+1]
return ar[0:0]
时间:
ar = np.array([True, False, True, True, True])
%timeit no_magic_func(ar)
1000000 loops, best of 3: 954 ns per loop
答案 3 :(得分:1)
编写一个节省时间的单行代码并不容易,但这里的代码基于askewchan删除的答案:
argmin = ar[::-1].argmin()
result = np.array([], dtype=bool) if ar[argmin] else ar[:len(ar)-argmin]
对于ar = np.full(1000000, True, dtype=bool)
来说,比Jaime的基于Numpy的解决方案快两倍,然后是:
ar[-10] = False
,ar[10] = False
(这是代表最佳和最差情况的两种情况)。但是,就像在Jaime的解决方案中一样,查找最后False
使NumPy(1.8.1)的位置通过整个数组,这是低效的。但是,原则上,Numpy不必对argmin()
执行此操作,因为它可能会在遇到的第一个False
处停止。
这对我来说就像使用最好的Numpy 来执行执行剪切给出最终数组的解决方案。原则上,NumPy也可以非常有效地找到切割位置。
答案 4 :(得分:0)
编辑:更新实现以处理numpy数组中缺少.pop()
def chop_array(ar, condition):
i = len(ar)
while (ar[i - 1] == condition and i > 0):
i = i - 1
return ar[0:i]
chop_array([True, False, True, False, True], True)
答案 5 :(得分:0)
这里几乎是一行(对于结果不为空的情况,一行),这应该非常快(只查看必要的元素):
def magic_func(arr):
try:
# The first element starting from the end which differs from the last one sets the limit:
return arr[:next(index for index in xrange(len(arr)-1, -1, -1) if arr[index] == False)+1]
except StopIteration:
return numpy.empty_like(arr)
next()
只返回第一个元素False
的索引。最后的+1
用于将其包含在结果中。 StopIteration
适用于所有元素均为True的情况。
一个真正的单行稍微慢一些(对索引进行额外测试,产生的是所有元素而不是False
):
ar[:next(index for index in xrange(len(ar)-1, -2, -1) if index == -1 or ar[index] == False)+1]
它相对清晰:从最后到开头扫描潜在最后一个元素的索引,如果没有找到False或者找到一个False,我们就会停止。
请注意,此解决方案的缺点是在不使用Numpy的情况下循环遍历原始数组(如果数组末尾有很多True值,则这不好)。它比许多其他解决方案有一些优势:
False
之前查看) - 但是,再次使用较慢的(非Numpy) )方法。因此,当数组末尾的True值数量很少时,此解决方案非常快。