【问题标题】:Count consecutive occurences of values varying in length in a numpy array计算 numpy 数组中长度不同的值的连续出现次数
【发布时间】:2014-08-12 02:00:48
【问题描述】:

假设我在一个 numpy 数组中有一堆数字,我根据返回布尔数组的条件来测试它们:

np.random.seed(3456)
a = np.random.rand(8)
condition = a>0.5

通过这个布尔数组,我想计算 True 连续出现的所有长度。例如,如果我有[True,True,True,False,False,True,True,False,True],我想找回[3,2,1]

我可以使用以下代码做到这一点:

length,count = [],0
for i in range(len(condition)):

    if condition[i]==True:
        count += 1
    elif condition[i]==False and count>0:
        length.append(count)
        count = 0

    if i==len(condition)-1 and count>0:
        length.append(count)

    print length

但是是否已经为此或 python、numpy、scipy 等函数实现了任何功能,用于计算给定输入的列表或数组中连续出现的长度?

【问题讨论】:

标签: python arrays numpy


【解决方案1】:

如果你已经有一个 numpy 数组,这可能会更快:

>>> condition = np.array([True,True,True,False,False,True,True,False,True])
>>> np.diff(np.where(np.concatenate(([condition[0]],
                                     condition[:-1] != condition[1:],
                                     [True])))[0])[::2]
array([3, 2, 1])

它检测块的开始位置,对第一个和最后一个块有一些逻辑,并简单地计算块开始之间的差异并丢弃与False 块对应的长度。

【讨论】:

  • 我将这个函数传递给 pandas 数据帧上的 grouby 和 resample 方法,所以我猜它最终将是一个 numpy 数组。在这种情况下,速度不是什么大问题,但在数据集更大的情况下会注意到
  • 我发现 1e6 bools 比 itertools 方法快几个数量级。谢谢!
  • 不错,谢谢!您是否有建议我如何调整您的代码,以便我可以在 2D numpy 数组上逐行执行此操作?
  • @pr94 按行执行可能会为每个答案提供不同长度的数组。我猜你必须一次做一行,因此你只需要循环一些方法并添加额外的索引[0,:]而不是[0]
【解决方案2】:

这是使用itertools 的解决方案(它可能不是最快的解决方案):

import itertools
condition = [True,True,True,False,False,True,True,False,True]
[ sum( 1 for _ in group ) for key, group in itertools.groupby( condition ) if key ]

Out:
[3, 2, 1]

【讨论】:

  • 绝对是一个非常pythonic的答案!实际上,这比我上面的代码片段要快得多。与 ~1-2 相比,大约 0.2s
  • 它起作用了......但随后它开始向我显示此错误:The truth value of an array with more than one element is ambiguous。出乎意料,不知道为什么。它在空闲状态下工作,而不是在 pycharm 中
  • 如果您使用 len(list(group)) 而不是 sum(1...),这会稍微快一些,但如果您已经有一个 numpy 数组,它仍然比@Jaime 的答案慢很多。跨度>
【解决方案3】:

您还可以通过查看条件数组的倒数的索引(np.where 的结果)来计算连续 False 值之间的距离。诀窍是确保布尔数组以False 开头。基本上,您正在计算True 条件之间的边界之间的距离。

condition = np.array([True, True, True, False, False, True, True, False, True, False])
if condition[0]:
    condition = np.concatenate([[False], condition])

idx = np.where(~condition)[0]

在最后一步,您需要将这些值设为 1,以便移除左右边缘。

>>> np.ediff1d(idx) - 1
array([3, 0, 2, 1])

【讨论】:

    【解决方案4】:

    如果t是np数组并且按升序排序,那么:

    d=np.diff(t)
    d_incr = np.argwhere(d>0).flatten()
    d_incr = np.insert(d_incr, 0, 0)
    

    np 数组 d_incr 将包含发生变化的索引,允许对范围 (1,d_incr.size) 中的 i 在 d_incr[i-1] 和 d_incr[i] 之间的值组执行操作

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-01
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多