3、Python基础回顾:NumPy数组操作与广播机制,Matplotlib数据可视化,Pandas数据处理基础

说实话,很多初学者一上来就扎进深度学习框架,结果连数据怎么装、怎么画、怎么清洗都搞不定。我见过太多人卡在数据预处理这一步了。今天咱们就把这三个库彻底捋一遍,这些都是我每天写代码都要用的东西。

3.1 NumPy:深度学习的数据骨架

NumPy 的 ndarray 是深度学习中最基础的数据结构。说白了,你训练模型时喂进去的数据,本质上都是 NumPy 数组。PyTorch 和 TensorFlow 的张量,底层设计思路也大量借鉴了 NumPy。

3.1.1 创建数组的几种姿势

我个人习惯用 np.array() 从列表创建,但更常用的是下面这些快捷方式:

import numpy as np

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

# 全一数组
ones = np.ones((2, 3))

# 单位矩阵
eye = np.eye(5)

# 随机数组,这个在初始化参数时特别常用
random_arr = np.random.randn(3, 3)  # 标准正态分布

# 等差数列,常用于生成坐标轴
x = np.linspace(0, 10, 100)  # 从0到10均匀取100个点
我的小习惯: 创建随机数组时,我一般用 np.random.seed(42) 固定随机种子。这样每次运行结果都一样,调试起来方便很多。

3.1.2 数组形状操作

深度学习里最常干的事就是 reshape。你想想看,一张图片读进来可能是 (H, W, C),但模型输入要求 (batch, C, H, W),这时候就得靠 reshape 和 transpose 了。

arr = np.arange(12)  # [0, 1, 2, ..., 11]

# 重塑形状
reshaped = arr.reshape(3, 4)  # 变成3行4列

# 展平,这个在连接全连接层时必用
flattened = arr.flatten()

# 转置,图像通道变换时常用
transposed = reshaped.T

# 增加或减少维度
expanded = np.expand_dims(arr, axis=0)  # 变成 (1, 12)
squeezed = np.squeeze(expanded)         # 去掉维度为1的轴
注意: reshape 和 resize 不一样。reshape 返回新数组,不修改原数组;resize 会直接修改原数组。我曾经在这上面吃过亏,调试了半天才发现是原数组被改了。

3.1.3 广播机制:NumPy 的灵魂

广播机制是 NumPy 最强大的特性之一。它允许不同形状的数组进行算术运算。嗯,这里要注意,广播不是万能的,它有严格的规则。

广播的核心规则: 从尾部维度开始比较,要么维度相等,要么其中一个维度为1,要么其中一个数组没有这个维度。

# 经典例子:给每行加上一个偏置
data = np.array([[1, 2, 3],
                 [4, 5, 6],
                 [7, 8, 9]])
bias = np.array([10, 20, 30])

# 广播自动将 bias 扩展成 (3, 3)
result = data + bias
print(result)
# [[11 22 33]
#  [14 25 36]
#  [17 28 39]]

我在项目中遇到过一个问题:两个数组形状分别是 (3, 1) 和 (1, 4),广播后得到 (3, 4)。当时我以为是 bug,后来才发现这就是广播的典型用法,用来做外积运算。

广播的常见应用场景:
  • 给所有样本减去均值(标准化)
  • 给每行加上不同的偏置
  • 特征缩放时除以标准差

3.2 Matplotlib:让数据说话

做深度学习,可视化是必不可少的。你总得看看损失曲线下降得漂不漂亮,特征分布长什么样吧?Matplotlib 就是干这个的。

3.2.1 快速画图三板斧

import matplotlib.pyplot as plt

