如何识别布尔数组中的值序列?

时间:2016-04-27 15:51:30

标签: python list python-3.x boolean

我有一个很长的布尔数组:

bool_array = [ True, True, True, True, True, False, False, False, False, False, True, True, True, False, False, True, True, True, True, False, False, False, False, False, False, False ]

我需要确定值翻转的位置,即TrueFalse的序列开始的地址。在这种特殊情况下,我想得到

index = [0, 5, 10, 13, 15, 19, 26]

有没有一种简单的方法可以不用手动循环来检查第(i + 1)行中的每个第i个元素?

5 个答案:

答案 0 :(得分:17)

作为大数据集的更有效方法,在python 3.X中,您可以使用itertools模块中的accumulategroupby函数。

>>> from itertools import accumulate, groupby
>>> [0] + list(accumulate(sum(1 for _ in g) for _,g in groupby(bool_array)))
[0, 5, 10, 13, 15, 19, 26]

代码背后的逻辑:

此代码使用groupby()函数对连续的重复项进行分类,然后循环遍历由groupby()返回的迭代器,该迭代器包含成对的键(我们使用下线而不是扔掉它来逃避它变量)和这些分类的迭代器。

>>> [list(g) for _, g in groupby(bool_array)]
[[True, True, True, True, True], [False, False, False, False, False], [True, True, True], [False, False], [True, True, True, True], [False, False, False, False, False, False, False]]

所以我们需要的是计算这些迭代器的长度并将每个长度与其先前的长度相加,以获得第一项的索引,该索引恰好是项目的更改位置,这正是{{1}功能是为了。

在Numpy中,您可以使用以下方法:

accumulate()

答案 1 :(得分:11)

这会告诉你哪里:

>>> import numpy as np
>>> np.argwhere(np.diff(bool_array)).squeeze()
array([ 4,  9, 12, 14, 18])

np.diff计算每个元素与下一个元素之间的差异。对于布尔值,它实质上将值解释为整数(0:False,非零:True),因此差异显示为+1或-1值,然后映射回布尔值(当发生更改时为True)。 / p>

np.argwhere函数会告诉您值为True的位置 - 现在是更改。

答案 2 :(得分:5)

使用zipenumerate即可

>>> [i for i,(m,n) in enumerate(zip(bool_array[:-1],bool_array[1:])) if m!=n]
[4, 9, 12, 14, 18]

现在你有[4, 9, 12, 14, 18],你可以

>>> [0]+[i+1 for i in [4, 9, 12, 14, 18]]+[len(bool_array)]
[0, 5, 10, 13, 15, 19, 26]

实现您的输出。

代码背后的逻辑:

  • zip接受两个迭代器并返回两个元素的序列。我们为从第一个元素开始的迭代器和从第二个元素开始的迭代器传递相同的列表。因此我们得到一个相邻数字列表
  • enumerate为您提供一系列索引和迭代器的值。
  • 现在我们将它包装在列表理解中。如果压缩值不相同,我们将返回索引

另一个单步程序是

>>> [i for i,(m,n) in enumerate(zip([2]+bool_array,bool_array+[2])) if m!=n]
[0, 5, 10, 13, 15, 19, 26]

这里我们故意将[2]引入列表中,这是因为第一个和最后一个值将始终不同(因为[2]永远不会出现在列表中)。因此我们将直接获得这些索引。

答案 3 :(得分:0)

Python 3.8开始并引入assignment expressions (PEP 572):=运算符),我们可以在列表推导中使用和增加变量。加上groupby

from itertools import groupby

# bool_array = [True, True, True, True, True, False, False, False, False, False, True, True, True, False, False, True, True, True, True, False, False, False, False, False, False, False]
total = 0
[total := total + len(list(gp)) for _, gp in groupby(bool_array)]
# [5, 10, 13, 15, 19, 26]

此:

  • 将变量total初始化为0,这象征着累加和
  • 使用groupby将连续的项目分组(连续的True将被分组在一起,连续的False也是如此)
  • 对于每个系列的布尔值,这两个都:
      通过赋值表达式
    • 用布尔值(total)的当前长度递增total := total + len(list(gp))
    • 同时将连续系列映射到新值total

当然要从0开始,您始终可以将[0]插入列表的前面。

答案 4 :(得分:0)

使用 pandas shift 查找 value != next 的位置。

import pandas as pd
bool_array = [ True, True, True, True, True, False, False, False, False, False, True, True, True, False, False, True, True, True, True, False, False, False, False, False, False, False ]
bools = pd.Series(bool_array)
flips = bools != bools.shift(1)
flips[flips].index

Int64Index([0, 5, 10, 13, 15, 19], dtype='int64')

或作为列表

list(flips[flips].index)

[0, 5, 10, 13, 15, 19]