3-1 NumPy数据的容器及数据集划分
📌 一、 课程导入(10 分钟)
-
对比实验:杂物箱 vs 专用零件盒
- Python 原生
list就像一个杂物箱,里面装的是指向乱七八糟内存地址的“纸条(指针)”,遍历修改极慢。 - NumPy 的
ndarray就像精密的零件盒,在内存中是一块连续紧密平铺的存储空间,只能存同一种类型,支持 CPU 矢量并行计算。
- Python 原生
-
直观感受“向量化计算”的威力
- 在 Jupyter Notebook 中给 500 万个数字同时乘以 2,对比耗时:
- 原生
for循环修改原列表:耗时约 0.33 秒。 - NumPy 向量化计算 (
array * 2):耗时仅约 0.002 秒(快了上百倍!)。
- 原生
- 在 Jupyter Notebook 中给 500 万个数字同时乘以 2,对比耗时:
- 👨🏫 教师活动:运行耗时对比代码,用高达上百倍的速度差距震撼学生;用“内存盒子”比喻讲解
list与ndarray底层结构的差异。 - 🧑🎓 学生活动:观察代码运行结果,体会运行时间的数量级差距,思考为什么机器学习处理海量数据必须依赖 NumPy。
避开繁琐的数学概念,通过直观的性能对比与内存比喻,快速激发学生的学习兴趣,建立对 NumPy 核心优势“向量化并行处理”的直观认知。
📖 二、 解决问题过程(一):创建数据容器 ndarray 与类型结构(20 分钟)
1. 四种常见创建函数对比
| 函数 | 数据来源 / 状态 | 默认数据类型(dtype) |
典型用途 |
|---|---|---|---|
np.array() |
现有 Python 列表/元组 | 自动推断(跟传入数据一致) | 手动输入已知数据 |
np.arange() |
按等差规律自动计算生成 | 通常为 int64 / int32 |
产生连续递增序列 |
np.zeros() |
全 0 填充 | float64 |
预分配内存空间 / 清零占位 |
np.ones() |
全 1 填充 | float64 |
基准掩码 / 乘法初始化 |
2. ndarray 的类型与维度逻辑结构
- 返回类型(Type):不管调用上述哪个函数,返回的统一是
numpy.ndarray(N-Dimensional Array)。 - 核心身份证属性:
dtype:里面存储的数据类型。ndim:数组的维度数量。shape:数组的空间形状/结构(元组形式)。- 0 维 (Scalar标量):单个数字(如 5),
shape为()。 - 1 维 (Vector向量):一排数据串,
shape类似(5,)。 - 2 维 (Matrix矩阵):Excel 表格,
shape类似(3, 4)(包含 3 行 4 列)。 - 3 维及以上 (Tensor张量):一叠表格或多维数据流。
- 0 维 (Scalar标量):单个数字(如 5),
- 👨🏫 教师活动:在 Jupyter 中逐一演示创建函数的语法,重点提醒
zeros/ones的默认dtype是float这一踩坑点。 - 🧑🎓 学生活动:跟练代码,使用
type()、.dtype和.shape打印验证各个数组的身份证属性。
打牢数据载体的底层概念,帮助学生彻底理清 ndarray 的类型与空间维度结构,避免后续写代码时因维度不匹配而报错。
💻 三、 解决问题过程(二):精准切片与特征分离(20 分钟)
1. 二维数组精准切片(机器学习核心操作)
二维切片公式:data[行切片, 列切片]
- 获取前 5 行:
data[0:5, :] - 获取最后一列(目标标签 $y$):
data[:, -1] - 获取除去最后一列的所有特征(特征集 $X$):
data[:, :-1]
- 👨🏫 教师活动:结合板书画图演示二维表格的“行”与“列”切割过程;重点拆解
data[:, :-1]和data[:, -1]中逗号两侧及负数索引的物理意义。 - 🧑🎓 学生活动:在 Jupyter Notebook 中运行切片代码,尝试修改切片范围(如提取特定行或特定列特征),观察输出结果并记录。
切片是机器学习数据预处理中最基础、最频繁的操作。摒弃纯数学抽象演示,直接对接真实数据集场景(分离特征 $X$ 与标签 $y$),帮助学生快速掌握二维数据的定位提取能力。
🚀 四、 解决问题过程(三):进阶——标准数据集划分 train_test_split(20 分钟)
1. 探究思考:为什么不能只用纯 NumPy 切片划分训练集和测试集?
如果我们直接用切片划分(例如 X_train = X[:8],X_test = X[8:]),会存在两个严重问题:
- 顺序偏差:如果原始数据是按类别排序的(如前 50 个全为健康,后 50 个全为患病),直接切片会导致训练集只有单一样本,模型根本学不到全貌。
- 考试作弊风险:必须把数据集打乱(Shuffle)并留出一部分测试集(模拟期末考试),才能真实检测模型有没有“死记硬背”。
2. 使用 train_test_split 规范划分
调用 scikit-learn 库中的 train_test_split 函数,只需一行代码就能同时完成随机打乱和按比例切割。
-
核心参数:
-
test_size=0.2:测试集占比 20%(训练集自动占 80%)。 -
random_state=42:随机数种子,确保每次运行代码时打乱顺序的结果一致(便于复现)。 -
返回值(注意严格顺序!):
X_train,X_test,y_train,y_test
- 👨🏫 教师活动:提出“只用切片划分训练集有什么隐患”的问题抛砖引玉;演示
train_test_split代码,用口诀“先 X 后 y,先 Train 后 Test”帮助学生记忆 4 个变量的解包顺序,带领学生核对划分前后的shape变化。 - 🧑🎓 学生活动:动手跟练,尝试更改
test_size为0.3或改变random_state的数值,打印观察X_train与X_test的行数如何自动按比例调整。
通过“从直接切片的缺陷”自然过渡到“专用工具库划分”,帮助学生理解机器学习防止过拟合的核心理念;通过对解包顺序与 shape 的严格校验,强化代码规范性与维度感知能力。
✍️ 五、 解决问题过程(四):充分课堂练习与巩固(20 分钟)
📝 六、 课堂小结(5 分钟)
flowchart LR
root["📊 3-1 NumPy 基础与数据集划分"]
subgraph C1["💡 核心容器与结构"]
direction TB
A1["类型:numpy.ndarray"]
A2["物理内存:连续平铺 (快百倍)"]
A3["属性:dtype / shape / ndim"]
end
subgraph C2["✂️ 1. 切片分离 (NumPy)"]
direction TB
B1["公式:data[行切片, 列切片]"]
B2["分离特征:X = data[:, :-1]"]
B3["分离标签:y = data[:, -1]"]
end
subgraph C3["🎲 2. 标准划分 (sklearn)"]
direction TB
C1_node["函数:train_test_split()"]
C2_node["功能:打乱(Shuffle) + 按比例(test_size)"]
C3_node["返回:X_train, X_test, y_train, y_test"]
end
root --> C1
root --> C2
root --> C3
%% 自定义主题色彩美化
style root fill:#4b6cb7,stroke:#253b6e,color:#fff,stroke-width:2px,rx:8px,ry:8px
style C1 fill:#e3f2fd,stroke:#2196f3,stroke-width:1px
style C2 fill:#fff3e0,stroke:#ff9800,stroke-width:1px
style C3 fill:#e8f5e9,stroke:#4caf50,stroke-width:1px