第2章 结构化数据学习:从表格中发现规律
本章技术主题: 结构化数据的分类、回归与泛化评价。
本章技术实验: 用模拟环境表格完成一次分类、一次回归和基线比较。
家庭项目: “打造一个AI阳台植物园”第一阶段——表格数据学习。
跨章位置: 保存字段、基线和独立测试,第3章加入视觉,第12章完成多模态集成。
技术主线: 表格记录 → 特征与标签 → 基线 → 模型训练 → 独立测试 → 错误代价判断。
学习目标
完成本章学习后,你将能够:
- 从生活记录中区分样本、特征和标签,并发现缺失值、单位不一致和信息泄漏问题。
- 说明分类与回归的差别,分别为两类任务建立简单基线。
- 运行一段完整的Keras分类代码,读懂数据划分、归一化、训练、损失和测试结果。
- 根据训练集、验证集和测试集的表现识别过拟合,并结合错误代价形成使用判断。
项目导入
本章以“打造一个AI阳台植物园”为连续项目,进入第一阶段:表格数据学习。实践任务是整理一份虚构的阳台环境记录,让模型完成两个相互关联但性质不同的任务:根据当天记录判断植物是否“需要关注”,以及预测第二天早晨的土壤湿度。前者输出类别,属于分类;后者输出连续数值,属于回归。
后续章节还会沿用阳台植物场景研究视觉、时间序列、生成和多模态任务;本章只把每条环境记录作为结构化样本,重点学习特征、标签、分类与回归。同一生活场景可以形成不同AI任务,不能把一章的输入、输出和评价直接套到另一章。
结构化数据通常以表格呈现。每一行代表一次观察,每一列有固定含义,例如温度、光照、空气湿度和土壤湿度。表格看起来比图像简单,但模型不会自动知道哪一列是原因、哪一列是结果,也不会自动发现记录中的单位错误和未来信息。把生活记录变成可靠学习数据,是本章真正的实践重点。
本章的“应用中的AI”是依据表格特征输出状态类别或预测数值的模型。“开发与学习AI”帮助学生讨论字段、生成和解释完整程序、分析训练日志以及提出单变量修改建议。学生必须亲自确认标签规则、数据划分和错误代价,不能让语言模型看到表头后自行虚构数据,也不能只根据它对结果的文字评价决定采用模型。
本项目只使用教师提供的虚构记录,不代表任何真实植物的养护标准。模型输出用于学习数据规律,不替代植物品种说明、专业种植知识或现场观察。
本章成果
- 一张经过字段说明、单位统一和质量检查的阳台环境数据表。
- 一幅展示两个特征与状态标签关系的散点图。
- 一个能够完整运行的Keras二分类最小程序及运行记录。
- 一份分类、回归、基线、过拟合和错误代价的比较说明。
- 一张说明模型适用范围和人工确认条件的判断卡。
考点提示
请重点思考:特征和标签由任务而不是列的位置决定;分类输出类别,回归输出连续数值;损失是训练时衡量差异的量;验证集帮助选择方案,测试集用于最后检查;模型必须先超过合理基线,才有继续使用的价值。
第一节 把生活记录整理成特征和标签
一、把观察变成一行数据
假设每天傍晚记录阳台环境,并由人工观察植物是否需要进一步查看。每一行是一日样本,输入列包括平均温度、累计光照、平均空气湿度和傍晚土壤湿度。状态标签由人工按照课堂项目规则填写为“正常”或“需要关注”。为了练习回归,还记录第二天早晨土壤湿度作为另一个标签。
| 日期编号 | 平均温度/℃ | 累计光照/lx·h | 空气湿度/% | 傍晚土壤湿度/% | 状态标签 | 次晨土壤湿度/% |
|---|---|---|---|---|---|---|
| D01 | 22 | 12000 | 55 | 42 | 正常 | 39 |
| D02 | 24 | 15000 | 52 | 38 | 正常 | 34 |
| D03 | 31 | 26000 | 35 | 18 | 需要关注 | 13 |
| D04 | 20 | 9000 | 60 | 45 | 正常 | 43 |
| D05 | 33 | 28000 | 32 | 15 | 需要关注 | 9 |
| D06 | 26 | 18000 | 48 | 35 | 正常 | 31 |
| D07 | 30 | 24000 | 38 | 20 | 需要关注 | 15 |
| D08 | 23 | 14000 | 58 | 40 | 正常 | 37 |
这里的“状态标签”和“次晨土壤湿度”都可以成为模型要学习的目标,但一次建模只选择其中一个。预测状态时,温度、光照、空气湿度和傍晚土壤湿度是特征,状态是标签;预测次晨湿度时,前四列仍是特征,次晨湿度变成标签。日期编号只是识别记录的编号,通常不作为特征。
不能把“第二天是否需要关注”提前放进当天输入,也不能加入根据状态标签直接填写的“建议浇水”列。这些列在真正预测时尚不存在,或已经包含答案。训练时使用这种未来信息或答案线索称为数据泄漏,它会让测试数字看起来很好,实际应用却无法复现。
二、先建立字段说明
在交给模型之前,为每一列写清名称、含义、单位、允许范围和缺失处理方法。例如温度统一使用摄氏度,湿度统一为0到100之间的百分数,光照使用同一种统计口径。若一行把华氏温度当成摄氏温度,数值仍能进入程序,却会破坏规律。
缺失值不能随意填成0。土壤湿度为0可能表示极干,也可能只是没有记录,两者含义完全不同。入门项目可以先把关键特征缺失的行标记为“不可用于训练”,保留在质量记录中;数据较多时再研究合理的缺失值填补方法。
标签同样需要规则。课堂中的“需要关注”只表示建议再次观察,不等于“必须浇水”,更不等于植物患病。两名学生若对同一行给出不同标签,应先查看书面规则并讨论原因,而不是让模型替人决定正确标签。
三、先看图,再训练模型
表格适合查看精确数值,图形更容易显露关系。可以把傍晚土壤湿度画在横轴、平均温度画在纵轴,用两种颜色表示状态标签。若“需要关注”的点大多出现在高温、低土壤湿度区域,说明这两个特征与标签存在可观察关系。若两类点完全混在一起,则要检查特征是否不足、标签是否不一致,或者任务本身是否无法由这些数据完成。
图上的关系不等于因果关系。即使高温记录更常被标为需要关注,也不能仅凭这张小表断言高温造成了某种植物状态。模型学习的是数据中可用于预测的统计关系,不会自动完成科学因果研究。
开发与学习AI可以根据“字段说明和几行虚构样例”检查单位、范围和可能泄漏,但应要求它逐列说明理由。学生随后回到原表核对,不能让它用想象补齐缺失记录。规划中的完整Notebook应保留原始表、清洗后的表和散点图,使每一步变化都可追溯。
第二节 用分类、回归与基线比较学习结果
一、先问一个最简单的方法能做到什么
在训练神经网络前,应建立基线。基线是一个简单、可重复的参考方法。分类任务可以始终猜训练集中数量最多的类别;如果训练数据中60%是“正常”,这个基线的正确率就是60%。回归任务可以始终预测训练标签的平均值,再计算它与真实值的平均绝对误差。
如果复杂模型没有稳定超过基线,就没有证据说明复杂性带来了价值。基线也能发现评价方式的问题:当100条记录中只有5条需要关注时,始终猜“正常”也能达到95%正确率,却漏掉全部需要关注样本。因此还要分别查看两类错误。
分类模型输出类别或类别分数,常用分类损失衡量预测分布与正确标签的差异。回归模型输出连续数值,可以使用平均绝对误差或均方误差。损失越小,表示模型输出与训练目标在该度量下越接近;它不是对模型“聪明程度”的总评分。
二、运行完整的最小分类程序
下面的程序使用24条虚构数据训练二分类模型。四个特征依次为温度、光照、空气湿度和土壤湿度,标签0表示正常,1表示需要关注。程序固定随机顺序,将60%数据用于训练、20%用于验证、20%用于最终测试,并把模型与多数类基线比较。
import numpy as np
import tensorflow as tf
from tensorflow import keras
keras.utils.set_random_seed(7)
x = np.array([
[22, 12000, 55, 42], [24, 15000, 52, 38],
[20, 9000, 60, 45], [26, 18000, 48, 35],
[23, 14000, 58, 40], [21, 11000, 62, 47],
[25, 16000, 50, 36], [19, 8000, 65, 50],
[27, 17000, 47, 34], [22, 13000, 57, 43],
[24, 10000, 59, 41], [25, 19000, 46, 33],
[31, 26000, 35, 18], [33, 28000, 32, 15],
[30, 24000, 38, 20], [29, 22000, 40, 22],
[32, 30000, 30, 12], [28, 25000, 42, 19],
[34, 31000, 28, 10], [29, 27000, 36, 17],
[31, 23000, 34, 21], [30, 29000, 33, 16],
[28, 20000, 41, 23], [32, 25000, 37, 14],
], dtype="float32")
y = np.array([0] * 12 + [1] * 12, dtype="float32")
rng = np.random.default_rng(7)
order = rng.permutation(len(x))
x, y = x[order], y[order]
train_end = int(len(x) * 0.60)
val_end = int(len(x) * 0.80)
x_train, y_train = x[:train_end], y[:train_end]
x_val, y_val = x[train_end:val_end], y[train_end:val_end]
x_test, y_test = x[val_end:], y[val_end:]
normalizer = keras.layers.Normalization()
normalizer.adapt(x_train)
model = keras.Sequential([
keras.Input(shape=(4,)),
normalizer,
keras.layers.Dense(8, activation="relu"),
keras.layers.Dense(1, activation="sigmoid"),
])
model.compile(
optimizer="adam",
loss="binary_crossentropy",
metrics=["accuracy"],
)
stop = keras.callbacks.EarlyStopping(
monitor="val_loss", patience=20, restore_best_weights=True
)
model.fit(
x_train,
y_train,
validation_data=(x_val, y_val),
epochs=200,
verbose=0,
callbacks=[stop],
)
test_loss, test_accuracy = model.evaluate(x_test, y_test, verbose=0)
majority_label = int(np.mean(y_train) >= 0.5)
baseline_accuracy = float(np.mean(y_test == majority_label))
probabilities = model.predict(x_test, verbose=0).reshape(-1)
predictions = (probabilities >= 0.5).astype(int)
print("测试损失:", round(float(test_loss), 4))
print("模型测试正确率:", round(float(test_accuracy), 4))
print("多数类基线正确率:", round(baseline_accuracy, 4))
for truth, probability, prediction in zip(y_test, probabilities, predictions):
print("真实标签:", int(truth), "关注分数:", round(float(probability), 3),
"预测标签:", int(prediction))
归一化层根据训练集计算各特征的尺度,使数值很大的光照不至于仅因单位较大而压过其他特征。它只在训练集上学习统计量,验证和测试数据不能参与这个过程。隐藏层学习特征组合,最后的S形函数输出0到1之间的关注分数。
这段代码是可运行的最小实现,不要求学生默写。学生应能指出输入数组、标签数组、三份数据、归一化层、模型输出和基线计算分别在哪里。规划中的完整Notebook应把同一程序拆成数据查看、可视化、建模、训练曲线和测试五段,并保留每段运行结果。
三、把同一任务改成回归
若标签改为次晨土壤湿度,任务就从分类变为回归。输入特征可以保持不变,模型最后一层改为一个不带分类激活函数的数值输出,训练损失改为平均绝对误差或均方误差。基线则始终输出训练集次晨湿度的平均值。
比较时不能用“分类正确率”评价回归,而要报告预测值平均偏离真实值多少个百分点。一个平均误差为3个百分点的模型是否可用,还取决于记录误差、植物差异和使用后果。本章不把回归代码叠加到正文程序中;下一阶段的配套Notebook应提供与分类并列的完整回归版本,供学生逐项比较输出层、损失和评价指标。
第三节 检查数据划分、过拟合与错误代价
一、三份数据承担不同责任
训练集用于调整参数,验证集用于比较模型结构、训练轮数和阈值,测试集只在方案确定后作最终检查。如果反复查看测试结果并据此修改模型,测试集也会逐渐变成训练过程的一部分,最终数字仍会过于乐观。
阳台记录还要注意时间关系。随机打乱适合本章理解基本划分,但若目标是预测未来,正式项目应按时间划分:较早记录用于训练,中间记录用于验证,最近记录用于测试。这样更接近“用过去预测未来”,也更容易发现季节变化造成的数据漂移。
相邻多日来自同一段稳定环境,内容可能高度相似。若把几乎重复的记录分散到训练和测试两边,模型实际上看过非常接近的情况。划分前应先判断哪些记录来自同一连续过程,必要时按时间段或植物个体成组划分。
二、从训练曲线发现过拟合
模型在训练集上的损失持续下降,而验证集损失先下降后上升,通常说明模型越来越适合训练细节,却没有提升对未见数据的能力,这称为过拟合。小数据配复杂模型、训练轮数过多、标签含噪声,都可能加重过拟合。
正文程序使用提前停止:验证损失长期没有改善就停止训练,并恢复验证表现最好的参数。提前停止能够限制问题,但不能弥补错误标签、数据泄漏和代表性不足。更根本的改进包括增加有意义的不同情形、简化模型、重新检查字段和改进划分。
开发与学习AI可以读取学生抄录的训练与验证损失,提出“减少网络规模”“检查泄漏”“增加边界样本”等假设。学生每次只选择一个假设实施,用同一测试集外的验证证据比较。不能把一条训练曲线直接交给AI后接受一句“模型已经很好”。
三、正确率之外还有错误代价
将“需要关注”错判为“正常”称为漏报,将“正常”错判为“需要关注”称为误报。漏报可能使需要复查的情况被忽略;误报会增加人工检查。两种错误的代价不同,阈值选择也会因此不同。
本项目不允许模型自动执行养护动作。它只能提出候选状态,由人结合植物种类、现场观察和记录质量确认。出现特征缺失、数值超出训练范围、分类分数接近或模型服务不可用时,程序应保留原始记录并转为人工检查。
最终判断至少比较四项证据:模型是否超过基线;验证和测试表现是否接近;关键类别的漏报是否可接受;输入条件是否与训练数据一致。若只有24条虚构数据,合理结论应是“完成了机制验证”,而不是宣称获得了普遍适用的植物养护模型。
本章小结
结构化数据学习从定义一行记录开始。特征是模型可获得的输入,标签是希望模型学习的目标。分类预测类别,回归预测连续数值,二者需要不同的输出、损失和评价指标。训练集调整参数,验证集选择方案,测试集进行最后检查。复杂模型只有稳定超过基线才显示出价值;训练表现明显好于验证表现可能意味着过拟合。最终是否使用模型,还要结合数据泄漏、错误代价、输入范围和人工责任判断。
关键术语
- 结构化数据:字段含义和排列规则明确、通常可以用行列表示的数据。
- 特征:模型在作出预测时能够获得的输入变量。
- 标签:训练时希望模型预测的目标类别或数值。
- 分类:预测离散类别的任务。
- 回归:预测连续数值的任务。
- 损失:训练时衡量模型输出与目标之间差异的量。
- 基线:用于判断复杂方法是否带来收益的简单参考方法。
- 数据泄漏:训练或输入中使用了真实应用时得不到的答案线索或未来信息。
- 过拟合:模型过度适应训练数据细节,对未见数据表现下降的现象。
- 错误代价:不同类型错误在真实任务中带来的影响和负担。
目标测试
- 在预测“是否需要关注”的任务中,哪一项最适合作为标签? A. 平均温度 B. 状态类别 C. 日期编号 D. 光照单位
- 下列哪一项属于数据泄漏? A. 使用当天温度预测次日状态 B. 统一湿度单位 C. 把次日人工结论提前作为当天输入 D. 删除无法解释的重复记录
- 分类任务的简单基线可以是什么? A. 始终猜训练集中最多的类别 B. 增加隐藏层 C. 延长训练时间 D. 删除测试集
- 哪一种现象最符合过拟合? A. 训练和验证损失都下降 B. 训练损失下降而验证损失持续上升 C. 模型与基线相同 D. 所有特征单位一致
- 判断并改错:“验证集用于调整参数,测试集可以每天查看并反复选择模型。”
- 判断并改错:“回归输出连续数值,因此可以直接用分类正确率评价。”
- 从本章阳台数据中各举一个特征、分类标签和回归标签,并说明三者作用。
- 为什么要在训练神经网络前建立基线?请分别给分类和回归写出一种基线。
- 某模型训练正确率为98%,验证正确率为70%,测试正确率为68%。你认为可能出现了什么问题?写出两项检查或改进措施。
- 在“需要关注”识别中,漏报比误报代价更高。请说明这一判断会怎样影响评价指标、阈值和人工确认规则。