NumPy入门:面试官问“Python怎么做矩阵运算“,别说用嵌套list
Python基础打好了,今天进入NumPy。
NumPy是Python科学计算的基石。做机器人开发,处理传感器数据、做矩阵运算、跑算法原型,几乎离不开它。面试的时候,如果岗位涉及Python开发,NumPy是必考内容。
先说个对比。
C++里做矩阵运算,你可能会用Eigen。Python里对应的就是NumPy。Eigen的Matrix类型,在NumPy里是ndarray。Eigen有矩阵乘法、求逆、特征值分解,NumPy全都有。
但NumPy比Eigen更通用——它不只是矩阵库,而是一个多维数组处理框架。图像数据是三维数组(高x宽x通道),点云是二维数组(Nx3),时间序列是一维数组。NumPy统一处理这些数据格式。
ndarray:NumPy的核心对象
NumPy的核心是ndarray——N维数组。和Python原生的list相比,ndarray有两个关键优势。
第一,内存连续。ndarray在内存中是连续存储的,和C的数组一样。这意味着CPU缓存命中率高,遍历速度快。Python的list存的是对象指针,每个元素散落在堆内存的不同位置。
第二,向量化运算。ndarray支持逐元素运算,不需要写循环:
import numpy as np
a = np.array([1.0, 2.0, 3.0])
b = np.array([4.0, 5.0, 6.0])
c = a + b # [5.0, 7.0, 9.0]
d = a * b # [4.0, 10.0, 18.0]
e = np.dot(a, b) # 32.0 点积
同样的操作,如果用Python list写,需要for循环或者列表推导式。NumPy的向量化运算底层是C实现,比纯Python快几十倍甚至上百倍。
创建数组的几种方式
# 从list创建
arr = np.array([1, 2, 3, 4])
# 常用工厂函数
zeros = np.zeros((3, 4)) # 3x4全零矩阵
ones = np.ones((2, 3)) # 2x3全一矩阵
eye = np.eye(3) # 3x3单位矩阵
rand = np.random.rand(3, 4) # 3x4随机矩阵
# 等差序列
linspace = np.linspace(0, 1, 100) # 0到1之间100个均匀点
arange = np.arange(0, 10, 0.5) # 0到10,步长0.5
在机器人开发中,np.zeros常用于初始化缓冲区,np.linspace常用于生成轨迹插值点,np.eye常用于构造变换矩阵。
数组操作:reshape、切片、广播
reshape——改变数组形状但不改变数据:
# 一个12元素的一维数组
flat = np.arange(12)
# 变成3x4的矩阵
matrix = flat.reshape(3, 4)
# 变成2x2x3的三维数组
tensor = flat.reshape(2, 2, 3)
# -1表示自动推断维度
matrix2 = flat.reshape(3, -1) # 等价于reshape(3, 4)
切片——和Python list类似但更强大:
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
data[0, :] # 第一行: [1, 2, 3]
data[:, 1] # 第二列: [2, 5, 8]
data[0:2, 1:] # 子矩阵: [[2, 3], [5, 6]]
注意:NumPy的切片返回的是视图(view),不是拷贝。修改视图会改变原数组。如果需要独立的副本,用.copy():
sub = data[0:2, :].copy() # 独立副本
广播(broadcasting)——不同形状的数组之间做运算:
# 一个3x4矩阵加上一个长度为4的向量
matrix = np.ones((3, 4))
vector = np.array([1, 2, 3, 4])
result = matrix + vector # 自动广播,每行都加上vector
广播规则是:两个数组的维度从右往左对齐,每个维度要么相等,要么其中一个是1。不满足规则会报ValueError。
数学运算和统计
data = np.random.rand(1000)
# 统计
mean = np.mean(data)
std = np.std(data)
max_val = np.max(data)
min_val = np.min(data)
# 矩阵运算
A = np.random.rand(3, 3)
B = np.random.rand(3, 3)
C = A @ B # 矩阵乘法(等价于np.dot(A, B))
A_inv = np.linalg.inv(A) # 求逆
eigenvalues = np.linalg.eig(A) # 特征值分解
@运算符是Python 3.5引入的矩阵乘法符号,比np.dot更直观。
数据类型和内存
NumPy数组是同质(homogeneous)的——所有元素必须是同一类型。这和Python list不同,list可以混合存放不同类型。
arr_float64 = np.array([1.0, 2.0], dtype=np.float64) # 默认
arr_float32 = np.array([1.0, 2.0], dtype=np.float32) # 省内存
arr_int32 = np.array([1, 2, 3], dtype=np.int32)
在机器人系统中,如果精度要求高(比如SLAM中的位姿估计),用float64;如果数据量大但对精度要求不高(比如点云可视化),用float32可以省一半内存。
另一个值得注意的点:NumPy默认是C顺序(行优先),和C++一样。但Fortran顺序(列优先)在某些线性代数运算中更高效。用order='F'可以指定。如果你从Fortran或MATLAB迁移过来,这个设置很重要。
NumPy常见踩坑记录
新手用NumPy最容易犯的错误之一是"切片修改了原数组"。a = np.array([1,2,3]); b = a[:2]; b[0] = 99,结果a也变了。这是因为b是a的视图,不是副本。解决方式是显式.copy()。但在大数组上频繁copy会影响性能,所以要在"安全"和"效率"之间取舍。
另一个坑是"整数溢出"。np.array([200], dtype=np.int8) + np.array([100], dtype=np.int8)的结果不是300而是-56,因为int8的范围是-128到127。NumPy不会像Python那样自动提升精度,溢出是静默发生的。处理传感器数据时,建议统一用float64或者明确检查数据范围,避免这种隐蔽的bug。
和机器人开发的联系
在机器人开发中,NumPy的使用场景非常多。传感器数据处理——激光雷达的扫描数据就是一个Nx2或Nx3的数组,用NumPy做滤波、变换非常方便。坐标变换——旋转矩阵、平移向量都是NumPy数组,矩阵乘法一步搞定。轨迹生成——用linspace生成时间序列,用向量化运算计算每个时刻的位置。
后面聊Eigen的时候我们用过C++做这些运算。在Python里,NumPy就是Eigen的替代品。区别是NumPy更快(原型开发阶段),Eigen更适合生产部署。
说到性能优化,面试中经常被问到的一点是:为什么NumPy比纯Python快?核心原因有三个:一是连续内存带来的缓存友好性,二是向量化操作避免了Python解释器的循环开销,三是底层C实现使用了高度优化的BLAS库。理解了这三点,面试时回答这个问题就不会只停留在因为用C写的这个表面答案了。
给正在准备面试的你
NumPy在Python面试中属于"中等频率"考点。建议你至少掌握:数组创建、reshape、切片、广播、基本的矩阵运算。这些是后续学pandas、Matplotlib、PyTorch的基础。
下篇NumPy进阶——矩阵运算与机器人运动学计算。我们会用NumPy来实现一些机器人学中的经典计算,比如旋转矩阵、四元数转换、正运动学。
如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。
「机器人软件开发面试·从入门到精通」连载系列 上一篇:第70篇 Python文件与数据处理——CSV/JSON/YAML的读写 下一篇预告:第72篇 NumPy进阶——矩阵运算与机器人运动学计算
有任何问题欢迎评论区留言,我会尽量回复。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)