4、数据标注与预处理:云端标注工具、数据清洗、特征工程、数据划分

数据准备这件事,说实话,比调模型要花时间得多。我见过太多团队把精力全砸在模型结构上,结果数据一塌糊涂,跑出来的指标根本没法看。今天咱们就聊聊云端ML工作流里,数据标注和预处理到底该怎么搞。

4.1 云端标注工具:SageMaker Ground Truth

标注数据,听起来就是个苦力活。但如果你还在用Excel手动打标签,那效率确实太低了。我个人习惯用SageMaker Ground Truth,它最大的好处是——你不用自己管标注团队。

你只需要上传原始数据,定义好标注任务(比如图像分类、目标检测、文本分类),Ground Truth会自动把任务分发给标注工人。它内置了质量检查机制,说白了就是同一份数据会分给多个人标,然后做一致性校验。

核心流程:
  • 创建标注项目 → 选择任务类型
  • 上传数据(S3路径) → 配置工人团队(公有/私有)
  • 启动标注 → 自动质检 → 导出标注结果

我在项目中遇到过一个问题:标注结果里有些标签明显是错的。后来发现是标注任务说明写得太模糊。嗯,这里要注意——标注指南一定要写清楚,最好附上正反例。否则工人凭感觉标,你后面清洗数据会哭的。

小技巧: 先用少量数据(比如100条)做一轮预标注,看看结果质量。没问题了再全量跑。这能省下不少冤枉钱。

4.2 数据清洗:别让脏数据毁了你的模型

数据清洗,说白了就是「去杂质」。你想想看,原始数据里什么妖魔鬼怪都有:空值、重复值、异常值、格式不统一……这些不处理,模型学到的全是噪音。

我一般按这个顺序来清洗:

  1. 去重:同一份数据出现多次,模型会过拟合到这些样本上。
  2. 处理缺失值:数值型用均值/中位数填充,类别型用众数填充。如果缺失太多(超过50%),我建议直接删掉这个特征。
  3. 异常值检测:用3σ原则或者IQR(四分位距)方法。比如用户年龄出现200岁,这明显是录入错误。
  4. 格式统一:日期格式、文本编码、数值单位,全部标准化。
避坑指南: 我曾经在清洗文本数据时,直接把所有标点符号都删了。结果模型学到的语义全乱了。后来才意识到,有些标点(比如问号、感叹号)其实携带情感信息。所以清洗策略一定要结合业务场景来定。

在云端做数据清洗,我推荐用AWS Glue或者SageMaker Processing。它们可以自动处理大规模数据,而且支持Python脚本。你只需要写个清洗函数,然后提交一个Processing Job就行。

# 一个简单的清洗示例(SageMaker Processing)
import pandas as pd

def clean_data(df):
    # 去重
    df = df.drop_duplicates()
    # 填充缺失值
    df['age'].fillna(df['age'].median(), inplace=True)
    # 异常值处理(年龄超过120视为异常)
    df = df[df['age'] <= 120]
    return df

# 在SageMaker Processing中调用
from sagemaker.processing import ProcessingInput, ProcessingOutput

4.3 特征工程:把原始数据变成模型能理解的语言

特征工程,说白了就是「翻译」。原始数据是人类的语言,模型只懂数字。你得想办法把文本、图片、时间、类别这些东西,变成数值向量。

我个人习惯把特征工程分成三类:

特征类型 常见方法 注意事项
数值型 标准化(Z-score)、归一化(Min-Max) 树模型不需要归一化,但神经网络需要
类别型 独热编码、标签编码、目标编码 类别太多时独热编码会爆炸,考虑用嵌入
文本型 TF-IDF、词嵌入(Word2Vec/BERT) 短文本用TF-IDF,长文本用预训练模型
时间型 提取年/月/日/星期、周期性编码 时间戳本身没意义,要提取周期特征

为什么会这样?因为模型本质上是在做数学运算。你给它一个「红色」的字符串,它算不了。但如果你把「红色」编码成 [1,0,0],把「蓝色」编码成 [0,1,0],模型就能理解它们之间的「距离」了。

经验之谈: 特征工程不是越多越好。我见过有人一口气造了200个特征,结果模型训练时间翻了三倍,效果反而下降了。记住一个原则:每个特征都要有业务解释。如果你自己都说不清这个特征代表什么,那模型大概率也学不会。

4.4 数据划分:训练/验证/测试

数据划分这件事,看起来简单,但坑特别多。最常见的错误就是——先划分,再做特征工程。顺序搞反了,会导致数据泄露。

正确的顺序是:

  1. 先把原始数据分成三份:训练集(60-70%)、验证集(15-20%)、测试集(15-20%)
  2. 只在训练集上做特征工程(比如计算均值、标准差)
  3. 用训练集上算好的参数,去转换验证集和测试集

为什么要这样?你想想看,如果你先对整个数据集做标准化,那验证集的数据「偷看」了训练集的分布信息。模型在测试时表现好,其实是因为它已经提前知道了全局信息。这属于典型的「数据泄露」。

我曾经踩过的坑: 有一次做时间序列预测,我直接用随机划分把数据分成了训练和测试。结果模型在测试集上表现特别好,上线后却一塌糊涂。后来才发现,时间序列数据必须按时间顺序划分——用过去的数据训练,用未来的数据测试。否则模型「偷看」了未来的信息,根本不能反映真实场景。

在云端,你可以用SageMaker的train_test_split功能,或者自己写脚本。我个人习惯用scikit-learn的train_test_splitStratifiedKFold来做分层抽样,确保每个类别在训练集和测试集中的比例一致。

from sklearn.model_selection import train_test_split

# 先划分,再特征工程
X_train, X_temp, y_train, y_temp = train_test_split(
    X, y, test_size=0.3, random_state=42, stratify=y
)
X_val, X_test, y_val, y_test = train_test_split(
    X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp
)
总结一下数据划分的关键点:
  • 先划分,后做特征工程
  • 时间序列数据必须按时间顺序划分
  • 分类问题用分层抽样,保持类别分布一致
  • 测试集只用一次,不要用它调参

好了,数据标注和预处理这部分就聊到这儿。记住一句话:数据质量决定了模型效果的上限,模型算法只是在逼近这个上限。把数据搞扎实了,后面的事情会顺利很多。


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