如何高效计算Numpy网格点与8邻域的差值和均值?
高效计算Numpy数组网格点的8邻域差值与均值
存储方案选择
不用考虑nm×nm的冗余结构,推荐以下两种存储方式:
- 差值数据:用
(n, m, 8)形状的Numpy数组,每个位置(i,j,k)对应第(i,j)个网格点与第k个方向邻域点的差值,完整保留所有计算结果且无冗余。 - 差值均值:用
(n, m)形状的数组,存储每个网格点对应8个差值的平均值,满足轻量化统计需求。
高效实现代码
1. 忽略边界点(仅计算内部有效点)
边缘点没有完整的8个邻域,可直接计算内部区域(行1到n-1、列1到m-1):
import numpy as np # 示例数组 arr = np.array([ [1, 2, 1, 3, 5], [0, 4, 2, 4, 1], [1, 1, 1, 0, 2] ]) n, m = arr.shape # 提取8个邻域的切片 neighbors = [ arr[:-2, :-2], # 左上 arr[:-2, 1:-1], # 正上 arr[:-2, 2:], # 右上 arr[1:-1, :-2], # 左 arr[1:-1, 2:], # 右 arr[2:, :-2], # 左下 arr[2:, 1:-1], # 正下 arr[2:, 2:] # 右下 ] # 计算每个内部点与8邻域的差值,结果形状为(n-2, m-2, 8) diff = (arr[1:-1, 1:-1][None, ...] - np.array(neighbors)).transpose(1, 2, 0) # 计算每个内部点的差值均值,结果形状为(n-2, m-2) diff_mean = diff.mean(axis=2)
2. 包含边界点(填充处理)
如果需要计算所有网格点的结果,先对原数组进行边界填充(示例用边缘值填充,也可选择0填充、镜像填充等):
# 边缘值填充数组,边界扩展1层 padded_arr = np.pad(arr, pad_width=1, mode='edge') # 提取填充后数组的8个邻域切片 neighbors_pad = [ padded_arr[:-2, :-2], padded_arr[:-2, 1:-1], padded_arr[:-2, 2:], padded_arr[1:-1, :-2], padded_arr[1:-1, 2:], padded_arr[2:, :-2], padded_arr[2:, 1:-1], padded_arr[2:, 2:] ] # 计算所有点的差值,结果形状为(n, m, 8) diff_pad = (padded_arr[1:-1, 1:-1][None, ...] - np.array(neighbors_pad)).transpose(1, 2, 0) # 计算所有点的差值均值,结果形状为(n, m) diff_mean_pad = diff_pad.mean(axis=2)
效率说明
全程使用Numpy的切片与广播机制,完全规避Python循环,依赖底层C实现的向量运算处理,在大数组场景下效率远高于手动遍历。
内容的提问来源于stack exchange,提问作者Simon M
相关产品推荐
相关产品推荐

