2

以下问题可以通过循环轻松解决,但我怀疑可能有一种更 Pythonic 的方式来实现这一点。

本质上,我有一个可迭代的布尔值,它们倾向于聚集成组。这是一个说明性示例:

[True, True, True, True, False, False, False, True, True, True, True, True]

我想为每个集群选择开始索引和结束索引True。使用循环,这很容易——每次我的迭代器是 aTrue时,我只需要检查我是否已经在一个True集群中。如果不是,我将in_true_cluster变量设置为 true 并存储索引。一旦我找到 a False,我将 index - 1 存储为终点。

有没有更蟒蛇的方式来做到这一点?请注意,我也在使用 PANDAS 和 NumPy,因此使用逻辑索引的解决方案是可以接受的。

4

2 回答 2

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 的数据有更多的集群变化,但这并不能弥补这么大的差异。)

于 2013-03-05T17:23:58.123 回答
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]

于 2013-03-05T17:27:59.300 回答