数据采集与特征工程:数据源选择、数据清洗、特征提取、特征选择方法
做智能决策模型这么多年,我越来越觉得一句话特别对:「数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限」。说白了,你模型再花哨,喂进去的是垃圾,出来的还是垃圾。今天咱们就聊聊这个「喂食」的过程——数据采集与特征工程。
核心观点:特征工程不是锦上添花,而是模型成败的基石。我见过太多团队花80%的时间调参,却不愿意花20%的时间做特征,结果模型上线后一塌糊涂。
一、数据源选择:从哪里找「好米」?
数据源的选择,其实是个「找米下锅」的活。我个人习惯把数据源分成三类:
- 内部数据:公司数据库、日志系统、业务系统。这是最靠谱的,但往往有权限壁垒。
- 公开数据:政府开放数据、学术数据集、行业报告。质量参差不齐,需要仔细甄别。
- 外部采购:第三方数据服务商。价格不菲,但有时能解决燃眉之急。
我在项目中遇到过一个问题:某次做用户画像模型,内部数据只有交易记录,缺少用户行为数据。后来我们接入了第三方埋点数据,才把模型效果提上去。嗯,这里要注意:数据源的「相关性」比「量」更重要。你想想看,100万条无关数据,不如1万条精准数据。
我的经验:选数据源时,先问自己三个问题:1)这个数据能直接或间接反映目标变量吗?2)数据采集成本是否可控?3)数据更新频率是否满足业务需求?
二、数据清洗:把「脏米」淘干净
数据清洗,说白了就是「去伪存真」。我刚开始做数据时,总觉得这步可有可无,直到有一次模型训练完,发现准确率奇高——后来一查,原来是数据里有大量重复样本,模型「作弊」了。从那以后,我再也不敢跳过数据清洗了。
常见的脏数据问题:
| 问题类型 | 表现 | 处理方法 |
|---|---|---|
| 缺失值 | 字段为空或NaN | 删除、均值填充、插值、模型预测填充 |
| 异常值 | 明显偏离正常范围 | 3σ原则、IQR方法、业务规则过滤 |
| 重复值 | 完全相同的记录 | 去重(注意业务含义) |
| 格式不一致 | 日期格式、单位不统一 | 标准化处理 |
举个例子,处理缺失值时,我一般这样写:
# 缺失值处理示例
import pandas as pd
import numpy as np
# 数值型特征:用中位数填充(比均值更鲁棒)
df['age'].fillna(df['age'].median(), inplace=True)
# 类别型特征:用众数填充
df['gender'].fillna(df['gender'].mode()[0], inplace=True)
# 时间序列:用前向填充
df['temperature'].fillna(method='ffill', inplace=True)
避坑指南:我曾经犯过一个错——把所有缺失值都填充为0。结果模型学到的规律全是错的。缺失值本身可能就包含信息,比如「用户未填写收入」可能暗示其收入不稳定。所以,先分析缺失原因,再决定处理方式。
三、特征提取:从「米」到「饭」的转化
特征提取,就是把原始数据变成模型能理解的形式。说白了,就是「翻译」工作。机器只认数字,你得把文本、图片、时间、类别都翻译成数字。
常见的特征提取方法:
- 数值型特征:直接使用,或做对数变换、标准化、分箱
- 类别型特征:独热编码、标签编码、目标编码
- 文本特征:TF-IDF、词嵌入、词袋模型
- 时间特征:年、月、日、星期、是否为节假日、时间差
- 组合特征:特征交叉、多项式特征
我记得有一次做电商推荐模型,原始数据只有「购买时间」和「商品ID」两个字段。后来我提取了「用户最近一次购买距今的天数」「用户购买同一类商品的频率」「用户购买时间段的偏好」等特征,模型AUC直接从0.72提升到了0.85。你想想看,这就是特征提取的魔力。
一个小技巧:做特征提取时,多问问自己「这个特征在业务上意味着什么?」。比如「用户凌晨3点下单」这个特征,可能暗示用户是夜猫子,或者有紧急需求。这种业务理解,往往是特征提取的灵感来源。
四、特征选择:去粗取精,留下「好米」
特征太多不是好事。我见过一个项目,工程师提取了500多个特征,结果模型训练慢得像蜗牛,还容易过拟合。特征选择,就是帮你「去粗取精」。
常用的特征选择方法:
- 过滤法:根据统计指标筛选(方差、相关系数、卡方检验)
- 包裹法:用模型效果来评估特征子集(递归特征消除RFE)
- 嵌入法:在模型训练过程中自动选择(L1正则化、树模型特征重要性)
我个人最常用的是嵌入法,尤其是基于树模型的特征重要性。为什么呢?因为它既考虑了特征与目标的关系,又考虑了特征之间的交互,而且计算效率高。
# 基于随机森林的特征重要性
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)
# 获取特征重要性
importances = model.feature_importances_
indices = np.argsort(importances)[::-1]
# 打印前10个重要特征
for i in range(10):
print(f"特征 {indices[i]}: 重要性 {importances[indices[i]]:.4f}")
避坑指南:我曾经用相关系数做特征选择,把相关性低的特征全删了。结果模型效果反而下降了。为什么?因为有些特征虽然与目标变量相关性不高,但与其他特征组合后能产生很强的预测能力。所以,特征选择不能只看单变量关系,还要考虑特征间的交互。
五、知识体系总览
下面这张图,是我梳理的数据采集与特征工程的整体流程。你可以把它当作一个「路线图」,做项目时对照着来,基本不会跑偏。
这张图把整个流程串起来了。从数据源选择开始,到数据清洗、特征提取,最后到特征选择。每一步都有对应的技术和方法。做项目时,你可以把它当作一个checklist,确保每个环节都做到位。
最后说一句:特征工程没有银弹。同样的方法,在这个数据集上效果好,换一个数据集可能就失效了。我的建议是:多尝试、多对比、多思考业务含义。做得多了,你自然会有感觉。