NumPy 2D布尔数组计算连续True的数量

3

我很想了解布尔数组中“True”补丁的个别尺寸。例如,在布尔矩阵中:

[[1, 0, 0, 0],
 [0, 1, 1, 0],
 [0, 1, 0, 0],
 [0, 1, 0, 0]]

输出结果将是:
[[1, 0, 0, 0],
 [0, 4, 4, 0],
 [0, 4, 0, 0],
 [0, 4, 0, 0]]

我知道我可以递归地完成这个任务,但我也认为在大规模上使用Python数组操作是代价高昂的,是否有可用的库函数可以完成此任务?


1
出于某种原因,你会发现这些类型的聚类算法通常在图像处理/计算机视觉库中。scipy.ndimage.measurements 中有你需要的内容。 - tel
1个回答

3

这里有一个快速简单的完整解决方案:

import numpy as np
import scipy.ndimage.measurements as mnts

A = np.array([
    [1, 0, 0, 0],
    [0, 1, 1, 0],
    [0, 1, 0, 0],
    [0, 1, 0, 0]
])

# labeled is a version of A with labeled clusters:
#
# [[1 0 0 0]
#  [0 2 2 0]
#  [0 2 0 0]
#  [0 2 0 0]]
#
# clusters holds the number of different clusters: 2
labeled, clusters = mnts.label(A)

# sizes is an array of cluster sizes: [0, 1, 4]
sizes = mnts.sum(A, labeled, index=range(clusters + 1))

# mnts.sum always outputs a float array, so we'll convert sizes to int
sizes = sizes.astype(int)

# get an array with the same shape as labeled and the 
# appropriate values from sizes by indexing one array 
# with the other. See the `numpy` indexing docs for details
labeledBySize = sizes[labeled]

print(labeledBySize)

输出:

[[1 0 0 0]
 [0 4 4 0]
 [0 4 0 0]
 [0 4 0 0]]

上面最棘手的一行是“高级”numpy索引:
labeledBySize = sizes[labeled]

其中一个数组用于索引另一个数组。有关为什么这样做的详细信息,请参见numpy索引文档(“索引数组”部分)

我还编写了上述代码的单个紧凑函数版本,您可以在线尝试。它包括基于随机数组的测试用例。


谢谢!这非常优雅。 - Rocky Li
更新,由于非常奇怪的原因,这并不起作用。即,B[B == label] = size 的赋值结果与预期不符。赋值结果是随机的和错误的 - 你最初的代码是在更大的矩阵上使用的 -> A size(10,10) 随机布尔矩阵不会起作用。 - Rocky Li
1
我找到了问题所在!对于具有多个索引的较大矩阵,B[B==label] 可能会存在先前更改的索引等于新标签的情况,这些索引就会错误地被标记为大小。 - Rocky Li
1
@RockyLi 哈哈,我应该自己发现这个问题。我发布了一份已经修正的代码版本,完全删除了循环,改用单个 numpy 高级索引操作。此外,还提供了一个在线测试案例的链接,基于随机数组。 - tel
这确实很花哨,但实际上很容易理解!感谢更新。 - Rocky Li

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接