python - 计算具有相同值的numpy数组中值的(部分)邻居
问题描述
我正在尝试为 numpy 数组中的每个条目计算/查找具有相同值的邻居的分数。它需要高性能(在更大的阵列上运行多次),可能具有更改邻域定义的能力(车/皇后,即 4 个邻居:NSEW,与 8 个邻居:NE、N、NW、E、W、SE ,S,SW),并且可以将 0 设置为 NaN 或不设置。
考虑一个简单的整数 numpy 数组:
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 卷积的相似之处,除了它们会带来总和,而不是计数。
解决方案
卷积正是您正在寻找的。例如,scipy.signal.convolve
。考虑以下内核:
kernel = np.ones((3, 3), dtype=int)
kernel[1, 1] = 0
# array([[1, 1, 1],
# [1, 0, 1],
# [1, 1, 1]])
这是一个空心环。内核将累加每个位置周围元素的数量。您需要对布尔值进行操作才能使其正常工作。
此外,由于您只想计算相似的元素,因此您需要创建一个数组,将独特的元素分离到各个平面中。碰巧的是,您可以同时创建一个布尔数组:
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 中的另一个卷积函数 , 在scipy.ndimage.convolve
这里不太适合,尽管你也可以使用它:
counts = convolve(b.view(np.uint8), kernel, mode='constant', cval=0)
注意论点b.view(np.uint8)
。您需要这样做或等效(例如b.astype(int)
)以避免获取布尔数组而不是计数。
TL;博士
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)
推荐阅读
- vba - 如何遍历 VBA 中的文本格式?
- c - C - 我的循环递减工作,但不确定为什么
- angular - 控制生成的内容 - *ngIf 的编译/编译时间版本
- javascript - Apex 图表跳过一些具有相同值的数据点
- arrays - 如果可能存在重复值和缺失值,您将什么称为“子列表”?
- r - 使用R从字符变量中提取最小值和最大值
- python - selenium 是否有相同按钮的最大点击次数
- javascript - 电子更新不起作用 - 最大允许大小为 50 MB
- spring-boot - 有没有办法配置@KafkaListener 的轮询间隔?
- android - 如何翻转卡片同时点击图片发出声音?