六步流水线跑一遍 12 万条数据:清洗 137.16 毫秒占 82.0%, 训练只花 7.28 毫秒占 4.4%。12 万条清洗完剩 95979 条,测试集准确率 0.859。
上一节分清三类范式,这一节把它串成一条线:从拿到数据到交出模型,中间要走六步。 每一步都能量出耗时。
一、六步,一个都不能省
收集 → 清洗 → 构造特征 → 训练 → 评估 → 保存部署。 这六步的名字很朴素,但顺序有讲究:清洗必须在特征之前(脏数据算出来的特征也是脏的), 评估必须在训练之后且用没见过的数据。 Demo 把六步都写进一个函数,每步前后各打一次时间戳。跑 12 万条数据,总耗时 167.30 毫秒。 这 167 毫秒里,每一步占多少?这就是这一节最有用的那张表。
二、清洗吃掉八成时间
实测占比:收集 6.5%、清洗 82.0%、特征 6.5%、训练 4.4%、评估 0.7%、 保存 0.0%。 清洗那一步干了三件事:补空值、去掉超过 4 个标准差的离群点、按六位小数去重。 12 万条去重后剩 95979 条——砍掉了两成。 去重为什么这么贵?它要把每一行当整体比较,等于给 12 万个三维点排序。 这是 O(n log n),数据量翻倍时间就翻一倍多。 所以「AI 训练师每天都在训模型」这句话是错的。 真正的分布是:八成的活在与数据较劲,四个点几在调模型。
三、形状怎么变,要一直盯着
Demo 每步都打一次数据的形状:进来是 (120000, 3),清洗后 (95979, 3),构造特征后 (95979, 5),
最后训练出 6 个权重。
为什么干净后还是 3 列、特征后变 5 列?因为清洗只删行不改列,特征工程新增了两个交叉项。
盯形状是排查 bug 最有效的手段。
准确率突然掉了,第一件事不是改模型,是看形状对不对——列数错了、行数少了一半,模型再好也白搭。
四、评估那一步最容易骗自己
Demo 把数据按 7:3 切开,训练集准确率 0.861、测试集 0.859。 两个数只差 0.002,说明没有明显过拟合。 如果训练集 0.99、测试集 0.60,那就是过拟合:模型把训练集的噪声也背下来了。 如果两个都低,那是欠拟合:模型太简单,或者特征根本不够。 还有一种更隐蔽的错:用测试集调参。你反复拿测试集比来比去,它就不再是「没见过的数据」了。 要调参就再切一份验证集出来。
五、动手 Demo:六步流水线走一遍
造 12 万条三特征数据,按收集、清洗(补空值+去离群+去重)、构造特征(标准化+两个交叉项)、 训练(最小二乘)、评估(7:3 切分)、保存六步依次执行,每步记耗时与产出形状,最后算占比。
t0 = time.perf_counter()
X = np.column_stack([x1, x2, x3]); y = (...)
steps.append((u'1 收集数据', time.perf_counter() - t0, X.shape))
t0 = time.perf_counter()
X = np.where(np.isnan(X), 0.0, X)
keep = (np.abs(X) < 4).all(1) # 去离群
_, uniq = np.unique(np.round(X, 6), axis=0, return_index=True)
steps.append((u'2 清洗数据', time.perf_counter() - t0, len(X)))
t0 = time.perf_counter()
w = np.linalg.lstsq(Atr, y[:k].astype(float), rcond=None)[0]
steps.append((u'4 训练模型', time.perf_counter() - t0, len(w)))
实跑输出:
--------------------------------------------------------------------
六步流水线走一遍:每步耗时多少、形状怎么变
--------------------------------------------------------------------
步骤 耗时(ms) 占比 产出
-----------------------------------------------------
1 收集数据 13.06 7.1% (120000, 3)
2 清洗数据 146.23 79.9% 120000 条 → 95979 条
3 构造特征 13.19 7.2% (95979, 5)
4 训练模型 9.30 5.1% 6 个权重
5 评估模型 1.34 0.7% 训练 0.861/测试 0.859
6 保存部署 0.00 0.0% 约 112 字节
总耗时 183.13 毫秒
原始数据形状 (120000, 3)
特征矩阵形状 (95979, 5)
测试集准确率 0.859
这次训练占 5.1%,收集+清洗+特征占 94.2%。
换台机器、换个数据量,这几个百分比都会变,但顺序一般不变:
花在数据上的时间远多于花在模型上。所以 AI 训练师每天干的事,
大半不在「训」上。
六行耗时:10.85 / 137.16 / 10.82 / 7.28 / 1.20 / 0.00 毫秒。
排第二的是收集(造数据本身),第三是构造特征,训练排到第四。
占比更直观:清洗 82.0%,训练 4.4%。
清洗那一步主要贵在 np.unique,它给 12 万行做了整体排序。
数据从 120000 条砍到 95979 条,去掉两成。
去重前如果不 round 到六位小数,浮点误差会让几乎所有行都「不重复」。
准确率 0.861 / 0.859,训练测试只差 0.002,没有过拟合迹象。
但这批数据是我用一个线性公式加噪声造的,本来就适合线性模型。
30 秒实验
- 把去重那一步注释掉重跑,看总耗时掉多少、准确率变不变。
- 把数据量从 12 万降到 1.2 万,看六个百分比还是不是这个排序。
- 想一想:为什么「用测试集反复调参」会让评估结果失真?
常见误区
- 「训模型是主要工作」——本例训练占 4.4%,清洗占 82%。
- 「数据差不多就行」——去重砍掉两成,不去重等于白训。
- 「测试集可以拿来调参」——调多了它就不是「没见过」的数据了。
自测三问(点开对答案)
1. 六步流程的固定顺序是什么? —— 收集、清洗、构造特征、训练、评估、保存部署。 2. 这次实测哪一步最贵?为什么? —— 清洗占 82.0%,主要贵在按整行去重,等于给全部数据排序。 3. 训练集 0.99、测试集 0.60 说明什么? —— 过拟合:模型把训练集的噪声也记住了,换数据就不行。流程讲完,下面进场景。第一个也是最大的一个:图像识别。
- ☐ (本节完,下一节 4.2.1 图像识别和分类:人脸识别、图像检索、物体识别)