在小厂带团队搞机器学习这半年踩过的坑

日志里找真相
2026-08-19 22:26
阅读 999

去年年底公司接了个本地零售商的订单预测项目。我在三线城市一家互联网公司当技术负责人,组里七个人,日常给本地连锁超市、小工厂做管理系统。我之前主要写Java和一点Python,机器学习基本没碰过。但这活推不掉,硬着头皮上。半年下来模型跑通了,准确率凑合能用,踩的坑比写的代码还多。

从哪开始?先把环境折腾明白

实践驱动的意思是,先跑起来一个东西,再回头补理论,比反过来效率高得多。

我用Python 3.11,包管理用的uv。核心库就三个:pandas、scikit-learn、matplotlib。别一上来就装PyTorch,连线性回归都没跑通,装那玩意纯属给自己找不痛快。

uv init ml-beginner
cd ml-beginner
uv add pandas scikit-learn matplotlib

有个小坑:Python 3.13下scikit-learn某些版本可能装不上,老实降到3.11。版本兼容问题在ML生态里特别常见,出问题先查版本矩阵。

数据长什么样,决定了你能走多远

客户给的数据是三年多销售记录,Excel约40万行。字段不多:日期、商品ID、品类、销售量、单价、是否促销。看着干净,实际全是雷。

商品ID格式混乱,日期格式五花八门,2025/1/2202501022025年1月2日居然出现在同一列。花了两天写清洗脚本。

import pandas as pd

df = pd.read_excel("sales_data.xlsx", dtype={"商品ID": str})
df["商品ID"] = df["商品ID"].str.strip().str.replace(r"[\s\u200b]", "", regex=True)
df["日期"] = pd.to_datetime(df["日期"], format="mixed", errors="coerce")
print(f"清洗前: {len(df)} 行")
df = df.dropna(subset=["日期", "销售量"])
print(f"清洗后: {len(df)} 行")

清洗完40万行剩36万,10%数据直接废了。真实世界的ML,80%时间都在跟脏数据搏斗。数据清洗不要追求完美,先把能用的部分跑通,再逐步完善。

特征工程,比模型本身重要

需求是预测未来一周每个商品销量。一开始拿历史销量当特征丢给模型,MAE大到客户想退款。

零售数据几个关键特征:

星期几:周末销量能比工作日高30%~50%。

是否促销:促销期间销量可能翻倍,且有滞后效应。

滞后特征:用过去7天、14天、30天销量作为特征。

品类信息:不同品类销售规律差别太大。

df["星期"] = df["日期"].dt.dayofweek
df["是否周末"] = (df["星期"] >= 5).astype(int)

for lag in [7, 14, 30]:
    df[f"销量_lag_{lag}"] = df.groupby("商品ID")["销售量"].shift(lag)

df["销量_rolling_7"] = df.groupby("商品ID")["销售量"].transform(
    lambda x: x.rolling(7, min_periods=1).mean()
)

这一步做完模型效果提升一大截。特征工程花的时间是模型训练调参的十倍,但收益也是十倍的。ML里加对一个特征可能让准确率翻倍。

模型选择和调参,别当调参侠

先用简单模型跑通流程,确认数据管道没问题,再上复杂模型。别一上来就XGBoost,连数据泄漏都没发现,再强的模型也白搭。

数据泄漏我踩了个大坑。做交叉验证时偷懒用了train_test_split随机切分,测试集R²到了0.95,上线后预测一塌糊涂。原因:随机切分让训练集和测试集包含相邻日期数据,模型通过滞后特征"偷看"了测试集信息。正确做法是按时间切分。

# 错误做法:随机切分
# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 正确做法:按时间切分
split_date = pd.Timestamp("2026-06-01")
train_mask = df["日期"] < split_date
test_mask = df["日期"] >= split_date

X_train, y_train = X[train_mask], y[train_mask]
X_test, y_test = X[test_mask], y[test_mask]

调参方面,小厂项目花三天把MAE从12.3调到11.8,客户根本感知不到。更重要的是稳定性和可解释性。客户问"为什么预测这个数",你得能说出"因为下周有促销,且过去30天销量在上升"。

代码可读性,ML项目里同样重要

ML教程代码变量名X、y、df、tmp满天飞。我的做法是把数据处理拆成独立函数:

def clean_product_id(df: pd.DataFrame) -> pd.DataFrame:
    """清洗商品ID格式,返回处理后的DataFrame"""
    ...

def add_lag_features(df: pd.DataFrame, lags: list[int]) -> pd.DataFrame:
    """添加滞后销量特征"""
    ...

def split_by_date(df: pd.DataFrame, split_date: str) -> tuple:
    """按时间切分训练集和测试集,避免数据泄漏"""
    ...

半年后回来看代码不用重新推导逻辑,同事接手也不会在群里骂人。

Trae和Agent Skills,真香还是鸡肋?

我平时用Trae写Python。写特征工程时很多pandas操作记不住语法,直接在编辑器里问一句"怎么按商品ID分组计算滚动均值",代码就出来了。

但AI生成的代码不能无脑复制。有次Trae生成的特征构造代码在计算滞后特征之前就做了缺失值填充,导致滞后特征全部被填充值污染,调了一下午才定位。

Agent Skills可以配置自定义技能规则。我建了一个"ML项目规范"的Skill:

  1. 所有数据处理函数必须写docstring
  2. 特征列名统一用中文前缀feat_,目标列用target_
  3. 切分数据集必须用时间切分,禁止随机切分
  4. 模型评估必须同时报告MAE和R²

相当于把代码规范固化到工具层面。不过Agent Skills目前还比较基础,复杂规则理解不了,更多是辅助。

上线之后才是真正的开始

模型测试集MAE约11.5,客户反馈比拍脑袋准多了。上线后新问题更多:数据管道每天凌晨跑批,上游数据延迟管道就挂,加了重试机制和钉钉告警。模型漂移问题,用了一个月准确率开始下降,因为季节变了。现在计划每月用新数据重新训练。

这半年最大的感受:机器学习入门不难,难的是把它真正用起来。网上教程教你跑MNIST,跟实际业务里的脏数据、数据泄漏、模型漂移完全是两个世界。但跑通第一个真实项目的成就感也是真的。

如果你也在小厂被逼着搞AI,我的建议是:别怕,先动手。装好环境,找一份真实数据,跑一个最简单的模型,然后慢慢迭代。踩坑是必然的,但每一个坑踩过去,你就比昨天强一点。

评论 0

最热最新
暂无评论
日志里找真相Lv.1
0
影响力
0
文章
0
粉丝