np.diag()可提取主对角线(k=0)及上下偏移对角线(k≠0),对非方阵各k值长度天然不同,无需补零;传入2d提取、1d构造,仅作用于前两维。

用 np.diag() 提取主对角线和指定偏移的对角线
np.diag() 是最直接的工具,但它行为分两种:传入 2D 数组时提取对角线;传入 1D 数组时构造对角矩阵。提取偏移对角线靠 k 参数控制。
-
k = 0(默认)提取主对角线:从左上到右下,索引满足i == j -
k > 0提取上方第k条对角线(如k=1是紧邻主对角线上方那条),对应j = i + k k 提取下方第 <code>|k|条对角线(如k=-2是主对角线下方第二条),对应j = i - |k|- 若偏移超出矩阵边界(例如 3×3 矩阵中
k=5),返回空数组array([]),不是报错 —— 这点容易误判为出错
示例:
import numpy as np
a = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
<p>print(np.diag(a, k=0)) # [1 6 11]
print(np.diag(a, k=1)) # [2 7 12]
print(np.diag(a, k=-1)) # [5 10]</p>
为什么不能直接用 a.diagonal()?它和 np.diag() 有啥区别?
a.diagonal(k) 看似等价,但它是 ndarray 的方法,**只支持 k 为单个整数**,不支持数组;而 np.diag() 在提取时也只接受单个 k,但关键差异在「返回视图还是副本」:
-
a.diagonal()返回的是原数组的**只读视图**(view),修改它会触发RuntimeWarning且无效 -
np.diag(a, k)总是返回**新数组(副本)**,可安全修改 - 二者在非方阵上行为一致,都按标准定义截取有效部分(比如 3×4 矩阵的
k=2只有前两个元素有效)
所以若后续要修改提取结果,务必用 np.diag();若只是读取且想省一点内存(极少场景),可用 .diagonal(),但得加 copy() 才能改。
批量提取多条偏移对角线:别循环调用 np.diag()
需要同时拿 k = -2, -1, 0, 1, 2 的对角线?手动循环五次 np.diag(a, k=i) 效率低、代码啰嗦。更高效的做法是用 np.eye() 构造掩码,再用布尔索引:
- 先生成与
a同形的全零数组,再用np.eye(a.shape[0], a.shape[1], k=k)得到对应偏移的 0/1 掩码 - 然后
a[mask]直接取出 —— 注意这会按行优先顺序展平,需根据需求重排 - 或者更简洁:用列表推导式
[np.diag(a, k=i) for i in [-2,-1,0,1,2]],可读性好,小矩阵无性能压力
大矩阵(如 >1000×1000)且偏移数多时,建议预分配结果列表并用循环,避免临时数组反复创建。
提取后长度不一致?这是正常现象,别硬 pad 对齐
非方阵中不同 k 对应的对角线长度天然不同。例如 3×5 矩阵:k=0 长 3,k=2 长 1,k=-2 长 1。强行用 np.pad() 补零或 None 会破坏数据语义,还可能误导后续计算。
- 如果后续要做向量化运算(如求每条对角线均值),直接用
[d.mean() for d in diags]即可 - 若必须堆成二维数组,用
np.array()会转成 object dtype,失去数值优势;真需要数值型二维结构,应明确补什么值(如np.nan),并用np.full()配合切片填充 - 最容易被忽略的是:对角线索引逻辑依赖于数组的
shape,而非ndim—— 即使是 3D 张量,np.diag()也只处理前两维,其余维度会被忽略或报错
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











