我的数据大致长这样:
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中实现这个功能的好方法?(还可以使用Pandas和Numpy来帮助解析数据)
如果我们有一个输入数组a
,我们可以使用向量化的解决方案-
m = a!=0
out = (m[1:] > m[:-1]).sum() + m[0]
为了获得更好的性能,我们可以使用 np.count_nonzero
。这个函数非常高效,可以非常快速地计算布尔值的数量,就像下面这样 -
out = np.count_nonzero(m[1:] > m[:-1]) + m[0]
基本上,我们得到一个非零掩码并计算上升沿的数量。为了考虑第一个元素也可能是非零的情况,并且不会有任何上升沿,我们需要检查它并将其添加到总和中。
此外,请注意,如果输入的 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
您可以通过使用 itertools.groupby()
和 列表推导式 表达式来实现:
>>> from itertools import groupby
>>> len([is_true for is_true, _ in groupby(a, lambda x: x!=0) if is_true])
3
这是一个简单的Python解决方案,只需计算从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
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]])
sum ([1 for n in range (len (a) - 1) if not a[n] and a[n + 1]])
((ser!=0)&(ser.shift()==0)).sum()
- JohnE