计算numpy数组中具有相同值的值的(分数)邻域

2024-06-16 14:34:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图为numpy数组中的每个条目计算/查找相同值的相邻项的分数。它需要性能良好(在较大的阵列上运行多次),可能能够更改邻域定义(rook/queen,即4个邻域:NSEW,而8个邻域:NE、N、NW、E、W、SE、S、SW),并且能够将0设置为NaN或非NaN

考虑一个简单的整数编号数组:

a = np.zeros((6,6), dtype=np.int64)
a[1,2] = a[1,3] = 1
a[4,4] = a[5,4] = a[5,5] = 3
a[4,3] = 2

这看起来像:

[[0 0 0 0 0 0]
[0 0 1 1 0 0]
[0 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 2 3 0]
[0 0 0 0 3 3]]

我想生成下面的数组,在这里我们考虑0个屏蔽(不是数字):

[[0 0 0 0 0 0]
[0 0 1 1 0 0]
[0 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 2 0]
[0 0 0 0 2 2]]

或者更好,如果表示为分数:

[[0 0 0 0 0 0]
[0 0 1/8 1/8 0 0]
[0 0 0 0 0 0]
[0 0 0 0 0 0]
[0 0 0 0 2/8 0]
[0 0 0 0 2/5 2/3]]

我考虑过与scipy卷积的相似之处,除了它们带来的是总和,而不是计数


Tags: numpy定义np条目数组nan性能分数
1条回答
网友
1楼 · 发布于 2024-06-16 14:34:19

卷积正是你要找的。例如,^{}。考虑下面的内核:

kernel = np.ones((3, 3), dtype=int)
kernel[1, 1] = 0
# array([[1, 1, 1],
#        [1, 0, 1],
#        [1, 1, 1]])

这是一个空心的戒指。内核将在每个位置加上周围元素的数量。不过,你需要对bools进行操作,它才能正常工作

此外,由于只希望计算相似的元素,因此需要创建一个数组,将唯一的元素分隔为各个平面。实际上,您可以在创建布尔数组的同时执行此操作:

u = np.unique(a)  # array([0, 1, 2, 3])
b = a == u[1:, None, None]

现在,如果向内核添加一个维度,则可以直接应用卷积:

counts = convolve(b, kernel[None, ...], 'same')

这将在原始非零以外的位置返回非零,因此必须对其进行屏蔽:

counts *= b

最后,现在可以对额外标签维度上的counts的非零元素求和:

counts = counts.sum(0)

此卷积返回对角线元素以及直接相邻元素。要返回后者,请改用此内核:

kernel = np.zeros((3, 3), dtype=int)
kernel[0, 1] = kernel[2, 1] = kernel[1, 0] = kernel[1, 2] = 1
# array([[0, 1, 0],
#        [1, 0, 1],
#        [0, 1, 0]])

scipy中的另一个卷积函数^{}在这里不太合适,尽管您也可以使用它:

counts = convolve(b.view(np.uint8), kernel, mode='constant', cval=0)

注意参数b.view(np.uint8)。您需要这样做或等效操作(例如b.astype(int)),以避免获得布尔数组而不是计数

TL;DR

from scipy.signal import convolve

kernel = np.ones((1, 3, 3), dtype=int)
kernel[0, 1, 1] = 0
b = a == np.unique(a)[1:].reshape(-1, 1, 1)
counts = (b * convolve(b, kernel, 'same')).sum(0)

相关问题 更多 >