
本文介绍如何使用 NumPy 的 sliding_window_view 与索引查表技术,将原始数组中相邻行构成的值对,高速映射为预定义规则数组中的对应结果值,全程避免 Python 循环,兼顾可读性与极致性能。
本文介绍如何使用 numpy 的 `sliding_window_view` 与索引查表技术,将原始数组中相邻行构成的值对,高速映射为预定义规则数组中的对应结果值,全程避免 python 循环,兼顾可读性与极致性能。
在科学计算与数据处理中,常需根据“上一行→下一行”的有序值对(如状态转移、时序差分、图边权重等),将二维数组按列生成新的映射结果数组。本教程以一个典型场景为例:给定源数组 a 和规则数组 b,要求对 a 每一列中所有垂直相邻元素对(即 (a[i, j], a[i+1, j]))查找 b 中匹配的 (x, y) 行,并提取其第三列数值,最终输出形状为 (a.shape[0]-1, a.shape[1]) 的结果数组 c。
核心挑战在于:既要保证配对顺序敏感((1,3) ≠ (3,1)),又要实现全向量化、零显式循环的高性能执行——尤其当该操作需重复执行数万次时,效率至关重要。
✅ 推荐方案:稠密索引查表(适用于值域紧凑场景)
当规则数组 b 中的取值范围小且连续(例如仅含 1,2,3 或 0~n-1),最优解是构建二维查找表(lookup table),利用 NumPy 高效整数索引完成批量映射:
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view as swv
# 示例数据
a = np.array([[2, 3, 1, 3],
[3, 2, 1, 3],
[1, 1, 1, 2],
[1, 3, 2, 3],
[3, 3, 1, 3],
[2, 1, 3, 2]])
b = np.array([[1, 1, 6],
[1, 2, 0],
[1, 3, 9],
[2, 1, 6],
[2, 2, 0],
[2, 3, 4],
[3, 1, 1],
[3, 2, 0],
[3, 3, 8]])
# 步骤 1:构建二维查找表 s,s[x, y] = 对应规则值(支持 1-based 值)
max_val = b[:, :2].max()
s = np.full((max_val + 1, max_val + 1), -1) # 初始化为哨兵值
s[b[:, 0], b[:, 1]] = b[:, 2] # 向量化赋值
# 步骤 2:提取 a 中所有垂直相邻对(形状: (n-1, cols, 2))
pairs = swv(a, 2, axis=0) # shape = (5, 4, 2)
# 步骤 3:用 pairs 的两个维度分别索引 s,得到结果
c = s[pairs[..., 0], pairs[..., 1]]
print(c)
# [[4 0 6 8]
# [1 6 6 0]
# [6 9 0 4]
# [9 8 6 8]
# [0 1 9 0]]? 关键说明:sliding_window_view(a, 2, axis=0) 将 a 沿行方向滑动,每步取 2 行堆叠成新维度,输出形状为 (a.shape[0]-1, a.shape[1], 2);pairs[..., 0] 和 pairs[..., 1] 分别提取“上值”和“下值”,直接作为二维数组 s 的行列索引,实现一次广播式查表。
⚠️ 注意事项与优化建议
-
值域偏移处理:若 b 中值从 1 开始(如本例),而你希望节省内存,可统一减 1 转为 0-based 索引:
s = np.full((max_val, max_val), -1) s[b[:, 0]-1, b[:, 1]-1] = b[:, 2] pairs_0b = swv(a, 2, axis=0) - 1 c = s[pairs_0b[..., 0], pairs_0b[..., 1]]
-
稀疏/大值域场景替代方案:当 b 中的值跨度极大(如 1 到 10^5)且稀疏时,构建稠密 s 会浪费内存甚至失败。此时推荐 Pandas merge 方案(仍保持向量化):
import pandas as pd df_pairs = pd.DataFrame(swv(a, 2, axis=0).reshape(-1, 2), columns=['x', 'y']) df_rules = pd.DataFrame(b, columns=['x', 'y', 'val']) c_flat = df_pairs.merge(df_rules, on=['x','y'], how='left')['val'].to_numpy() c = c_flat.reshape(-1, a.shape[1])
✅ 优势:内存友好,不依赖值连续性;⚠️ 缺点:速度约为 NumPy 查表的 1/10(见基准测试),适合单次或低频调用。
健壮性增强:生产环境建议校验 b 是否覆盖所有可能的 (x,y) 组合,或对未命中项设默认值(如 np.where(c == -1, 0, c))。
? 性能对比(实测基准)
| 场景 | NumPy 查表 | Pandas Merge |
|---|---|---|
| 稠密(1000×1000,值域 1~1000) | ~16.5 ms | ~173 ms |
| 稀疏(1000 个值,来自 50000 可能值) | ~5.0 s(OOM 风险) | ~192 ms |
? 结论:优先用 NumPy 查表;值域稀疏或不可控时,切换至 Pandas merge。二者均远超手动 for 循环(通常慢 100× 以上)。
通过本方法,你可在毫秒级完成百万级配对映射,真正实现“规则驱动、向量加速、工业可用”的数组转换范式。

















