4. NumPy核心操作:数组创建与索引、矩阵运算、统计函数、随机数生成

各位同学,咱们今天聊点硬核的。NumPy,说白了就是Python科学计算的基石。我刚开始做运动控制仿真那会儿,数据量一大,纯Python列表处理起来慢得让人抓狂。后来用了NumPy,才真正体会到什么叫「飞一般的感觉」。

这一节,我带你过一遍NumPy最核心的四个操作。你想想看,搞运动控制,哪个环节离得开数组、矩阵、统计和随机数?一个都跑不掉。

核心要点:NumPy的核心是ndarray对象。它比Python原生列表快几十倍,原因在于底层用C语言实现,并且支持向量化操作。说白了,就是一次处理一批数据,而不是一个个循环。

4.1 数组创建与索引

创建数组是第一步。我个人习惯用 np.array() 从列表转换,但更常用的是 np.zeros()np.ones()np.arange()

import numpy as np

# 从列表创建
arr1 = np.array([1, 2, 3, 4, 5])

# 全零数组,常用于初始化
zeros = np.zeros((3, 4))

# 等差数列,类似range
arr2 = np.arange(0, 10, 2)  # [0, 2, 4, 6, 8]

# 等间隔数组,指定个数
arr3 = np.linspace(0, 1, 5)  # [0. , 0.25, 0.5, 0.75, 1. ]

索引这块,我踩过坑。有一次做轨迹规划,需要提取某一段位置数据,直接用 arr[1:3] 切片,结果发现修改切片会影响原数组。为什么?因为NumPy切片返回的是视图,不是副本。嗯,这里要注意:

避坑指南:NumPy切片默认是浅拷贝(视图)。如果你需要独立的数据,一定要用 .copy() 方法。我曾经因为这个问题,调试了一下午才发现数据被意外修改了。

# 索引示例
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 取单个元素
print(arr[1, 2])  # 6

# 取一行
print(arr[0, :])  # [1, 2, 3]

# 布尔索引——这个在运动控制中非常实用
mask = arr > 5
print(arr[mask])  # [6, 7, 8, 9]

4.2 矩阵运算

运动控制里,矩阵运算无处不在。坐标变换、雅可比矩阵、动力学方程……全是矩阵。NumPy的矩阵运算,我总结为三类:

运算类型 运算符/函数 说明
逐元素运算 +, -, *, / 对应位置元素直接运算
矩阵乘法 @np.dot() 线性代数中的矩阵乘法
转置/逆 .T, np.linalg.inv() 矩阵转置和求逆
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 逐元素乘法
C = A * B  # [[5, 12], [21, 32]]

# 真正的矩阵乘法
D = A @ B  # [[19, 22], [43, 50]]

# 转置
print(A.T)  # [[1, 3], [2, 4]]

# 求逆
inv_A = np.linalg.inv(A)

我记得有一次做六轴机器人的逆解,需要频繁计算3x3旋转矩阵的逆。用 np.linalg.inv() 虽然方便,但计算量不小。后来我改用解析公式,速度提升了近10倍。所以,能用解析解就别用数值解,这是性能优化的铁律。

4.3 统计函数

统计函数在仿真分析中用来评估性能。比如,分析电机转速的波动、计算轨迹跟踪误差的均值方差等。

data = np.array([2.1, 2.3, 2.0, 2.4, 2.2, 2.5, 2.1])

# 基本统计量
mean = np.mean(data)      # 均值
std = np.std(data)        # 标准差
max_val = np.max(data)    # 最大值
min_val = np.min(data)    # 最小值

# 百分位数——我常用它来评估控制精度
p50 = np.percentile(data, 50)   # 中位数
p95 = np.percentile(data, 95)   # 95%分位点

print(f"均值: {mean:.3f}, 标准差: {std:.3f}")
print(f"95%误差在: {p95:.3f} 以内")

实用技巧:在运动控制仿真中,我习惯用 np.percentile(data, [5, 95]) 来评估误差的分布范围。这比单纯看最大值更靠谱,因为最大值可能只是某个瞬间的毛刺。

4.4 随机数生成

随机数在仿真中用来模拟噪声、初始化参数、做蒙特卡洛分析。NumPy的随机模块 np.random 功能很全。

# 设置种子,保证结果可复现
np.random.seed(42)

# 均匀分布 [0, 1)
rand_uniform = np.random.rand(3, 3)

# 正态分布
rand_normal = np.random.randn(1000)  # 均值0,标准差1

# 整数随机
rand_int = np.random.randint(0, 10, size=(2, 3))

# 打乱数组——做数据增强时常用
arr = np.array([1, 2, 3, 4, 5])
np.random.shuffle(arr)

你想想看,做运动控制仿真时,传感器噪声怎么模拟?我一般用 np.random.normal(0, 0.01, size=data.shape) 来生成高斯白噪声,然后叠加到真实信号上。这样仿真结果才贴近实际。

注意:每次运行前设置 np.random.seed() 是个好习惯。否则两次运行结果不同,你根本没法判断是算法改进带来的提升,还是随机性导致的波动。我早期吃过这个亏,后来就养成了固定种子的习惯。

知识体系总览

下面这张图,是我梳理的NumPy核心操作知识结构。你可以把它当作一个快速索引图,用到哪个知识点,回来查一下就行。

NumPy核心操作 数组创建与索引 创建方式 np.array / np.zeros np.arange / np.linspace 索引技巧 切片 / 布尔索引 / 花式索引 矩阵运算 运算类型 逐元素运算 (+ - * /) 矩阵乘法 (@ / np.dot) 线性代数 转置 .T / 求逆 np.linalg.inv 统计函数 常用统计量 均值 / 标准差 / 方差 最大值 / 最小值 / 求和 高级应用 百分位数 / 累积和 随机数生成 分布类型 均匀分布 np.random.rand 正态分布 np.random.randn 实用技巧 设置种子 / 打乱数组 应用场景:运动控制仿真、轨迹规划、传感器噪声模拟、性能评估

好了,这一节的内容就这些。数组创建是基础,矩阵运算是核心,统计函数帮你分析数据,随机数生成让仿真更真实。这四个模块,你在运动控制仿真中几乎每天都会用到。

我个人建议,学完这一节后,马上打开Jupyter Notebook,把上面的代码敲一遍。光看不练,等于白学。你想想看,代码这东西,敲一遍和看十遍,效果天差地别。

专注资料整理