NumPy是Python科学计算的核心库,以高性能的多维数组(ndarray)为基础,提供了丰富的数值计算功能,广泛应用于数据分析、机器学习、科学仿真等领域。
一、前期准备
1. 环境配置
- 安装NumPy:
pip install numpy(建议Python 3.8+版本); - 验证安装:在Python终端执行
import numpy as np,无报错则安装成功; - 辅助工具:Jupyter Notebook(便于分段运行代码、查看结果)。
2. 核心概念梳理
- ndarray:NumPy的核心数据结构,即多维数组,支持同类型元素存储,比Python列表更高效;
- 维度(ndim):数组的轴数,如一维数组(1D)、二维数组(2D,矩阵)、三维数组(3D);
- 形状(shape) :数组各维度的元素个数,如
(3,4)表示3行4列的二维数组; - 数据类型(dtype) :数组元素的类型,如
int32、float64、bool; - 广播机制:不同形状数组间运算时,NumPy自动扩展数组维度以匹配形状的规则;
- 线性代数:基于ndarray实现矩阵乘法、求逆、特征值、行列式等运算。
二、实战1:多维数组核心操作
多维数组是NumPy的基础,掌握创建、索引、变形、拼接等操作,是后续计算的前提。
1. 数组创建(常用方式)
python
import numpy as np
# 1. 从列表/嵌套列表创建
arr1 = np.array([1, 2, 3, 4]) # 一维数组
arr2 = np.array([[1, 2], [3, 4], [5, 6]]) # 二维数组(3行2列)
print("一维数组:\n", arr1)
print("二维数组形状:", arr2.shape) # 输出:(3, 2)
# 2. 特殊数组创建(实战高频)
arr_zeros = np.zeros((2, 3)) # 全0数组(2行3列)
arr_ones = np.ones((3, 3), dtype=np.int32) # 全1数组,指定int32类型
arr_empty = np.empty((2, 2)) # 空数组(内存随机值,仅占位)
arr_range = np.arange(0, 10, 2) # 等差数列:0,2,4,6,8
arr_linspace = np.linspace(0, 1, 5) # 等间隔数组:0,0.25,0.5,0.75,1
arr_eye = np.eye(3) # 单位矩阵(3x3)
print("单位矩阵:\n", arr_eye)
2. 数组索引与切片
(1)一维数组(与Python列表类似)
python
arr = np.arange(10)
print(arr[5]) # 索引:取第6个元素(5)
print(arr[2:7]) # 切片:2-6(左闭右开)
print(arr[::2]) # 步长2:0,2,4,6,8
(2)二维数组(行+列索引)
python
arr = np.array([[1,2,3], [4,5,6], [7,8,9]])
# 取第2行第3列元素(6)
print(arr[1, 2])
# 取第1行所有列
print(arr[0, :])
# 取所有行的第2列
print(arr[:, 1])
# 取前2行、前2列
print(arr[:2, :2])
# 布尔索引:筛选大于5的元素
print(arr[arr > 5]) # 输出:[6 7 8 9]
3. 数组变形与重塑
python
arr = np.arange(12)
# 重塑为3行4列
arr_reshape = arr.reshape(3, 4)
print("重塑后:\n", arr_reshape)
# 展平数组(多维转一维)
arr_flat = arr_reshape.flatten() # 拷贝数据,原数组不变
arr_ravel = arr_reshape.ravel() # 视图,原数组改变会同步
print("展平数组:", arr_flat)
# 转置(行变列,列变行)
arr_trans = arr_reshape.T
print("转置后:\n", arr_trans)
4. 数组拼接与分割
python
# 拼接
arr1 = np.array([[1,2], [3,4]])
arr2 = np.array([[5,6], [7,8]])
# 纵向拼接(行增加)
arr_vstack = np.vstack((arr1, arr2))
# 横向拼接(列增加)
arr_hstack = np.hstack((arr1, arr2))
print("纵向拼接:\n", arr_vstack)
print("横向拼接:\n", arr_hstack)
# 分割
arr = np.arange(9).reshape(3,3)
# 横向分割(按列分)
arr_split1, arr_split2 = np.hsplit(arr, 2)
# 纵向分割(按行分)
arr_split3, arr_split4 = np.vsplit(arr, 2)
print("横向分割结果:\n", arr_split1)
三、实战2:广播机制(核心难点)
广播是NumPy中不同形状数组间运算的核心规则,能避免手动扩展数组,提升计算效率。
1. 广播的核心规则
- 规则1:如果两个数组维度不同,先将维度少的数组补1,直到维度数相同;
- 规则2:对于每个维度,若长度相同或其中一个为1,则可以广播,否则报错;
- 规则3:广播时,长度为1的维度会被扩展为匹配另一个数组的长度。
2. 基础广播案例
python
# 案例1:标量与数组运算(最常见)
arr = np.array([1,2,3])
result = arr + 5 # 标量5广播为[5,5,5]
print("标量广播:", result) # 输出:[6 7 8]
# 案例2:一维数组与二维数组运算
arr1 = np.array([[1,2,3], [4,5,6]]) # (2,3)
arr2 = np.array([10, 20, 30]) # (3,) → 补1为(1,3) → 广播为(2,3)
result = arr1 + arr2
print("一维+二维广播:\n", result)
# 输出:
# [[11 22 33]
# [14 25 36]]
# 案例3:不同维度广播(需满足规则)
arr3 = np.array([[1], [2], [3]]) # (3,1)
arr4 = np.array([10, 20]) # (2,) → 补1为(1,2) → 广播为(3,2)
result = arr3 * arr4
print("不同维度广播:\n", result)
# 输出:
# [[10 20]
# [20 40]
# [30 60]]
# 错误案例(不满足规则)
# arr5 = np.array([1,2]) # (2,)
# arr6 = np.array([[1,2,3], [4,5,6]]) # (2,3)
# result = arr5 + arr6 # 报错:维度不匹配
3. 广播的实战应用(数据归一化)
python
# 对二维数组每行进行归一化:(值-均值)/标准差
data = np.array([[1,2,3], [4,5,6], [7,8,9]])
# 计算每行均值(axis=1,保持维度便于广播)
mean = np.mean(data, axis=1, keepdims=True)
# 计算每行标准差
std = np.std(data, axis=1, keepdims=True)
# 广播运算
normalized_data = (data - mean) / std
print("归一化后:\n", normalized_data)
# 输出每行均值为0,标准差为1的数组
四、实战3:线性代数运算(核心应用)
NumPy的numpy.linalg模块提供了完整的线性代数运算接口,满足矩阵分析、线性方程组求解等需求。
1. 基础矩阵运算
python
# 矩阵乘法(注意:不是元素相乘)
A = np.array([[1,2], [3,4]])
B = np.array([[5,6], [7,8]])
# 方法1:np.dot()(兼容一维/二维)
dot_result = np.dot(A, B)
# 方法2:@运算符(Python 3.5+,推荐)
at_result = A @ B
print("矩阵乘法:\n", at_result)
# 输出:
# [[19 22]
# [43 50]]
# 元素相乘(与矩阵乘法区分)
element_mul = A * B
print("元素相乘:\n", element_mul)
# 输出:
# [[ 5 12]
# [21 32]]
# 矩阵求逆(仅方阵且可逆)
A_inv = np.linalg.inv(A)
print("矩阵A的逆:\n", A_inv)
# 矩阵转置
A_trans = A.T
print("矩阵A的转置:\n", A_trans)
# 行列式计算
det_A = np.linalg.det(A)
print("矩阵A的行列式:", det_A) # 输出:-2.0000000000000004
2. 线性方程组求解
求解方程组:
ini
x + 2y = 5
3x + 4y = 13
转化为矩阵形式:Ax = b,其中A=[[1,2],[3,4]],b=[5,13],求解x。
python
A = np.array([[1,2], [3,4]])
b = np.array([5, 13])
# 求解线性方程组
x = np.linalg.solve(A, b)
print("方程组解:x={}, y={}".format(x[0], x[1])) # 输出:x=3.0, y=1.0
# 验证:A @ x 应等于b
print("验证结果:", A @ x) # 输出:[ 5. 13.]
3. 特征值与特征向量
python
# 计算特征值和特征向量
A = np.array([[1,2], [3,4]])
eigenvalues, eigenvectors = np.linalg.eig(A)
print("特征值:", eigenvalues)
print("特征向量:\n", eigenvectors)
# 验证:A·v = λ·v(v为特征向量,λ为特征值)
v = eigenvectors[:, 0] # 第一个特征向量
lamda = eigenvalues[0] # 第一个特征值
print("验证特征值:", np.allclose(A @ v, lamda * v)) # 输出:True
4. 奇异值分解(SVD,实战高频)
python
# 奇异值分解(适用于非方阵)
A = np.array([[1,2,3], [4,5,6]])
U, S, VT = np.linalg.svd(A)
print("U矩阵:\n", U)
print("奇异值:", S)
print("VT矩阵:\n", VT)
# 重构矩阵(验证SVD)
# 需将S转为对角矩阵
S_mat = np.zeros((2,3))
S_mat[:2, :2] = np.diag(S)
A_recon = U @ S_mat @ VT
print("重构矩阵与原矩阵是否一致:", np.allclose(A, A_recon)) # 输出:True
五、实战优化技巧
1. 避免循环,用向量化运算
NumPy向量化运算比Python循环快10~100倍,例如:
python
# 低效:循环计算
arr = np.arange(1000000)
result = []
for x in arr:
result.append(x * 2 + 1)
result = np.array(result)
# 高效:向量化运算
result = arr * 2 + 1 # 广播机制自动处理
2. 数据类型优化
默认float64精度高但占用内存,可根据需求改为float32:
python
arr = np.ones((1000, 1000), dtype=np.float32) # 内存占用减少一半
3. 避免拷贝,使用视图
python
arr1 = arr.reshape(-1) # -1自动计算维度,视图无拷贝
arr2 = arr[:, ::2] # 切片为视图,原数组修改会同步
arr3 = arr.copy() # 仅需独立数据时拷贝
六、常见问题与解决
1. 广播报错:维度不匹配
- 排查:打印数组
shape,确认是否满足广播规则; - 解决:用
reshape手动扩展维度,例如arr = arr.reshape(-1, 1)。
2. 矩阵乘法与元素相乘混淆
- 区分:
A @ B是矩阵乘法,A * B是元素相乘; - 注意:矩阵乘法要求前一个数组列数=后一个数组行数。
3. 求逆报错:奇异矩阵
- 原因:矩阵行列式为0,不可逆;
- 解决:检查矩阵是否正确,或使用伪逆
np.linalg.pinv(A)。
4. 精度问题
- 现象:浮点数运算出现
0.9999999999而非1; - 解决:用
np.allclose(a, b)代替a == b比较数组。