☰
NumPy中的矩阵运算函数小记
2026/10/8 9:43:11 网站建设 项目流程

前言


先纠正标题里两个不严谨的地方。第一,NumPy 不是 Python 标准库,它是需要单独安装的第三方库(用pip install numpy);本机没装它,所以下面的调用无法在本机运行验证,API 签名均以 NumPy 官方文档为准,请你以自己的环境为准。第二,「矩阵运算函数」这个说法偏笼统——NumPy 里做矩阵运算的东西有三种形态:模块级函数(如numpy.dot)、ndarray的方法(如a.reshape(...))、以及运算符(@、*)。把a @ b叫「函数」并不准确,它是运算符,背后调用__matmul__。


另外要提前说清一个高频误解:在 NumPy 里,*是逐元素相乘(element-wise,也叫 Hadamard 积),不是矩阵乘法;矩阵乘法要用@运算符或numpy.matmul/numpy.dot。大量「矩阵乘法算错了」的 bug,根源就是把*当成了矩阵乘。


再补一句版本提醒:Python 2.7 已于 2020 年 1 月 1 日停止维护,较新的 NumPy 也早已不再支持 Python 2,网上老代码里的print语句(print x)、xrange等写法在 Python 3 里都不能用,本文示例一律按 Python 3 写。


本文按「建矩阵 → 改形状 → 做乘法 → 解线性方程组」的顺序,记几种常用的矩阵运算写法,并给出可对照官方的签名。


一、创建矩阵与查看形状


ndarray是 NumPy 的核心数据结构,二维的ndarray就是通常说的矩阵。


# 适用于 Python 3.8+ 且已安装 NumPy(以官方文档为准)
import numpy as np

A = np.array([[1, 2], [3, 4]]) # 由嵌套列表构造 2x2
Z = np.zeros((2, 3)) # 2 行 3 列,全 0,默认 float64
O = np.ones((3, 3)) # 3x3 全 1
I = np.eye(3) # 3x3 单位矩阵

print(A.shape) # (2, 2)
print(A.dtype) # int64(视平台而定)
print(Z.shape) # (2, 3)

形状通过.shape属性读取,它是一个元组。修改形状不会复制数据,只要内存布局允许,.reshape返回的是视图(view)。


# 适用于 Python 3.8+ 且已安装 NumPy(以官方文档为准)
a = np.arange(6) # 一维 [0 1 2 3 4 5]
m = np.reshape(a, (2, 3)) # 变成 2x3
print(m.shape) # (2, 3)
print(a.shape) # (6,) ← 原数组不变

二、转置:.T与numpy.transpose


转置有两种等价写法:数组属性.T,或函数numpy.transpose(a, axes=None)。


# 适用于 Python 3.8+ 且已安装 NumPy(以官方文档为准)
A = np.array([[1, 2, 3], [4, 5, 6]])
print(A.shape) # (2, 3)
print(A.T.shape) # (3, 2)
print(np.transpose(A).shape) # (3, 2)

官方文档特别指出:对一维数组,transpose返回的是原数组的一个未改动视图——一维没有「行列」可换。要留意多维数组的转置在三维及以上默认是「反转所有轴的顺序」,需要更精细控制时才传axes。


三、矩阵乘法:@、matmul、dot


三种写法:




写法官方签名 / 说明



A @ B运算符,等价于调用__matmul__,Python 3.5 起支持(PEP 465)

numpy.matmul(x1, x2, /, out=None, *, casting='same_kind', order='K', dtype=None, subok=True)函数形式,官方推荐

numpy.dot(a, b, out=None)老的通用函数,文档注明「using matmul or a @ b is preferred」

A * B逐元素相乘,不是矩阵乘



对两个二维数组,@、matmul、dot结果一致:


# 适用于 Python 3.8+ 且已安装 NumPy(以官方文档为准)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

print(A * B)
# [[ 5 12]
# [21 32]] ← 逐元素相乘

print(A @ B)
# [[19 22]
# [43 50]] ← 矩阵乘法

print(np.matmul(A, B)) # 与 A @ B 相同
print(np.dot(A, B)) # 二维时也与 A @ B 相同

验算A @ B第一行第一列:1*5 + 2*7 = 19,对得上;A * B第一行第一列是1*5 = 5,也就是逐元素。


matmul和dot的差异在两处:一是matmul不接受标量,dot可以;二是维数大于 2 时,matmul把数组当成「一批矩阵」并按广播规则处理,dot则是把a的最后一个轴与b的倒数第二个轴求和。日常二维矩阵用哪个都行,但官方推荐matmul或@。


四、线性代数:numpy.linalg


矩阵求逆、行列式、解方程都在numpy.linalg里,签名如下(均以官方文档为准):




函数签名作用



numpy.linalg.invinv(a)求逆矩阵

numpy.linalg.detdet(a)求行列式

