2017-10-19 50 views
4

我有一个numpy的二进制数组是这样的:如何在每个人的左边的numpy的数组数零的个数

Array A = [1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0] 

我想看看有多少0在每个左边是有1,并且在其它阵列看起来像这样对这个这个例子返回它:

nb_1s = [0, 0, 1, 2, 2, 5] 

有在左侧没有0为两个第一1S所以阵列的第一两个数字是0等等......

I K现在首先我必须启动与1的个数阵列,我的数组:

def give_zeros(binary_array): 
    binary_array = np.asarray(binary_array) 
    nb_zeros = np.zeros(binary_array.sum()) 


    return nb_zeros 

但我不知道如何来算零的个数。我应该用'nditer'在for循环中迭代吗?它看起来并不高效,因为我将不得不在非常大的数组上运行此函数。

你有什么想法吗? 谢谢。

+0

不应该认为是:'[0,0,1,1,0,3]'? – Divakar

+0

计数是否累计? – alvas

+0

是计数是累积的,最后1在其左相邻3个零,加上1秒 – user2505650

回答

3

下面是从的1s指数范围阵列的分化量化的方式 -

def leftzeros_count(a): 
    idx = np.flatnonzero(a!=0) 
    return idx - np.arange(len(idx)) 

样品试验 -

In [298]: a = np.array([1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0]) 

In [299]: leftzeros_count(a) 
Out[299]: array([0, 0, 1, 2, 2, 5]) 

In [300]: a = np.array([0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0]) 

In [301]: leftzeros_count(a) 
Out[301]: array([1, 1, 2, 3, 3, 6]) 

In [302]: a = np.array([0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1]) 

In [303]: leftzeros_count(a) 
Out[303]: array([ 1, 1, 2, 3, 3, 6, 10]) 

运行测试

对于时机,让瓷砖给定的样本大量的时间和时间的量化方法 -

In [7]: a = np.array([1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0]) 

In [8]: a = np.tile(a,100000) 

# @Eric Duminil's soln 
In [9]: %timeit (a == 0).cumsum()[a > 0] 
100 loops, best of 3: 10.9 ms per loop 

# Proposed in this post 
In [10]: %timeit leftzeros_count(a) 
100 loops, best of 3: 3.71 ms per loop 
+0

您的回答,我想答案这个数组:[1,0,0,1,1,1,0,0,0,0,1,0,0,1,0],但函数返回:[2,4,4,4,8, 10],它应该是:[0,2,2,6,8] – user2505650

+0

@ user2505650请检查编辑。我已经更新了一个新的方法。 – Divakar

+0

在'nonzero'之前直接使用'nonzero'没有'flatnonzero'调用'ravel'会更好。 – alvas

2

在非矢量化方式:

>>> x = [1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0] 
>>> c, y = 0, [] 
>>> for i in x: 
...  if i == 1: 
...   y.append(c) 
...  else: 
...   c += 1 
... 
>>> y 
[0, 0, 1, 2, 2, 5] 

对于矢量化的解决方案,请参阅@ Divakar的回答是:

numpy,先找到非零指数,与np.nonzero()

>>> np.nonzero(x)[0] 
array([ 0, 1, 3, 5, 6, 10]) 

然后减去具有索引的长度的范围内的数组:

>>> idx = np.nonzero(x)[0] 
>>> np.arange(len(idx)) 
array([0, 1, 2, 3, 4, 5]) 
>>> np.nonzero(x)[0] - np.arange(len(idx)) 
array([0, 0, 1, 2, 2, 5]) 

>>> np.arange(x.count(1)) 
array([0, 1, 2, 3, 4, 5]) 
>>> np.nonzero(x)[0] - np.arange(x.count(1)) 
array([0, 0, 1, 2, 2, 5]) 
+0

是后2个0,虽然不NumPy的。 –

+0

这与我的解决方案有何不同? – Divakar

+0

@Divakar,没有太大的区别,只是'flatnonzero'有一个多余的'拉威尔()'一步,P – alvas

1

如果计数是累积的(根据你的例子),那么你可以很容易地为O做到这一点(N )。只要有一个每次通过提高你找到一个零,则计数器变量的值追加到另一个阵列,每一个您的初始阵列中打了一个柜台。

+0

确实。见https://stackoverflow.com/a/46826684/6419007 –

+0

@EricDuminil授予您提供了一个简洁的解决方案,我并不赞成,这样一个简单的问题提供了直线上升的代码的解决方案。它进一步复制和粘贴编程,这污染了世界各地的代码库。只是我2美分(和明确的意见为准)。 –

+1

感谢您的评论。我了解你的观点。我非常欣赏numpy的简洁语法,并且无法拒绝写一些东西。 –

4

代码

你可以使用:

(A == 0).cumsum()[A > 0] 
# array([0, 0, 1, 2, 2, 5]) 

或:

(~A).cumsum()[A] 
# array([0, 0, 1, 2, 2, 5]) 

如果A是一个布尔数组。

说明

A == 0是一个布尔数组是True每个0

>>> import numpy as np 
>>> A = np.array([1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0]) 
>>> A == 0 
array([False, False, True, False, True, False, False, True, True, 
     True, False, True, True, True, True], dtype=bool) 

您可以使用cumsum()来算的True S上的号码:

>>> (A == 0).cumsum() 
array([0, 0, 1, 1, 2, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9]) 

你只需要其中A > 0的值:

>>> (A == 0).cumsum()[A > 0] 
array([0, 0, 1, 2, 2, 5]) 

完成!

+1

这似乎是最pythonic,如果不是最有效的解决方案 –

+0

@DanielF:谢谢。事实上,接受的答案比我的代码快20%。 –

+1

像往常一样,有错误的方式,正确的方式和@Divakar的方式 - 这有点像正确的方式,但有更多的代码,但以某种方式更快。 –

相关问题