2016-12-31 84 views
7

我的数据看起来是这样的:在Python中计算非零值的聚类数量?

a=[0,0,0,0,0,0,10,15,16,12,11,9,10,0,0,0,0,0,6,9,3,7,5,4,0,0,0,0,0,0,4,3,9,7,1] 

从本质上讲,有前非零数字一串零的,我期待数由零隔开非零数字的组数。在上面的例子中的数据,有3组非零数据的这样的代码应该返回3.

  • 非零的组之间的零的个数是可变的

任何好的方法来做到这在python中? (同样使用熊猫和numpy的,以帮助分析数据)

+0

如果在一系列(或数据帧)具有,凑ld do:'((ser!= 0)&(ser.shift()== 0))。sum()' – JohnE

+0

相关:[从数组中提取单独的非零块](http://stackoverflow.com/问题/ 31544129/extract-separate-non-zero-blocks-from-array)和[如何将列表切分成Python中非零整数的连续组](http://stackoverflow.com/questions/6760871/how- python) – user2314737

回答

5

随着a作为输入数组,我们可以有一个量化的解决方案 -

m = a!=0 
out = (m[1:] > m[:-1]).sum() + m[0] 

或者性能,我们可能会使用np.count_nonzero这是非常有效的算的bool比如这里的情况下,像这样 -

out = np.count_nonzero(m[1:] > m[:-1]) + m[0] 

基本上,我们得到的non-zeros口罩和计数上升沿。为了解释第一个元素也可能非零,并且不会有任何上升的边缘,我们需要检查它并将其加到总和中。

此外,请注意,如果输入a是一个列表,我们需要使用m = np.asarray(a)!=0来代替。

样品运行三个案例 -

In [92]: a # Case1 :Given sample 
Out[92]: 
array([ 0, 0, 0, 0, 0, 0, 10, 15, 16, 12, 11, 9, 10, 0, 0, 0, 0, 
     0, 6, 9, 3, 7, 5, 4, 0, 0, 0, 0, 0, 0, 4, 3, 9, 7, 
     1]) 

In [93]: m = a!=0 

In [94]: (m[1:] > m[:-1]).sum() + m[0] 
Out[94]: 3 

In [95]: a[0] = 7 # Case2 :Add a non-zero elem/group at the start 

In [96]: m = a!=0 

In [97]: (m[1:] > m[:-1]).sum() + m[0] 
Out[97]: 4 

In [99]: a[-2:] = [0,4] # Case3 :Add a non-zero group at the end 

In [100]: m = a!=0 

In [101]: (m[1:] > m[:-1]).sum() + m[0] 
Out[101]: 5 
2

简单蟒溶液,只是计数从0到非零的变化,通过保持前面的值的轨道(上升沿检测):

a=[0,0,0,0,0,0,10,15,16,12,11,9,10,0,0,0,0,0,6,9,3,7,5,4,0,0,0,0,0,0,4,3,9,7,1] 

previous = 0 
count = 0 
for c in a: 
    if previous==0 and c!=0: 
     count+=1 
    previous = c 

print(count) # 3 
4

您可以通过使用itertools.groupby()列表理解表达为:

>>> from itertools import groupby 

>>> len([is_true for is_true, _ in groupby(a, lambda x: x!=0) if is_true]) 
3 
+0

如果使用不易转换为Numpy数组的iterable,这很好。 –

+0

那,我想OP不会有这样的情况。 – Divakar

+0

哦,我的意思是一般的“groupby”方法 - 我其实没有注意到你的错误。无论如何,我的观点是,由于问题是关于Numpy可用的情况,矢量化解决方案更好,但对于其他情况,这是一个很好的知识。 –

1
sum ([1 for n in range (len (a) - 1) if not a[n] and a[n + 1]]) 
+0

如果第一个元素不是零,该怎么办? – Divakar

+0

@Divakar从本质上来说,在非零数字之前有一堆零这就是OP所说的。 – user7342539

+0

啊我的不好,很好注意! – Divakar

2
  • 垫阵列,两侧零与np.concatenate
  • 发现其中零与a == 0
  • 发现边界有np.diff
  • 总结边界由两个与sum
  • 鸿沟发现,因为我们将会发现两倍于我们想要的数量

def nonzero_clusters(a): 
    return int(np.diff(np.concatenate([[0], a, [0]]) == 0).sum()/2) 

示范

nonzero_clusters(
    [0,0,0,0,0,0,10,15,16,12,11,9,10,0,0,0,0,0,6,9,3,7,5,4,0,0,0,0,0,0,4,3,9,7,1] 
) 

3 

nonzero_clusters([0, 1, 2, 0, 1, 2]) 

2 

nonzero_clusters([0, 1, 2, 0, 1, 2, 0]) 

2 

nonzero_clusters([1, 2, 0, 1, 2, 0, 1, 2]) 

3 

定时
a = np.random.choice((0, 1), 100000)
代码

from itertools import groupby 

def div(a): 
    m = a != 0 
    return (m[1:] > m[:-1]).sum() + m[0] 

def pir(a): 
    return int(np.diff(np.concatenate([[0], a, [0]]) == 0).sum()/2) 

def jean(a): 
    previous = 0 
    count = 0 
    for c in a: 
     if previous==0 and c!=0: 
      count+=1 
     previous = c 
    return count 

def moin(a): 
    return len([is_true for is_true, _ in groupby(a, lambda x: x!=0) if is_true]) 

def user(a): 
    return sum([1 for n in range (len (a) - 1) if not a[n] and a[n + 1]]) 

enter image description here

+0

对于性能,jean2 = numba.jit(jean)以65μs运行。 –