numpy.linalg.solvesolve(a, b)解线性方程组a @ x = b

numpy.linalg.eigeig(a)求特征值与特征向量



# 适用于 Python 3.8+ 且已安装 NumPy(以官方文档为准)
import numpy as np

A = np.array([[3.0, 1.0], [1.0, 2.0]])
print(np.linalg.det(A)) # 5.0 (3*2 - 1*1)

inv_A = np.linalg.inv(A)
print(np.allclose(A @ inv_A, np.eye(2))) # True ← 用 allclose 查浮点近似相等

b = np.array([9.0, 8.0])
x = np.linalg.solve(A, b)
print(x) # [2. 3.]
print(np.allclose(A @ x, b)) # True

要点:



  • np.linalg.inv要求矩阵是方阵,否则抛LinAlgError;若矩阵奇异(不可逆),同样抛LinAlgError。

  • 解方程组优先用np.linalg.solve(A, b),而不是先求逆再乘inv(A) @ b——后者数值上更不稳定,也更慢。

  • 判断浮点结果是否相等不要用==,用numpy.allclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)。


实战:解一个线性方程组


下面是一个完整的小例子:解A x = b,再回代验证。


# 适用于 Python 3.8+ 且已安装 NumPy(以官方文档为准)
import numpy as np

def solve_system(A, b):
"""解 A @ x = b,返回解向量;奇异或非方阵时抛 numpy.linalg.LinAlgError。"""
A = np.asarray(A, dtype=float)
b = np.asarray(b, dtype=float)
x = np.linalg.solve(A, b)
ok = np.allclose(A @ x, b)
return x, ok

if __name__ == "__main__":
A = [[2, 1, -1],
[-3, -1, 2],
[-2, 1, 2]]
b = [8, -11, -3]
x, ok = solve_system(A, b)
print("解:", x) # 解: [ 2. 3. -1.]
print("验证:", ok) # 验证: True

逐行说明:



  • np.asarray(...)把列表转成数组,dtype=float保证后续按浮点运算,避免整数下整除问题。

  • np.linalg.solve直接得到未知数向量x,没有显式求逆。

  • np.allclose(A @ x, b)把结果代回验证,浮点误差在你的容差范围内就返回True。


常见坑点



  1. 把*当矩阵乘法


❌C = A * B想做矩阵乘法 —— 得到的其实是逐元素积。 ✅ 矩阵乘用C = A @ B(或np.matmul(A, B))。



  1. 先求逆再乘 b 解方程


❌x = np.linalg.inv(A) @ b—— 数值稳定性差、更慢。 ✅x = np.linalg.solve(A, b)。



  1. 浮点结果用==比较


❌if A @ x == b:—— 浮点误差导致偶尔为假。 ✅if np.allclose(A @ x, b):。



  1. 对非方阵求逆


❌ 对 2x3 矩阵调np.linalg.inv—— 抛numpy.linalg.LinAlgError。 ✅ 确认矩阵是方阵;非方阵要解方程用最小二乘之类的其他方法。



  1. 误以为reshape会复制数据


❌b = a.reshape(2, 3)后改b,以为a不受影响 —— 若返回的是视图,两者共享底层数据。 ✅ 需要独立副本就显式b = a.reshape(2, 3).copy()。



  1. 用numpy.matrix写线性代数


❌ 用np.matrix构造矩阵 —— 官方文档明确「It is no longer recommended to use this class, even for linear algebra. Instead use regular arrays.」,且该类未来可能被移除。 ✅ 用二维ndarray加@运算符。



  1. 在没装 NumPy 的环境里 import


❌import numpy后直接用 —— 未安装会ModuleNotFoundError: No module named 'numpy'。 ✅ 先pip install numpy,并在代码里用try/except ImportError给出友好提示(如果面向他人分发)。



  1. 整数数组下的除法


❌ 用整数类型的数组做平均,期望得到小数 —— 若走的是整除语义会截断。 ✅ 构造时指定dtype=float,或用/得到浮点结果(/在 Python 3 和 NumPy 里都是真除法,整除要写//)。


总结




目的写法备注



构造矩阵np.array、np.zeros、np.ones、np.eye二维ndarray

形状 / 转置.shape、.reshape、.T、np.transposereshape常返回视图

矩阵乘法A @ B、np.matmul(A, B)官方推荐;np.dot亦可

逐元素乘A * B不是矩阵乘法

求逆 / 行列式np.linalg.inv、np.linalg.det需方阵,奇异抛LinAlgError

解方程np.linalg.solve(A, b)优于先求逆

浮点比较np.allclose别用==



NumPy 的矩阵运算记起来不复杂:乘法认准@,*只管逐元素;线性代数进numpy.linalg;结果比较用allclose;再避开np.matrix这个已被官方劝退的老类。由于 NumPy 是第三方库且版本演进较快,实际使用时请以你所用版本的官方文档为准。





需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询