以下问题可以通过循环轻松解决,但我怀疑可能有更多的pythonic方式来实现这一点。
从本质上讲,我有一个可迭代的布尔值,它们往往被聚集成组。这是一个说明性的例子:
[True, True, True, True, False, False, False, True, True, True, True, True]
我想为每个True
群集挑选起始索引和结束索引。使用循环,这很容易 - 每次我的迭代器都是True
时,我只需要检查我是否已经在True
集群中。如果没有,我将in_true_cluster
变量设置为true并存储索引。找到False
后,我将索引-1存储为终点。
有更多的pythonic方式吗?请注意,我也使用PANDAS和NumPy,因此使用逻辑索引的解决方案是可以接受的。
答案 0 :(得分:3)
实际上,这是一种numpy方式,它应该比使用itertools
或手动循环更快:
>>> a = np.array([True, True, True, True, False, False, False, True, True, True, True, True])
>>> np.diff(a)
array([False, False, False, True, False, False, True, False, False,
False, False], dtype=bool)
>>> _.nonzero()
(array([3, 6]),)
正如你在评论中提到的那样,大熊猫的groupby
也可以。
时间来说服@poke这是值得的:
>>> %%timeit a = np.random.randint(2, size=1000000)
... np.diff(a).nonzero()
...
100 loops, best of 3: 12.2 ms per loop
>>> def cluster_changes(array):
... changes = []
... last = None
... for i, elt in enumerate(array):
... if elt != last:
... last = elt
... changes.append(i)
... return changes
...
>>> %%timeit a = np.random.randint(2, size=1000000)
cluster_changes(a)
...
1 loops, best of 3: 348 ms per loop
与7线手动功能相比,使用单线程的阵列数量为30。 (当然,这里的数据比OP的数据有更多的集群变化,但这并不能弥补这么大的差异。)
答案 1 :(得分:3)
怎么样:
In [25]: l = [True, True, True, True, False, False, False, True, True, True, True, True]
In [26]: d = np.diff(np.array([False] + l + [False], dtype=np.int))
In [28]: zip(np.where(d == 1)[0], np.where(d == -1)[0] - 1)
Out[28]: [(0, 3), (7, 11)]
此处,两次分别位于索引[0; 3]
和[7; 11]
。