3、Python数据科学基础速通:NumPy数组操作、Matplotlib可视化、Pandas数据处理
好,咱们直接进入正题。做深度学习,说白了就是跟数据打交道。图像进来是像素矩阵,训练过程要算梯度,结果要画曲线——这三样东西,NumPy、Matplotlib、Pandas 就是你的左膀右臂。我个人习惯把这仨称为「数据科学三件套」,今天带你速通一遍。
3.1 NumPy:深度学习的心脏
NumPy 的核心就是 ndarray,也就是多维数组。你想想看,一张彩色图片是什么?不就是 (H, W, 3) 的三维数组嘛。模型里的权重、偏置,全是 NumPy 数组。
3.1.1 创建数组
import numpy as np
# 从列表创建
arr = np.array([1, 2, 3, 4, 5])
# 全零数组,常用于初始化偏置
zeros = np.zeros((3, 4))
# 全一数组,常用于初始化权重
ones = np.ones((2, 3))
# 随机数组,模型初始化必备
rand = np.random.randn(3, 3) # 标准正态分布
# 等差数列,画图时经常用
x = np.linspace(0, 10, 100) # 0到10之间均匀取100个点
我的小习惯:初始化权重时,我一般用 np.random.randn 再乘以一个缩放因子,比如 0.01。直接 randn 有时候会让梯度爆炸,尤其是深层网络。
3.1.2 数组运算
NumPy 的广播机制,嗯,这里要注意。它能让不同形状的数组做运算,省去你写循环的麻烦。
a = np.array([[1, 2], [3, 4]])
b = np.array([10, 20])
# 广播:b 会被自动扩展成 [[10,20], [10,20]]
c = a + b # 结果:[[11, 22], [13, 24]]
# 矩阵乘法,深度学习前向传播的核心
d = np.dot(a, b) # 或者 a @ b
我曾经踩过的坑:广播虽然方便,但形状不匹配时会静默出错。比如你想做 (3,4) 和 (4,3) 的矩阵乘,结果写成了 a * b(逐元素乘),NumPy 不会报错,但结果完全不对。所以每次运算前,我习惯先 print(a.shape, b.shape) 看一眼。
3.1.3 索引与切片
图像处理里,切片用得特别多。比如你想取一张图的左上角 100x100 区域:
img = np.random.randn(224, 224, 3)
patch = img[0:100, 0:100, :] # 取左上角
# 布尔索引,筛选出大于0.5的像素
mask = img > 0.5
high_values = img[mask]
3.2 Matplotlib:让数据说话
做深度学习,你不看曲线怎么知道模型在收敛还是发散?Matplotlib 就是你的眼睛。
3.2.1 基础绘图
import matplotlib.pyplot as plt
# 训练损失曲线
epochs = range(1, 101)
train_loss = np.random.randn(100).cumsum() + 10 # 模拟下降
val_loss = np.random.randn(100).cumsum() + 12
plt.figure(figsize=(10, 6))
plt.plot(epochs, train_loss, label='训练损失', color='blue')
plt.plot(epochs, val_loss, label='验证损失', color='red', linestyle='--')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('训练过程监控')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
关键点:验证损失如果开始上升而训练损失还在下降,那就是过拟合了。我一般会在验证损失连续 5 个 epoch 不降时,触发早停。
3.2.2 子图与图像显示
做图像分类时,我经常需要同时看原始图和预测结果。子图就派上用场了。
fig, axes = plt.subplots(2, 3, figsize=(12, 8))
for i, ax in enumerate(axes.flat):
ax.imshow(np.random.randn(32, 32, 3)) # 模拟显示6张图
ax.set_title(f'样本 {i+1}')
ax.axis('off')
plt.tight_layout()
plt.show()
3.3 Pandas:表格数据的瑞士军刀
虽然图像本身是数组,但图像的标签、路径、元数据,用 Pandas 管理最方便。说白了,DataFrame 就是一张 Excel 表,但比 Excel 强大一百倍。
3.3.1 读取与创建
import pandas as pd
# 从字典创建
data = {
'图片路径': ['cat_001.jpg', 'dog_002.jpg', 'bird_003.jpg'],
'标签': ['猫', '狗', '鸟'],
'宽度': [224, 320, 256],
'高度': [224, 240, 256]
}
df = pd.DataFrame(data)
# 读取CSV,数据集标注文件常用格式
# df = pd.read_csv('annotations.csv')
3.3.2 常用操作
# 查看前5行
print(df.head())
# 筛选出所有猫的图片
cats = df[df['标签'] == '猫']
# 分组统计各类别数量
counts = df.groupby('标签').size()
print(counts)
# 添加新列:计算面积
df['面积'] = df['宽度'] * df['高度']
我常用的技巧:训练集和验证集划分,我一般用 sklearn 的 train_test_split,但如果你不想引入新库,Pandas 的 sample 和 drop 也能搞定:
train = df.sample(frac=0.8, random_state=42)val = df.drop(train.index)
3.3.3 与NumPy的联动
Pandas 和 NumPy 是无缝衔接的。你从 DataFrame 里取一列,得到的就是 NumPy 数组。
# 提取标签列转为NumPy数组
labels = df['标签'].values # 或者 df['标签'].to_numpy()
# 对数值列做统计
mean_width = df['宽度'].mean()
print(f'平均宽度: {mean_width:.1f} 像素')
注意:Pandas 的 .values 在旧版本中常用,新版本推荐用 .to_numpy()。我遇到过因为版本问题,.values 返回的是视图而不是副本,导致后续修改出了问题。所以现在统一用 to_numpy()。
3.4 三件套的实战配合
最后,我带你走一遍实际工作流。假设你有一个图像分类项目:
- Pandas 读取标注 CSV,得到图片路径和标签
- NumPy 把图片加载成数组,做归一化、数据增强
- Matplotlib 显示预处理后的样本,检查有没有问题
- 训练过程中,用 Matplotlib 实时画损失曲线
- 训练结束后,用 Pandas 分析各类别的准确率
你看,这三个库环环相扣。我个人觉得,把这套流程跑通一遍,比死记硬背 API 有用得多。嗯,今天就到这里,下一章咱们开始搭建真正的卷积神经网络。