如何用多变量索引2的幂次方阵的行/列轴以提取子矩阵?
用Numpy高效实现幂次方阵的二元组索引
对于2的幂次方阵的分块/二元组索引需求,Numpy的维度重塑(reshape)+ 多维度索引是最高效的方案,完全不需要手动映射索引,而且操作都是矢量化的,性能拉满。
核心思路
把原方阵的行/列维度拆分成「块索引」+「块内索引」的组合,通过reshape将矩阵转换成多维度数组,之后直接用你想要的二元组(或多元组)作为索引访问即可。
4x4矩阵示例(对应你的需求)
先把普通列表转成Numpy数组,再按块大小重塑维度:
import numpy as np # 初始化4x4矩阵 M = np.array([ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16] ]) # 重塑为(块行索引r1, 块内行索引r2, 块列索引c1, 块内列索引c2) # 这里块大小是2x2,所以维度是(2,2,2,2) M_blocked = M.reshape(2, 2, 2, 2)
接下来直接实现你要的索引效果:
- 单个元素访问:
M[(0,0),(0,0)]→ 对应M_blocked[0, 0, 0, 0]print(M_blocked[0, 0, 0, 0]) # 输出:1 - 单个元素访问:
M[(1,0),(1,1)]→ 对应M_blocked[1, 0, 1, 1]print(M_blocked[1, 0, 1, 1]) # 输出:12 - 整行访问:
M[(0,1),]→ 取r1=0、r2=1的行,展平为一维print(M_blocked[0, 1, :, :].flatten()) # 输出:[5 6 7 8] - 子矩阵访问:
M[(0,),(0,)]→ 取r1=0的所有块内行、c1=0的所有块内列print(M_blocked[0, :, 0, :]) # 输出: # [[1 2] # [5 6]]
8x8矩阵示例(自定义块大小)
按你的要求,把8x8矩阵分成2个4x4子块(r1∈[0,1],r2∈[0-3]),只需调整reshape的参数:
# 初始化8x8矩阵 M_8x8 = np.arange(64).reshape(8,8) # 重塑为(块行r1, 块内行r2, 块列c1, 块内列c2),块大小4x4 M_8x8_blocked = M_8x8.reshape(2, 4, 2, 4) # 取r1=1、r2=2的整行(对应原矩阵第6行) print(M_8x8_blocked[1, 2, :, :].flatten()) # 输出:[48 49 50 51 52 53 54 55] # 取左上角4x4子矩阵 print(M_8x8_blocked[0, :, 0, :]) # 输出原矩阵0-3行、0-3列的所有元素
为什么这个方法高效?
Numpy的reshape是视图操作,不会复制原矩阵的数据,只是改变了数据的访问方式,所以几乎没有额外开销,比手动计算映射索引快得多,尤其适合大矩阵场景。
内容的提问来源于stack exchange,提问作者Enigma
相关产品推荐
相关产品推荐