# 1. 折线图 - 看损失曲线
epochs = range(1, 101)
loss = [0.9 / (1 + 0.05 * i) for i in epochs]  # 模拟损失下降
plt.plot(epochs, loss, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.legend()
plt.show()

# 2. 散点图 - 看数据分布
x = np.random.randn(100)
y = 2 * x + 1 + np.random.randn(100) * 0.5
plt.scatter(x, y, alpha=0.6)
plt.xlabel('Feature X')
plt.ylabel('Target Y')
plt.show()

# 3. 直方图 - 看数值分布
data = np.random.randn(1000)
plt.hist(data, bins=30, alpha=0.7, edgecolor='black')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()
我的调试技巧: 训练模型时,我习惯每 10 个 epoch 画一次损失曲线。如果曲线突然上翘,说明学习率可能太大了。如果曲线太平,说明模型可能没学到东西。

3.2.2 子图布局

实际项目中,经常需要把多个图放在一起对比。比如同时看训练损失和验证损失。

fig, axes = plt.subplots(1, 2, figsize=(12, 4))

# 左图:损失曲线
axes[0].plot(epochs, train_loss, label='Train', color='blue')
axes[0].plot(epochs, val_loss, label='Validation', color='red')
axes[0].set_title('Loss')
axes[0].legend()

# 右图:准确率曲线
axes[1].plot(epochs, train_acc, label='Train', color='blue')
axes[1].plot(epochs, val_acc, label='Validation', color='red')
axes[1].set_title('Accuracy')
axes[1].legend()

plt.tight_layout()
plt.show()

3.3 Pandas:数据清洗的瑞士军刀

真实世界的数据哪有那么干净?缺失值、重复值、异常值,什么妖魔鬼怪都有。Pandas 就是用来处理这些脏数据的。

3.3.1 读取与预览数据

import pandas as pd

# 读取 CSV 文件
df = pd.read_csv('data.csv')

# 快速预览
print(df.head())      # 前5行
print(df.info())      # 数据类型和缺失值
print(df.describe())  # 统计摘要

# 查看列名
print(df.columns.tolist())

3.3.2 数据清洗三板斧

第一板斧:处理缺失值

# 检查缺失值
print(df.isnull().sum())

# 删除有缺失值的行
df_clean = df.dropna()

# 填充缺失值(常用方法)
df['age'].fillna(df['age'].median(), inplace=True)  # 用中位数填充
df['income'].fillna(0, inplace=True)                # 用0填充
df['category'].fillna('Unknown', inplace=True)      # 用固定值填充

第二板斧:处理重复值

# 检查重复行
print(df.duplicated().sum())

# 删除重复行
df_unique = df.drop_duplicates()

# 按指定列去重
df_unique = df.drop_duplicates(subset=['user_id'])

第三板斧:处理异常值

# 用 IQR 方法检测异常值
Q1 = df['price'].quantile(0.25)
Q3 = df['price'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 过滤异常值
df_filtered = df[(df['price'] >= lower_bound) & (df['price'] <= upper_bound)]
我曾经踩过的坑: 有一次处理用户行为数据,直接删除了所有缺失值,结果发现删掉了 40% 的数据。后来才知道,有些缺失值其实是「用户没有这个行为」,应该用 0 填充而不是删除。所以处理缺失值前,一定要先理解业务含义。

3.3.3 数据变换与分组

# 创建新特征
df['age_group'] = pd.cut(df['age'], bins=[0, 18, 35, 60, 100], 
                         labels=['少年', '青年', '中年', '老年'])

# 分组聚合
grouped = df.groupby('age_group')['income'].agg(['mean', 'std', 'count'])
print(grouped)

# 数据透视表
pivot = pd.pivot_table(df, values='income', index='age_group', 
                       columns='gender', aggfunc='mean')

3.4 三个库的协同工作

实际项目中,这三个库是配合使用的。我一般的工作流是这样的:

  1. Pandas 读取和清洗数据:处理缺失值、异常值、特征工程
  2. NumPy 转换数据格式:把 DataFrame 转成 ndarray,做标准化、归一化
  3. Matplotlib 可视化验证:画分布图、相关性热力图,确认数据质量
# 完整示例:数据预处理流水线
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 1. 读取数据
df = pd.read_csv('housing.csv')

# 2. 清洗:填充缺失值
df['total_bedrooms'].fillna(df['total_bedrooms'].median(), inplace=True)

# 3. 特征工程:创建新特征
df['rooms_per_household'] = df['total_rooms'] / df['households']

# 4. 转换为 NumPy 数组
features = ['median_income', 'rooms_per_household', 'housing_median_age']
X = df[features].values

# 5. 标准化
mean = X.mean(axis=0)
std = X.std(axis=0)
X_normalized = (X - mean) / std

# 6. 可视化验证
plt.figure(figsize=(10, 6))
plt.hist(X_normalized[:, 0], bins=50, alpha=0.7)
plt.title('Normalized Median Income Distribution')
plt.show()
总结一下:
  • NumPy 负责数学运算和数组操作,广播机制要烂熟于心
  • Matplotlib 负责可视化,损失曲线和分布图是调试利器
  • Pandas 负责数据清洗,缺失值和异常值处理是基本功

这三个库是深度学习的基石。我建议你花一周时间,把上面的代码都敲一遍。相信我,后面学 PyTorch 的时候,你会感谢现在的自己。


公众号:蓝海资料掘金营,微信deep3321