如何在NumPy中从p*q大矩阵提取m*n子矩阵?(数独场景示例)
提取9×9矩阵中所有3×3子矩阵的NumPy优化方法
当然有更直接高效的实现方式!你的嵌套np.split/np.hsplit做法是可行的,但NumPy提供了更简洁的数组操作方法,不用写循环就能一次性提取所有3×3子矩阵。下面介绍两种常用的优化方案:
方法1:利用数组重塑(reshape)+ 轴交换(swapaxes)
这是最经典的无循环实现方式,核心是通过重塑数组维度来直接拆分出所有3×3块:
import numpy as np grid = np.array([ [5,3,4,6,7,8,9,1,2], [6,7,2,1,9,5,3,4,8], [1,9,8,3,3,2,5,6,7], [8,5,9,7,6,1,4,2,3], [4,2,6,8,5,3,7,9,1], [7,1,3,9,2,4,8,5,6], [9,6,1,5,3,7,2,8,4], [2,8,7,4,1,9,6,3,5], [3,4,5,2,8,6,1,7,9] ]) # 一次性提取所有3×3子矩阵 blocks = grid.reshape(3, 3, 3, 3).swapaxes(1, 2).reshape(-1, 3, 3) # 打印结果 for block in blocks: print(block) print("---")
原理说明:
grid.reshape(3, 3, 3, 3):把原9×9矩阵拆分为3个行块(每个行块3行)×3个列块(每个列块3列),维度变为(行块数, 行块内行数, 列块数, 列块内列数);swapaxes(1, 2):调整轴的顺序,将维度转换为(行块数, 列块数, 行块内行数, 列块内列数),让每个行块对应的列块可以直接组合成完整的3×3子矩阵;reshape(-1, 3, 3):将所有子矩阵展平为一个数组,其中每个元素都是3×3的子矩阵(最终得到9个3×3块)。
方法2:使用滑动窗口视图(sliding_window_view)
如果你使用的是NumPy 1.20及以上版本,可以用sliding_window_view来更直观地提取非重叠窗口:
from numpy.lib.stride_tricks import sliding_window_view # 生成所有滑动窗口,然后按步长3取非重叠的3×3块 blocks = sliding_window_view(grid, window_shape=(3, 3))[::3, ::3].reshape(-1, 3, 3) # 打印结果 for block in blocks: print(block) print("---")
原理说明:
sliding_window_view(grid, window_shape=(3,3)):生成所有可能的3×3滑动窗口,维度为(7,7,3,3)(因为滑动步长默认是1);[::3, ::3]:每隔3个窗口取一个,筛选出所有非重叠的3×3块,此时维度为(3,3,3,3);reshape(-1, 3, 3):同样将所有子矩阵展平为9个3×3块的数组。
这两种方法都能得到和你原来代码完全一致的结果,而且避免了循环开销,代码更简洁,处理大矩阵时效率优势更明显。
内容的提问来源于stack exchange,提问作者Thalish Sajeed
相关产品推荐
相关产品推荐

