多标签分类实战-二分类和XGBoost
多标签分类实战-二分类和XGBoost
深入理解多标签分类问题,掌握 Binary Relevance 方案和 XGBoost 模型的训练与使用。从第一性原理出发,理解为什么需要多标签分类,以及如何训练和评估多标签分类模型。
目录
1. 多标签分类问题
1.1 什么是多标签分类?
多分类 vs 多标签分类的本质区别
多分类(Multi-class):
- 定义:类别互斥,一个样本只能属于一个类别
- 例子:图像分类 ``` 一张图片:
- 可能是”猫”(概率90%)
- 可能是”狗”(概率8%)
- 可能是”鸟”(概率2%) → 最终分类:猫(最高概率) → 一张图只能是一种动物 ```
多标签分类(Multi-label):
- 定义:类别非互斥,一个样本可以属于多个类别
- 例子:文本标签 ``` 一篇文章:
- 是”科技”(概率85%)
- 是”AI”(概率75%)
- 是”深度学习”(概率60%) → 最终标签:[‘科技’, ‘AI’, ‘深度学习’](多个标签) → 一篇文章可以同时有多个标签 ```
实际业务场景举例
多标签分类场景:
1
2
3
4
5
6
7
对象A:
- 类别1:是(概率85%)
- 类别2:是(概率60%)
- 类别3:否(概率10%)
最终结果:对象A同时属于"类别1"和"类别2"
→ 一个对象可以同时属于多个类别
为什么需要多标签?
- 类别之间不是互斥的
- 需要为每个类别输出独立的概率
- 业务需要知道”这个对象属于哪些类别”
1.2 多标签分类的挑战
挑战1:标签相关性
问题:不同标签之间可能存在相关性。
例子:
1
2
3
4
5
6
标签A:类别1
标签B:类别2
相关性:
- 如果一个对象是"类别1",更可能是"类别2"?
- 还是两者独立?
影响:
- 如果忽略相关性,可能丢失信息
- 如果考虑相关性,模型复杂度增加
Binary Relevance 方案的处理:
- 假设标签之间独立
- 每个标签独立训练模型
- 简单高效,但可能忽略相关性
挑战2:类别不平衡
问题:每个标签的正负样本比例可能不同。
例子:
1
2
3
4
5
6
7
8
9
标签"类别1":
- 正样本(是):100个
- 负样本(否):900个
- 比例:9:1(严重不平衡)
标签"类别2":
- 正样本(是):50个
- 负样本(否):950个
- 比例:19:1(更不平衡)
影响:
- 模型可能偏向多数类(负样本)
- 准确率会误导(99%准确率但漏掉所有正样本)
- 需要特殊处理
挑战3:特征重要性分配
问题:不同标签可能依赖不同的特征。
例子:
1
2
3
4
5
6
7
标签"类别1":
- 重要特征:特征A、特征B
- 特征重要性:特征A(0.3), 特征B(0.25), ...
标签"类别2":
- 重要特征:出入境频率、地点
- 特征重要性:出入境频率(0.35), 地点(0.28), ...
影响:
- 每个标签需要独立的特征重要性
- 不能用一个模型的特征重要性代表所有标签
2. 多标签分类方案对比
2.1 Binary Relevance (BR) 方案
核心思想
定义:为每个标签训练独立的二分类模型。
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
原始问题:多标签分类
输入:对象特征
输出:['类别1', '类别2'](多标签)
↓
分解为多个独立的二分类问题:
问题1:是否属于"类别1"?(二分类)
问题2:是否属于"类别2"?(二分类)
↓
训练:
模型1:学习"类别1" vs "非类别1"
模型2:学习"类别2" vs "非类别2"
↓
预测:
模型1 → 概率1(是否类别1)
模型2 → 概率2(是否类别2)
↓
组合结果:
多标签 = [概率1 > 阈值, 概率2 > 阈值, ...]
优点
- 简单高效
- 每个模型独立训练,互不干扰
- 训练速度快,易于实现
- 支持多标签
- 一个对象可以同时属于多个类别
- 每个模型独立输出概率
- 易于扩展
- 新增类别只需训练一个新模型
- 不影响已有模型
- 特征重要性清晰
- 每个模型学习该类别的特征模式
- 特征重要性针对性强
缺点
- 忽略标签相关性
- 假设标签之间独立
- 可能丢失标签之间的关联信息
- 可能产生矛盾预测
- 如果标签有互斥关系,可能同时预测为正
- 需要后处理规则
2.2 其他方案简介
Classifier Chains (CC)
核心思想:链式分类器,考虑标签顺序。
流程:
1
2
3
4
5
6
7
模型1:预测标签1
↓
模型2:预测标签2(使用标签1的预测结果作为特征)
↓
模型3:预测标签3(使用标签1和标签2的预测结果作为特征)
↓
...
问题:
- 标签顺序敏感(顺序不同,结果不同)
- 训练复杂(需要按顺序训练)
- 错误传播(前面的错误会影响后面)
Label Powerset (LP)
核心思想:将多标签转换为多分类。
例子:
1
2
3
4
5
6
7
8
9
10
11
原始标签组合:
- ['类别1']
- ['类别2']
- ['类别1', '类别2']
- []
转换为多分类:
- 类别A:'类别1'
- 类别B:'类别2'
- 类别C:'类别1+类别2'
- 类别D:'无标签'
问题:
- 类别爆炸(2^n个类别,n是标签数)
- 数据稀疏(很多类别组合没有样本)
- 难以扩展(新增标签需要重新训练)
神经网络多标签学习
核心思想:端到端学习,自动学习标签相关性。
问题:
- 需要大量数据
- 可解释性差
- 训练复杂
2.3 为什么选择 BR 方案?
业务场景匹配度
类别相对独立:
1
2
3
4
类别1和类别2:
- 可能有相关性,但不强
- 可以独立判断
- BR方案的独立性假设基本成立
需要清晰的解释:
1
2
3
4
每个类别需要独立的解释:
- 为什么是"类别1"?
- 为什么是"类别2"?
- BR方案提供独立的特征重要性
实施复杂度
BR方案:
- 简单:每个模型独立训练
- 快速:可以并行训练
- 易于调试:问题容易定位
其他方案:
- CC:顺序训练,复杂
- LP:类别爆炸,不可行
- 神经网络:需要大量数据,复杂
可解释性要求
BR方案:
- 每个模型的特征重要性清晰
- 可以解释每个标签的预测原因
其他方案:
- CC:难以解释(依赖前面的预测)
- LP:难以解释(类别组合)
- 神经网络:黑盒,难以解释
结论:BR方案最适合当前场景。
3. XGBoost 算法深入理解
3.1 决策树基础回顾
什么是决策树?
定义:通过一系列规则(IF-THEN)进行决策的树形结构。
可视化理解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
决策树示例:
根节点(所有样本)
|
┌─────────────┴─────────────┐
| 年龄 < 30? |
↓ ↓
是(左) 否(右)
| |
┌───────┴───────┐ ┌─────────┴─────────┐
| 收入 > 50000? | | 历史记录 > 5? |
↓ ↓ ↓ ↓
是 否 是 否
↓ ↓ ↓ ↓
类别1 类别2 类别1 类别2
决策过程:
1
2
3
4
5
6
7
8
样本:年龄=25, 收入=60000, 历史记录=3
决策路径:
1. 年龄 < 30? → 是
2. 收入 > 50000? → 是
3. 预测 = 类别1
最终预测:类别1
决策树如何做决策?
核心机制:通过特征值比较,逐步缩小范围。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
特征空间(2维):
收入
↑
高 | 区域1(类别1)
| ┌─────┐
| │ │
| └─────┘
| 区域2(低风险)
└─────────→ 年龄
决策树的分裂:
- 第1次分裂:年龄 < 30(垂直分割)
- 第2次分裂:收入 > 50000(水平分割)
- 结果:将特征空间分成4个区域
关键理解:
- 每个节点 = 一个判断条件
- 每个叶子 = 一个预测结果
- 从根到叶的路径 = 一条决策规则
3.2 集成学习策略
单独决策树 vs 集成学习
单独决策树的问题:
1
2
3
4
5
6
7
8
9
10
11
问题1:容易过拟合
- 树太深 → 记住训练数据的每个细节
- 测试集表现差
问题2:不稳定
- 训练数据微小变化 → 树结构完全不同
- 预测结果不稳定
问题3:精度有限
- 单棵树的学习能力有限
- 难以捕捉复杂模式
集成学习的优势:
1
2
3
4
多个模型组合:
- 降低过拟合风险(平均多个模型的预测)
- 提高稳定性(减少方差)
- 提高精度(组合多个模型的优势)
Bagging vs Boosting 的区别
Bagging(如随机森林)的本质:
核心思想:并行训练多棵树,投票决策。
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
训练阶段(并行):
树1(数据子集1 + 特征子集1) → 训练 → 模型1
树2(数据子集2 + 特征子集2) → 训练 → 模型2
树3(数据子集3 + 特征子集3) → 训练 → 模型3
...
树100(数据子集100 + 特征子集100) → 训练 → 模型100
预测阶段:
样本 → 模型1预测 → 预测1
样本 → 模型2预测 → 预测2
...
样本 → 模型100预测 → 预测100
↓
最终预测 = 多数投票(预测1, 预测2, ..., 预测100)
本质:
- 降低方差(通过平均多个模型的预测)
- 适合高方差模型(如深度决策树)
Boosting(如XGBoost)的本质:
核心思想:串行训练多棵树,每棵树学习前一轮的残差。
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
第1轮:
树1 → 预测1
残差1 = 真实值 - 预测1
↓
第2轮:
树2 → 学习残差1 → 预测2
残差2 = 残差1 - 预测2
↓
第3轮:
树3 → 学习残差2 → 预测3
残差3 = 残差2 - 预测3
↓
...
最终预测 = 预测1 + 预测2 + 预测3 + ...
本质:
- 降低偏差(通过逐步纠错)
- 适合高偏差模型(如浅层决策树)
为什么选择 Boosting?
小数据集的特点:
1
2
3
4
5
6
7
8
9
数据量:中等(几百到几千样本)
↓
通常面临的问题:高偏差(模型太简单)
- 模型无法捕捉复杂模式
- 训练集和测试集表现都差
↓
解决方案:Boosting
- 通过逐步纠错降低偏差
- 逐步改进模型性能
对比:
1
2
3
4
5
6
7
8
9
10
11
Bagging(随机森林):
- 主要降低方差
- 适合高方差问题
- 小数据集可能过拟合
Boosting(XGBoost):
- 主要降低偏差
- 适合高偏差问题
- 小数据集通过正则化防止过拟合
↓
结论:Boosting更适合小数据集
3.3 XGBoost 的核心优势
XGBoost的特征处理要求
重要理解:XGBoost可以支持多种弱学习器,是否需要归一化取决于我们采用的弱学习器类型。
常见实现:选择决策树作为弱学习器(默认情况)。
当使用决策树作为弱学习器时:
1. 特征无需归一化
原理:
- 树模型的分裂方式:通过遍历特征所有取值来选择划分点
- 排序而非距离:树模型关注的是特征值的排序关系,而不是绝对数值大小
- 归一化不影响排序:归一化不会改变特征值的相对大小关系
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
原始数据:
特征1(年龄):[20, 25, 30, 35, 40]
特征2(收入):[1000, 5000, 10000, 20000, 50000]
归一化后:
特征1:[0, 0.25, 0.5, 0.75, 1.0]
特征2:[0, 0.1, 0.2, 0.4, 1.0]
XGBoost分裂(决策树):
原始数据:按"年龄 < 30"分裂
归一化后:按"年龄 < 0.5"分裂
结果:分裂效果相同 ✅
归一化不影响排序关系
树模型的分裂结果不变
结论:使用决策树作为弱学习器时,特征无需归一化。
2. 需要ONE-HOT处理(类别特征)
为什么需要ONE-HOT?
XGBoost的特征处理机制:
- 特征排序:在模型训练之前,XGBoost会对所有特征按取值进行排序并加载到内存
- 要求特征有序:XGBoost要求特征是有序的(数值型特征天然有序)
问题场景:
1
2
3
4
5
6
7
8
9
10
11
12
13
离散特征(类别特征):
地点:["北京", "上海", "深圳"]
如果直接k值编码(Label Encoding):
北京 = 0
上海 = 1
深圳 = 2
↓
问题:XGBoost会认为 0 < 1 < 2(有序关系)
↓
但实际上:北京、上海、深圳之间没有大小关系(无序)
↓
结果:模型会错误地认为"深圳 > 上海 > 北京" ❌
解决方案:ONE-HOT编码
ONE-HOT编码:
1
2
3
4
5
6
7
8
9
10
11
12
原始特征:地点 = "北京"
ONE-HOT编码后:
地点_北京 = 1
地点_上海 = 0
地点_深圳 = 0
↓
每个类别变成一个独立的二值特征
↓
二值特征(0或1)被当成有序特征处理
↓
但二值特征的有序/无序处理结果相同 ✅
为什么ONE-HOT可以?
原理:
- 二值特征的特殊性:对于二值特征(0或1),无论当成有序还是无序处理,结果都相同
- 有序处理:0 < 1(数值大小关系)
- 无序处理:0 ≠ 1(类别不同)
- 结果:两种处理方式在二值特征上等价
XGBoost特征处理总结:
| 特征类型 | 处理方式 | 原因 |
|---|---|---|
| 数值特征 | 无需归一化 | 树模型基于排序分裂,不受尺度影响 |
| 类别特征 | ONE-HOT编码 | 避免k值编码被误认为有序关系 |
| 缺失值 | 可自动处理 | XGBoost可以自动学习如何处理缺失值 |
关键理解:
- 归一化:使用决策树弱学习器时不需要
- ONE-HOT:类别特征必须使用,避免有序性误解
- 缺失值:可以自动处理,但建议在特征工程阶段统一处理
优势1:二阶梯度优化
传统梯度提升:
1
2
3
4
5
只使用一阶梯度(梯度方向)
↓
更新参数:参数 = 参数 - 学习率 × 梯度
↓
收敛速度:慢
XGBoost:
1
2
3
4
5
使用二阶梯度(梯度 + 二阶导数)
↓
更新参数:参数 = 参数 - 学习率 × (梯度 / 二阶导数)
↓
收敛速度:快(更精确的步长)
本质:二阶梯度提供了更精确的步长信息,收敛更快。
优势2:正则化机制
L1/L2 正则化:
1
2
3
4
5
6
7
L1正则化(Lasso):
- 惩罚参数的绝对值
- 作用:特征选择(将不重要特征的权重设为0)
L2正则化(Ridge):
- 惩罚参数的平方
- 作用:防止参数过大(平滑权重)
剪枝(Pruning):
1
2
3
4
5
树构建后:
- 计算每个节点的增益
- 如果增益 < 阈值 → 剪掉该节点
↓
作用:防止树过深,降低过拟合风险
采样(Sampling):
1
2
3
4
5
6
7
行采样(subsample):
- 每棵树只用部分样本训练
- 作用:增加随机性,降低过拟合
列采样(colsample_bytree):
- 每棵树只用部分特征
- 作用:增加随机性,降低过拟合
本质:多重正则化机制,防止过拟合。
优势3:特征交互自动学习
传统方法:
1
2
3
4
5
6
需要手工创建交互特征:
- 特征A × 特征B
- 特征A + 特征B
- ...
↓
工作量大,容易遗漏
XGBoost:
1
2
3
4
5
6
树结构自动学习特征交互:
树路径:[特征A < 10, 特征B > 5]
↓
自动捕获:特征A和特征B的交互
↓
无需手工创建交互特征
本质:树结构天然支持特征交互,自动学习。
优势4:类别不平衡处理
scale_pos_weight 参数:
问题:正负样本不平衡。
例子:
1
2
3
正样本:100个
负样本:900个
比例:9:1
解决方案:
1
2
3
4
5
6
7
8
scale_pos_weight = 负样本数 / 正样本数
= 900 / 100 = 9
含义:
- 正样本的梯度权重 × 9
- 负样本的梯度权重 × 1
↓
效果:正负样本的梯度贡献平衡
本质:通过调整梯度权重,平衡正负样本的贡献。
4. XGBoost 参数配置
4.1 核心参数
n_estimators(树的数量)
定义:Boosting中树的数量。
作用:
1
2
3
4
5
6
7
8
9
树的数量越多:
- 模型越复杂
- 可能过拟合
- 训练时间越长
树的数量越少:
- 模型越简单
- 可能欠拟合
- 训练时间越短
如何选择?
1
2
3
4
5
方法:早停(Early Stopping)
- 监控验证集性能
- 如果性能不再提升 → 停止训练
↓
避免:树太多导致过拟合
典型值:50-200(根据数据量调整)
max_depth(树的最大深度)
定义:每棵树的最大深度。
作用:
1
2
3
4
5
6
7
8
9
深度越深:
- 模型越复杂
- 可能过拟合
- 训练时间越长
深度越浅:
- 模型越简单
- 可能欠拟合
- 训练时间越短
如何选择?
1
2
3
4
5
6
7
8
小数据集(< 1000样本):
- max_depth = 3-6(防止过拟合)
中等数据集(1000-10000样本):
- max_depth = 6-10
大数据集(> 10000样本):
- max_depth = 10-15
典型值:6-8(平衡复杂度和性能)
learning_rate(学习率)
定义:每棵树的贡献权重。
作用:
1
2
3
4
5
6
7
学习率越大:
- 每棵树的贡献越大
- 收敛越快,但可能不稳定
学习率越小:
- 每棵树的贡献越小
- 收敛越慢,但更稳定
与n_estimators的关系:
1
2
3
4
5
6
learning_rate × n_estimators ≈ 常数
例子:
- learning_rate=0.1, n_estimators=100
- learning_rate=0.05, n_estimators=200
→ 最终效果相似,但后者更稳定
典型值:0.01-0.3(常用0.1)
4.2 正则化参数
subsample(行采样)
定义:每棵树使用的样本比例。
作用:
1
2
3
4
subsample = 0.8:
- 每棵树只用80%的样本训练
- 增加随机性
- 降低过拟合风险
典型值:0.6-0.9(常用0.8)
colsample_bytree(列采样)
定义:每棵树使用的特征比例。
作用:
1
2
3
4
colsample_bytree = 0.8:
- 每棵树只用80%的特征
- 增加随机性
- 降低过拟合风险
典型值:0.6-0.9(常用0.8)
reg_lambda(L2 正则化)
定义:L2正则化系数。
作用:
1
2
3
4
reg_lambda越大:
- 惩罚参数平方越大
- 参数值越小(平滑)
- 降低过拟合风险
典型值:0.1-10(常用1.0)
reg_alpha(L1 正则化)
定义:L1正则化系数。
作用:
1
2
3
4
reg_alpha越大:
- 惩罚参数绝对值越大
- 更多参数变为0(特征选择)
- 降低过拟合风险
典型值:0-10(常用0,不做特征选择)
4.3 类别不平衡处理
scale_pos_weight 的作用
定义:正样本的权重倍数。
计算:
1
2
3
4
5
6
scale_pos_weight = 负样本数 / 正样本数
例子:
正样本:100个
负样本:900个
scale_pos_weight = 900 / 100 = 9
作用机制:
1
2
3
4
5
6
7
训练时:
正样本的梯度贡献 × scale_pos_weight
负样本的梯度贡献 × 1
↓
平衡正负样本的梯度贡献
↓
模型更关注正样本(少数类)
效果:
1
2
3
4
5
6
7
不使用scale_pos_weight:
- 模型偏向负样本(多数类)
- 召回率低(漏掉很多正样本)
使用scale_pos_weight:
- 模型平衡关注正负样本
- 召回率提高(找到更多正样本)
如何计算合适的权重?
方法1:基于样本比例
1
2
3
4
scale_pos_weight = 负样本数 / 正样本数
优点:简单直接
缺点:可能不够精确
方法2:基于业务需求
1
2
3
4
5
6
7
如果漏报成本高(如风险检测):
- 增加scale_pos_weight
- 例如:scale_pos_weight × 1.5
如果误报成本高(如垃圾邮件):
- 减少scale_pos_weight
- 例如:scale_pos_weight × 0.8
方法3:交叉验证调优
1
2
3
4
5
6
尝试不同的scale_pos_weight值:
- 1.0, 2.0, 5.0, 10.0, ...
↓
在验证集上评估性能
↓
选择最优值
5. 多标签分类训练流程
5.1 完整流程图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
原始数据(分表)
↓
┌─────────────────────────────────┐
│ 步骤1:数据加载与预处理 │
│ - 加载原始数据表 │
│ - 数据清洗与转换 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤2:特征工程 │
│ - Featuretools自动特征生成 │
│ - 特征矩阵构建 │
│ - 特征定义保存 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤3:标签提取与对齐 │
│ - 从汇总表提取标签 │
│ - 特征矩阵与标签对齐 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤4:创建二分类标签 │
│ - 为每个类别创建独立标签 │
│ - 正负样本定义 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤5:数据分割 │
│ - 训练集 vs 测试集 │
│ - 分层采样(保持比例) │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤6:类别平衡处理 │
│ - 下采样负样本(可选) │
│ - 计算scale_pos_weight │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤7:模型训练 │
│ - 为每个类别训练XGBoost模型 │
│ - 提取特征重要性 │
│ - 归一化权重 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤8:模型评估 │
│ - 训练集 vs 测试集性能 │
│ - 评估指标计算 │
│ - 问题诊断 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 步骤9:模型保存 │
│ - 保存模型文件 │
│ - 保存特征权重 │
│ - 保存特征定义 │
│ - 保存特征数据库 │
└─────────────────────────────────┘
5.2 数据准备
特征矩阵构建
输入:原始数据表(多表结构)
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
对象信息表(objects)
↓
行为记录表(behavior_records)
↓
事件记录表(event_records)
↓
分类记录表(category_records)
↓
特征工程(Featuretools)
↓
特征矩阵(feature_matrix)
- 每个人员一行
- 每个特征一列
- 例如:26个特征
例子:
1
2
3
4
5
6
特征矩阵:
人员ID | COUNT(border) | MODE(地点) | MEAN(间隔) | ...
-------|--------------|-----------|-----------|----
001 | 5 | 北京 | 28 | ...
002 | 3 | 上海 | 35 | ...
003 | 8 | 深圳 | 22 | ...
标签提取与对齐
输入:汇总表(包含标签信息)
流程:
1
2
3
4
5
6
7
8
9
10
11
汇总表(summary)
↓
提取"命中模型"列
↓
解析标签(支持多标签,用逗号分隔)
↓
标签字典:{人员ID: [标签列表]}
↓
转换为DataFrame
↓
与特征矩阵对齐(按人员ID合并)
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
汇总表:
对象ID | 标签
-------|----------
001 | 类别1,类别2
002 | 类别1
003 | (空)
标签提取后:
对象ID | labels
-------|-------
001 | ['类别1', '类别2']
002 | ['类别1']
003 | []
与特征矩阵对齐:
特征矩阵 + 标签 → 合并数据框
- 特征列:26个特征
- 标签列:labels(多标签格式)
5.3 二分类标签创建
核心思想
多标签 → 多个独立的二分类标签
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
原始标签(多标签格式):
对象001:['类别1', '类别2']
对象002:['类别1']
对象003:[]
↓
为每个类别创建独立的二分类标签:
类别"类别1":
对象001:1(包含"类别1")
对象002:1(包含"类别1")
对象003:0(不包含"类别1")
↓
类别"类别2":
对象001:1(包含"类别2")
对象002:0(不包含"类别2")
对象003:0(不包含"类别2")
正负样本的定义
关键理解:正负样本是针对每个类别独立定义的。
例子:
1
2
3
4
5
训练数据:
对象001:['类别1', '类别2']
对象002:['类别1']
对象003:['类别2']
对象004:[]
为”类别1”创建二分类标签:
1
2
3
4
5
6
7
对象001:标签 = 1(正样本,因为包含"类别1")
对象002:标签 = 1(正样本,因为包含"类别1")
对象003:标签 = 0(负样本,因为不包含"类别1")
对象004:标签 = 0(负样本,因为不包含"类别1")
正样本:2个(对象001, 对象002)
负样本:2个(对象003, 对象004)
为”类别2”创建二分类标签:
1
2
3
4
5
6
7
对象001:标签 = 1(正样本,因为包含"类别2")
对象002:标签 = 0(负样本,因为不包含"类别2")
对象003:标签 = 1(正样本,因为包含"类别2")
对象004:标签 = 0(负样本,因为不包含"类别2")
正样本:2个(对象001, 对象003)
负样本:2个(对象002, 对象004)
关键点:
- 每个风险类型的正负样本是独立定义的
- 多标签人员(如人员001)在不同模型中可能都是正样本
- 正常人员(如人员004)在所有模型中都是负样本
类别不平衡问题
问题:正样本通常远少于负样本。
例子:
1
2
3
4
类别"类别1":
正样本:100个(属于"类别1")
负样本:900个(不属于"类别1")
比例:9:1(严重不平衡)
影响:
- 模型可能偏向负样本(多数类)
- 准确率高但召回率低(漏掉很多正样本)
- 需要特殊处理
5.4 模型训练
训练数据分割
目的:评估模型的泛化能力。
流程:
1
2
3
4
5
6
7
8
9
完整数据集(1000个样本)
↓
随机分割(stratify=标签,保持比例)
↓
训练集(800个样本,80%)
- 用于训练模型
↓
测试集(200个样本,20%)
- 用于评估模型(模型从未见过)
分层采样(stratify):
1
2
3
4
5
6
7
8
9
10
目的:保持正负样本比例一致
不使用stratify:
训练集:正样本80个,负样本720个(比例9:1)
测试集:正样本20个,负样本180个(比例9:1)
→ 比例一致 ✅
使用stratify:
确保训练集和测试集的正负样本比例相同
→ 评估更准确
类别平衡采样策略
问题:正负样本不平衡。
解决方案1:下采样(Under-sampling)
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
计算当前比例:
负样本数 / 正样本数 = 900 / 100 = 9
↓
判断:比例 > 阈值(如3.0)?
├─→ 是 → 进行下采样
└─→ 否 → 不采样
↓
下采样:
目标比例 = 1.5(负样本/正样本)
需要的负样本数 = 正样本数 × 1.5 = 100 × 1.5 = 150
↓
从900个负样本中随机选择150个
↓
合并:
正样本:100个
负样本:150个(采样后)
比例:1.5:1 ✅
优点:
- 减少训练数据量,训练更快
- 平衡正负样本比例
缺点:
- 丢失负样本信息(可能包含有用信息)
解决方案2:scale_pos_weight
流程:
1
2
3
4
5
6
7
8
9
计算权重:
scale_pos_weight = 负样本数 / 正样本数
= 900 / 100 = 9
↓
训练时:
正样本的梯度贡献 × 9
负样本的梯度贡献 × 1
↓
效果:正负样本的梯度贡献平衡
优点:
- 不丢失数据(使用全部样本)
- 自动平衡梯度贡献
缺点:
- 可能不如采样效果好(取决于数据)
组合策略:
1
2
3
4
5
6
7
8
9
10
11
步骤1:下采样
负样本:900 → 150(下采样)
↓
步骤2:计算scale_pos_weight
基于采样后的数据:
scale_pos_weight = 150 / 100 = 1.5
↓
步骤3:训练模型
使用采样后的数据 + scale_pos_weight
↓
效果:双重平衡(采样 + 权重)
缺失值处理
问题:特征矩阵中可能有缺失值。
处理流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
检查缺失值
↓
数值特征:
缺失值 → 填充中位数(推荐)或均值
- 中位数:对异常值更稳健
- 均值:适合正态分布数据
↓
类别特征:
缺失值 → 填充"未知"类别
- 创建"未知"类别,而不是用众数
- 保留缺失值的信息
↓
确保训练和预测时处理方式一致
为什么数值特征用中位数而不是均值?
问题:均值受异常值影响大。
例子:
1
2
3
4
5
6
7
8
9
10
11
数据:[20, 25, 30, 35, 100](100是异常值)
均值 = (20 + 25 + 30 + 35 + 100) / 5 = 42
↓
被异常值100拉高
不能代表数据的真实中心 ⚠️
中位数 = 30
↓
不受异常值影响
更能代表数据的真实中心 ✅
为什么类别特征用”未知”而不是众数?
问题:缺失值可能包含信息。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
缺失值可能的原因:
- 数据未收集(信息缺失)
- 该特征不适用(业务逻辑)
- 数据错误(需要标记)
↓
如果用众数填充:
- 丢失了"缺失"这个信息
- 模型无法区分"真实值=众数"和"缺失值=众数"
↓
如果用"未知"类别:
- 保留了"缺失"这个信息
- 模型可以学习"缺失值"的模式 ✅
XGBoost的缺失值处理:
注意:XGBoost可以自动处理缺失值,但显式处理更可控。
两种方式对比:
1
2
3
4
5
6
7
方式1:显式填充
优点:可控、可解释
缺点:需要选择填充策略
方式2:XGBoost自动处理
优点:简单、自动学习
缺点:不够透明、可能不一致
建议:在特征工程阶段统一处理缺失值,确保训练和预测时一致。
关键:训练和预测时的缺失值处理必须一致。
模型训练与评估
训练流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
为每个风险类型:
步骤1:准备数据
- 特征矩阵(X)
- 二分类标签(y)
↓
步骤2:数据分割
- 训练集(X_train, y_train)
- 验证集(X_val, y_val)
- 测试集(X_test, y_test)
↓
步骤3:类别平衡处理
- 下采样(可选)
- 计算scale_pos_weight
↓
步骤4:缺失值处理
- 数值特征:中位数填充(对异常值更稳健)
- 类别特征:"未知"类别填充
↓
步骤5:特征归一化(可选,树模型不强制要求)
- 使用MinMaxScaler或StandardScaler
- 保存归一化参数,用于预测时使用
- 注意:树模型基于排序分裂,归一化不是必需的
↓
步骤6:训练XGBoost模型
- 设置参数(n_estimators, max_depth, ...)
- 使用验证集进行早停(early_stopping_rounds)
- 训练模型
↓
步骤7:提取特征重要性
- 模型自动计算
- 归一化为权重
↓
步骤8:评估模型
- 训练集性能
- 验证集性能(用于早停和调参)
- 测试集性能(最终评估)
- 对比分析
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
类别"类别1":
训练集:
- 样本数:800
- 正样本:80,负样本:720
- 下采样后:正样本80,负样本120
- scale_pos_weight = 1.5
↓
训练XGBoost模型:
- n_estimators = 100
- max_depth = 6
- learning_rate = 0.1
- scale_pos_weight = 1.5
↓
评估结果:
- 训练集准确率:95%
- 测试集准确率:90%
- 训练集F1:0.88
- 测试集F1:0.82
↓
分析:
- 训练集和测试集性能接近 → 泛化能力好 ✅
6. 类别不平衡处理
6.1 问题描述
为什么类别不平衡会影响模型性能?
核心原因:模型优化目标与业务目标不一致。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
数据分布:
正样本:100个(10%)
负样本:900个(90%)
模型优化目标:最小化错误率
↓
策略:预测所有样本为负样本
↓
结果:
- 准确率:90%(很高!)
- 但召回率:0%(漏掉所有正样本)❌
↓
业务目标:找到所有正样本(高风险人员)
- 漏报成本高
- 准确率90%但召回率0% → 完全失败
本质:
- 模型被多数类(负样本)”绑架”
- 优化目标(准确率)与业务目标(召回率)不一致
- 需要特殊处理
6.2 解决方案
方案1:下采样(Under-sampling)
定义:减少多数类(负样本)的数量。
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
原始数据:
正样本:100个
负样本:900个
比例:9:1
↓
计算目标:
目标比例:1.5:1
需要的负样本数:100 × 1.5 = 150
↓
随机选择150个负样本
↓
采样后数据:
正样本:100个
负样本:150个
比例:1.5:1 ✅
优点:
- 平衡正负样本比例
- 训练更快(数据量减少)
缺点:
- 丢失负样本信息(750个负样本被丢弃)
- 可能丢失有用信息
方案2:上采样(Over-sampling)
定义:增加少数类(正样本)的数量。
方法:
1
2
3
4
5
6
7
8
9
10
方法1:简单复制
正样本:100个 → 复制 → 900个
↓
问题:过拟合(重复样本)
方法2:SMOTE(合成少数类过采样)
生成新的合成正样本
↓
优点:样本多样性
缺点:可能生成噪声样本
在当前项目中:
- 通常不使用上采样
- 原因:正样本数量已经足够,主要是负样本太多
方案3:scale_pos_weight 参数调整
定义:调整正样本的权重。
计算:
1
2
scale_pos_weight = 负样本数 / 正样本数
= 900 / 100 = 9
作用机制:
1
2
3
4
5
6
7
训练时:
正样本的梯度贡献 × 9
负样本的梯度贡献 × 1
↓
平衡正负样本的梯度贡献
↓
模型更关注正样本
优点:
- 不丢失数据(使用全部样本)
- 自动平衡梯度贡献
- 简单高效
缺点:
- 可能不如采样效果好(取决于数据分布)
6.3 组合策略
采样 + 权重调整的结合使用
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
步骤1:下采样
负样本:900 → 150(下采样)
比例:9:1 → 1.5:1
↓
步骤2:计算scale_pos_weight
基于采样后的数据:
scale_pos_weight = 150 / 100 = 1.5
↓
步骤3:训练模型
使用采样后的数据 + scale_pos_weight
↓
效果:
- 数据层面平衡(采样)
- 梯度层面平衡(权重)
- 双重保障
为什么组合使用?
- 采样:快速平衡数据分布
- 权重:进一步平衡梯度贡献
- 组合:效果更好,更稳健
7. 模型预测与评估
7.1 为什么需要评估?评估的本质是什么?
评估的目的
目的1:验证模型的泛化能力
核心问题:在训练数据上表现好 ≠ 在新数据上表现好
例子:
1
2
3
4
5
6
7
训练集:1000个样本
模型准确率:99%
↓
测试集:200个新样本
模型准确率:70%
↓
问题:过拟合(模型"死记硬背"训练数据)
目的2:模型选择
场景:有多个候选模型,选择哪个?
流程:
1
2
3
4
5
模型A:测试集F1 = 0.75
模型B:测试集F1 = 0.82
模型C:测试集F1 = 0.78
↓
选择:模型B(性能最好)
目的3:模型优化
场景:模型表现不够好,如何改进?
流程:
1
2
3
4
5
6
7
8
9
10
评估结果:
训练集F1:0.95
测试集F1:0.70
↓
诊断:过拟合
↓
改进措施:
- 增加正则化
- 减少模型复杂度
- 增加数据量
评估的本质
定义:评估是对模型真实性能的估计。
核心挑战:
1
2
3
4
5
6
7
真实性能:模型在无限数据上的表现(未知)
↓
我们需要:在有限数据上估计真实性能
↓
方法:划分数据集
- 训练集:学习模式
- 测试集:估计性能
关键理解:
- 测试集性能是对真实性能的估计
- 估计的准确性取决于测试集的大小和质量
- 测试集越大,估计越准确
7.2 数据集划分的原理
为什么需要划分数据集?
训练集的作用:让模型学习数据中的模式(拟合)
流程:
1
2
3
4
5
6
7
训练集(800个样本)
↓
模型学习:
- 哪些特征组合 → 高风险?
- 哪些特征组合 → 低风险?
↓
模型"记住"了训练数据中的模式
验证集的作用:调整超参数,选择模型(防止过拟合)
流程:
1
2
3
4
5
6
7
8
验证集(100个样本)
↓
尝试不同的超参数:
- max_depth = 3 → 验证集F1 = 0.75
- max_depth = 6 → 验证集F1 = 0.82
- max_depth = 10 → 验证集F1 = 0.70
↓
选择:max_depth = 6(验证集性能最好)
超参数调优策略
为什么需要调优?
问题:默认参数可能不是最优的。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
默认参数:
max_depth = 6
learning_rate = 0.1
reg_lambda = 1.0
↓
验证集F1 = 0.80
调优后:
max_depth = 4
learning_rate = 0.05
reg_lambda = 2.0
↓
验证集F1 = 0.85(提升5%)✅
调优方法:
方法1:手动调优(推荐小数据集)
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
步骤1:设置基础参数
n_estimators = 100
learning_rate = 0.1
步骤2:调整树结构
尝试 max_depth = [3, 4, 5, 6, 7]
在验证集上评估
选择最优值
步骤3:调整正则化
尝试 reg_lambda = [0.5, 1.0, 2.0, 5.0]
在验证集上评估
选择最优值
步骤4:调整学习率
如果过拟合 → 降低learning_rate
如果欠拟合 → 提高learning_rate
步骤5:微调其他参数
subsample, colsample_bytree等
方法2:网格搜索(Grid Search)
流程:
1
2
3
4
5
6
7
8
9
10
定义参数网格:
max_depth = [3, 4, 5, 6]
learning_rate = [0.05, 0.1, 0.15]
reg_lambda = [0.5, 1.0, 2.0]
↓
尝试所有组合(3×3×3 = 27种)
↓
在验证集上评估每种组合
↓
选择验证集性能最好的组合
优点:系统全面
缺点:计算成本高(需要训练27个模型)
方法3:随机搜索(Random Search)
流程:
1
2
3
4
5
6
7
8
9
10
定义参数范围:
max_depth = [3, 10](随机选择)
learning_rate = [0.01, 0.3](随机选择)
reg_lambda = [0.1, 5.0](随机选择)
↓
随机选择N个组合(如20个)
↓
在验证集上评估
↓
选择验证集性能最好的组合
优点:计算成本低,通常能找到好参数
缺点:可能遗漏最优组合
调优优先级:
优先级1:核心参数
1
2
3
max_depth:树深度(影响模型复杂度)
learning_rate:学习率(影响收敛速度和精度)
reg_lambda:L2正则化(防止过拟合)
优先级2:正则化参数
1
2
reg_alpha:L1正则化(特征选择)
gamma:最小损失减少量(控制分裂)
优先级3:采样参数
1
2
subsample:行采样比例
colsample_bytree:列采样比例
调优建议:
- 小数据集(< 500样本):手动调优,重点调max_depth和reg_lambda
- 中等数据集(500-5000样本):可以使用网格搜索或随机搜索
- 大数据集(> 5000样本):可以使用贝叶斯优化(Optuna等)
交叉验证(Cross Validation)
为什么需要交叉验证?
问题:单次划分可能不稳定。
例子:
1
2
3
4
5
6
7
8
9
10
单次划分:
训练集:800个样本
测试集:200个样本
↓
测试集F1 = 0.82
问题:如果换一个划分方式呢?
测试集F1 = 0.78(差异大)⚠️
↓
单次划分的结果不稳定
交叉验证的原理:
K折交叉验证(K-Fold CV):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
数据集(1000个样本)
↓
分成K折(如5折):
折1:200个样本(测试集)
折2-5:800个样本(训练集)
↓
训练模型,评估折1 → F1_1
折2:200个样本(测试集)
折1,3-5:800个样本(训练集)
↓
训练模型,评估折2 → F1_2
...(重复K次)
↓
最终结果:
平均F1 = (F1_1 + F1_2 + ... + F1_K) / K
标准差 = std([F1_1, F1_2, ..., F1_K])
例子(5折交叉验证):
1
2
3
4
5
6
7
8
9
10
折1:F1 = 0.82
折2:F1 = 0.78
折3:F1 = 0.85
折4:F1 = 0.80
折5:F1 = 0.83
↓
平均F1 = 0.816
标准差 = 0.025
↓
结论:模型性能约为0.816 ± 0.025
交叉验证的优势:
- 更稳定:多次评估,结果更可靠
- 充分利用数据:每个样本都参与训练和测试
- 评估方差:标准差反映模型稳定性
适用场景:
- 小数据集(< 500样本):使用3-5折交叉验证
- 中等数据集(500-5000样本):使用5-10折交叉验证
- 大数据集(> 5000样本):可以使用单次划分(数据量足够)
注意事项:
- 计算成本:需要训练K个模型,计算成本高
- 时间序列数据:不能随机划分,需要使用时间序列交叉验证
- 类别不平衡:需要使用分层交叉验证(Stratified K-Fold)
测试集的作用:最终评估模型性能(无偏估计)
流程:
1
2
3
4
5
6
7
测试集(100个样本)
- 模型从未见过这些数据
↓
最终评估:
- 测试集F1 = 0.80
↓
结论:模型的真实性能约为0.80
划分的本质
本质1:模拟模型在实际应用中的表现
1
2
3
4
5
6
7
8
9
10
11
12
13
实际应用:
新数据(模型从未见过)
↓
模型预测
↓
评估性能
测试集:
模拟"新数据"
↓
模型预测(从未在训练中见过)
↓
评估性能(估计真实性能)
本质2:为什么不能只用训练集评估?
问题:过拟合的风险
例子:
1
2
3
4
5
6
7
8
9
只用训练集评估:
训练集准确率:99%
↓
结论:模型很好 ✅
↓
实际应用:
新数据准确率:60% ❌
↓
问题:过拟合(模型"死记硬背"训练数据)
解决:使用独立的测试集
1
2
3
4
训练集评估:99%(可能过拟合)
测试集评估:85%(更接近真实性能)
↓
结论:模型性能约为85%,存在过拟合风险
如何划分数据集?
方法1:随机划分(三划分)
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
完整数据集(1000个样本)
↓
随机打乱
↓
第一次划分:
- 训练集:700个(70%)
- 临时集:300个(30%)
↓
第二次划分(从临时集):
- 验证集:150个(15%)
- 测试集:150个(15%)
↓
最终划分:
- 训练集:700个(70%)
- 验证集:150个(15%)
- 测试集:150个(15%)
为什么需要三划分?
问题:如果只有训练集和测试集,无法同时进行早停和最终评估。
两划分的问题:
1
2
3
4
5
6
7
8
训练集(80%)+ 测试集(20%)
↓
问题1:早停需要验证集
- 如果用测试集早停 → 测试集被"污染"(参与了训练过程)
- 如果用训练集早停 → 无法检测过拟合
问题2:最终评估需要独立测试集
- 如果测试集用于早停 → 不能用于最终评估
三划分的优势:
1
2
3
4
5
6
7
8
9
10
训练集(70%)+ 验证集(15%)+ 测试集(15%)
↓
验证集:用于早停和超参数调优
- 监控训练过程
- 选择最优参数
- 不参与最终评估
测试集:仅用于最终评估
- 完全独立,从未参与训练
- 无偏估计模型真实性能
适用场景:
- 数据是独立同分布的(i.i.d.)
- 没有时间顺序依赖
- 需要早停机制时(推荐三划分)
方法2:时间序列划分
流程:
1
2
3
4
按时间顺序:
- 训练集:2023年1-8月的数据
- 验证集:2023年9月的数据
- 测试集:2023年10月的数据
适用场景:
- 数据有时间顺序
- 需要模拟未来预测
分层采样(stratify):
目的:保持类别分布一致
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
原始数据:
正样本:100个(10%)
负样本:900个(90%)
↓
分层采样:
训练集:
正样本:80个(10%)
负样本:720个(90%)
↓
测试集:
正样本:20个(10%)
负样本:180个(90%)
↓
比例一致 ✅
划分比例:
70-20-10(训练-验证-测试):
- 适用于:数据量充足(> 10000样本)
- 优点:测试集足够大,估计准确
80-10-10(训练-验证-测试):
- 适用于:数据量中等(1000-10000样本)
- 优点:训练集更多,模型性能更好
90-5-5(训练-验证-测试):
- 适用于:数据量少(< 1000样本)
- 优点:最大化训练数据
- 缺点:测试集小,估计可能不准确
7.3 评估指标的第一性原理
为什么需要多个评估指标?
核心原因:不同的指标关注不同的方面。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
场景:风险检测
指标1:准确率
- 关注:整体预测正确率
- 问题:类别不平衡时会被多数类主导
指标2:精确率
- 关注:预测为正的样本中,真正为正的比例
- 适用:误报成本高
指标3:召回率
- 关注:真正的正样本中,被找到的比例
- 适用:漏报成本高
指标4:F1分数
- 关注:精确率和召回率的平衡
- 适用:需要平衡两者
关键理解:
- 没有”完美”的指标
- 只有”适合”的指标
- 业务目标决定指标选择
准确率(Accuracy)的本质
定义:预测正确的样本数 / 总样本数
公式:
1
2
3
4
5
6
7
准确率 = (TP + TN) / (TP + TN + FP + FN)
其中:
TP(True Positive):真正例(预测为正,实际为正)
TN(True Negative):真负例(预测为负,实际为负)
FP(False Positive):假正例(预测为正,实际为负)
FN(False Negative):假负例(预测为负,实际为正)
例子:
1
2
3
4
5
6
7
8
9
10
预测结果:
预测为正:150个
其中:真正为正:100个(TP)
假正:50个(FP)
预测为负:850个
其中:真负:800个(TN)
假负:50个(FN)
准确率 = (100 + 800) / 1000 = 90%
适用场景:类别平衡的数据
例子:
1
2
3
4
5
数据分布:
正样本:500个(50%)
负样本:500个(50%)
↓
准确率有意义 ✅
局限性:类别不平衡时,准确率会误导
例子:
1
2
3
4
5
6
7
8
9
10
11
数据分布:
正样本:10个(1%)
负样本:990个(99%)
策略:预测所有样本为负样本
↓
准确率:99%(很高!)
↓
但召回率:0%(漏掉所有正样本)❌
↓
结论:准确率99%但模型完全失败
为什么会有这个问题?
- 准确率忽略了类别分布
- 多数类(负样本)主导了准确率
- 少数类(正样本)的影响被忽略
精确率(Precision)的本质
定义:预测为正的样本中,真正为正的比例
公式:
1
2
3
精确率 = TP / (TP + FP)
含义:预测为正的样本中,有多少是真的正样本?
本质含义:模型的”严谨程度”(宁缺毋滥)
例子:
1
2
3
4
5
6
7
8
9
10
预测结果:
预测为正:100个
其中:真正为正:90个(TP)
假正:10个(FP)
精确率 = 90 / 100 = 90%
↓
含义:预测为正的100个样本中,90个是真的正样本
↓
模型很"严谨":只有很确定才预测为正
适用场景:误报成本高
例子:
1
2
3
4
5
6
垃圾邮件过滤:
误报成本高(正常邮件被误判为垃圾邮件)
↓
关注精确率:预测为垃圾邮件的,有多少真的是垃圾邮件?
↓
精确率高 → 误报少 ✅
可视化理解:
1
2
3
4
5
预测为正的样本:
┌─────────────────┐
│ 真正为正(TP) │ ← 精确率关注这部分
│ 假正(FP) │ ← 误报,成本高
└─────────────────┘
召回率(Recall)的本质
定义:真正的正样本中,被正确预测为正的比例
公式:
1
2
3
召回率 = TP / (TP + FN)
含义:真正的正样本中,有多少被找到了?
本质含义:模型的”覆盖率”(宁滥勿缺)
例子:
1
2
3
4
5
6
7
8
9
实际正样本:100个
其中:被找到:80个(TP)
被漏掉:20个(FN)
召回率 = 80 / 100 = 80%
↓
含义:100个真正的正样本中,找到了80个
↓
模型"覆盖率":80%
适用场景:漏报成本高
例子:
1
2
3
4
5
6
疾病诊断:
漏报成本高(有病但没诊断出来)
↓
关注召回率:真正的病人中,有多少被诊断出来了?
↓
召回率高 → 漏报少 ✅
可视化理解:
1
2
3
4
5
实际正样本:
┌─────────────────┐
│ 被找到(TP) │ ← 召回率关注这部分
│ 被漏掉(FN) │ ← 漏报,成本高
└─────────────────┘
F1 分数的本质
定义:精确率和召回率的调和平均
公式:
1
2
3
4
F1 = 2 × (精确率 × 召回率) / (精确率 + 召回率)
或:
F1 = 2 × TP / (2 × TP + FP + FN)
为什么用调和平均而不是算术平均?
算术平均:
1
2
3
4
5
6
7
算术平均 = (精确率 + 召回率) / 2
例子:
精确率 = 0.9,召回率 = 0.1
算术平均 = (0.9 + 0.1) / 2 = 0.5
↓
问题:即使召回率很低,算术平均仍然较高
调和平均:
1
2
3
4
5
6
7
调和平均 = 2 × (精确率 × 召回率) / (精确率 + 召回率)
例子:
精确率 = 0.9,召回率 = 0.1
调和平均 = 2 × (0.9 × 0.1) / (0.9 + 0.1) = 0.18
↓
优点:只有当两者都高时,F1才高
本质:平衡精确率和召回率的权衡
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
场景1:高精确率,低召回率
精确率 = 0.95,召回率 = 0.30
F1 = 2 × (0.95 × 0.30) / (0.95 + 0.30) = 0.46
↓
含义:很严谨,但覆盖率低
场景2:低精确率,高召回率
精确率 = 0.50,召回率 = 0.90
F1 = 2 × (0.50 × 0.90) / (0.50 + 0.90) = 0.64
↓
含义:覆盖率高,但不够严谨
场景3:高精确率,高召回率
精确率 = 0.85,召回率 = 0.80
F1 = 2 × (0.85 × 0.80) / (0.85 + 0.80) = 0.82
↓
含义:既严谨又全面 ✅
适用场景:需要同时考虑精确率和召回率
F1的局限性:
- 假设精确率和召回率同等重要
- 但实际可能不是(如漏报成本更高)
解决方案:F-beta分数
1
2
3
4
5
F-beta = (1 + β²) × (精确率 × 召回率) / (β² × 精确率 + 召回率)
β > 1:更关注召回率(漏报成本高)
β < 1:更关注精确率(误报成本高)
β = 1:F1(两者同等重要)
ROC-AUC 的本质
ROC曲线的本质:不同阈值下的真阳性率 vs 假阳性率
定义:
1
2
3
4
5
6
真阳性率(TPR)= TP / (TP + FN) = 召回率
假阳性率(FPR)= FP / (FP + TN)
ROC曲线:
X轴:假阳性率(FPR)
Y轴:真阳性率(TPR)
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
不同阈值下的性能:
阈值 = 0.9(很严格):
TPR = 0.3(只找到30%的正样本)
FPR = 0.01(只有1%的负样本被误判)
↓
点:(0.01, 0.3)
阈值 = 0.5(中等):
TPR = 0.8(找到80%的正样本)
FPR = 0.2(20%的负样本被误判)
↓
点:(0.2, 0.8)
阈值 = 0.1(很宽松):
TPR = 0.95(找到95%的正样本)
FPR = 0.5(50%的负样本被误判)
↓
点:(0.5, 0.95)
连接所有点 → ROC曲线
AUC的本质:模型区分正负样本的能力
定义:ROC曲线下的面积(Area Under Curve)
含义:
1
2
3
AUC = 1.0:完美区分(所有正样本的分数 > 所有负样本的分数)
AUC = 0.5:随机猜测(无法区分)
AUC = 0.0:完全错误(所有预测都反了)
例子:
1
2
3
4
5
6
7
模型A:AUC = 0.95
- 区分能力强
- 正样本和负样本的分数分布分离明显
模型B:AUC = 0.65
- 区分能力弱
- 正样本和负样本的分数分布重叠较多
适用场景:
- 关注模型的排序能力
- 而非特定阈值下的性能
- 适合类别不平衡场景
与F1的区别:
1
2
3
4
5
6
7
8
9
F1:
- 关注特定阈值下的性能
- 需要设置阈值(如0.5)
- 阈值不同,F1不同
AUC:
- 关注整体排序能力
- 不需要设置阈值
- 评估所有可能的阈值
如何选择合适的指标?
从业务目标出发:
场景1:误报成本高
1
2
3
4
5
6
7
例子:垃圾邮件过滤
- 误报:正常邮件被误判为垃圾邮件(用户不满)
- 漏报:垃圾邮件没被过滤(影响较小)
↓
关注:精确率
- 预测为垃圾邮件的,有多少真的是垃圾邮件?
- 精确率高 → 误报少 ✅
场景2:漏报成本高
1
2
3
4
5
6
7
例子:疾病诊断、风险检测
- 漏报:有病但没诊断出来(生命危险)
- 误报:没病但被诊断出来(可以复查)
↓
关注:召回率
- 真正的病人中,有多少被诊断出来了?
- 召回率高 → 漏报少 ✅
场景3:需要平衡
1
2
3
4
5
6
例子:一般分类任务
- 误报和漏报成本相当
↓
关注:F1分数
- 平衡精确率和召回率
- F1高 → 整体性能好 ✅
类别不平衡场景:
不能用准确率:
1
2
3
4
5
6
7
8
9
数据分布:
正样本:10个(1%)
负样本:990个(99%)
准确率:99%(被多数类主导)
↓
但召回率:0%(完全失败)
↓
结论:准确率误导 ❌
用F1或AUC:
1
2
3
4
F1:关注少数类(正样本)的性能
AUC:关注排序能力(不受类别分布影响)
↓
都能反映真实性能 ✅
多标签场景:
每个标签单独计算指标:
1
2
3
4
5
6
7
8
9
标签"类别1":
精确率:0.85
召回率:0.80
F1:0.82
标签"类别2":
精确率:0.75
召回率:0.70
F1:0.72
然后平均:
1
2
3
4
5
6
7
宏平均(Macro Average):
平均F1 = (0.82 + 0.72) / 2 = 0.77
- 每个标签同等重要
微平均(Micro Average):
将所有标签的TP、FP、FN合并后计算
- 样本多的标签权重更大
7.4 模型预测
概率预测(predict_proba)的本质
定义:输出概率值,而非类别标签。
例子:
1
2
3
4
5
6
7
8
输入:对象A的特征向量
↓
模型预测:
类别1:0.85(85%概率)
类别2:0.60(60%概率)
类别3:0.10(10%概率)
↓
输出:概率值(0到1之间)
概率的含义:模型对预测的”信心程度”
例子:
1
2
3
4
5
6
7
8
9
高置信度:
类别1:0.95(95%概率)
↓
含义:模型非常确定
低置信度:
类别1:0.55(55%概率)
↓
含义:模型不太确定(接近随机猜测)
为什么需要概率?
原因1:阈值的选择
流程:
1
2
3
4
5
6
7
8
模型输出概率:
类别1:0.72(72%概率)
↓
设置阈值:
阈值 = 0.5 → 预测为"是"(0.72 > 0.5)
阈值 = 0.8 → 预测为"否"(0.72 < 0.8)
↓
阈值不同,预测结果不同
原因2:业务决策
流程:
1
2
3
4
5
6
7
8
9
10
概率 = 0.95:
→ 高风险,立即处理
概率 = 0.60:
→ 中等风险,进一步调查
概率 = 0.30:
→ 低风险,暂时不处理
↓
概率值帮助业务决策
多标签预测结果的融合
流程:
1
2
3
4
5
6
7
8
9
10
11
12
每个标签独立的概率预测:
模型1(类别1) → 概率1 = 0.85
模型2(类别2) → 概率2 = 0.60
模型3(类别3) → 概率3 = 0.10
↓
设置阈值(如0.5):
概率1 = 0.85 > 0.5 → 预测为"是"
概率2 = 0.60 > 0.5 → 预测为"是"
概率3 = 0.10 < 0.5 → 预测为"否"
↓
最终结果:
['类别1', '类别2']
如何设置阈值?
方法1:固定阈值
1
2
3
4
所有标签使用相同阈值:
阈值 = 0.5
↓
简单,但可能不够灵活
方法2:标签特定阈值
1
2
3
4
5
6
不同标签使用不同阈值:
类别1:阈值 = 0.7(更严格)
类别2:阈值 = 0.5(中等)
类别3:阈值 = 0.3(更宽松)
↓
灵活,但需要调优
阈值选择的本质:平衡精确率和召回率
流程:
1
2
3
4
5
6
7
8
9
阈值越高:
- 精确率越高(更严谨)
- 召回率越低(覆盖率低)
↓
阈值越低:
- 精确率越低(不够严谨)
- 召回率越高(覆盖率高)
↓
需要在精确率和召回率之间权衡
7.5 评估结果的分析与问题诊断
模型表现差的可能原因(从原理出发思考)
原因1:数据问题
问题1.1:训练集和测试集分布不一致
表现:
1
2
3
4
训练集性能:95%
测试集性能:60%
↓
性能差距大,但可能不是过拟合
可能原因:
- 数据泄露:测试集包含训练时的信息
- 选择偏差:训练集和测试集来自不同分布
- 时间漂移:训练数据是旧的,测试数据是新的
问题1.2:数据质量差
表现:
1
2
3
4
训练集性能:70%
测试集性能:65%
↓
性能都不高,可能不是过拟合
可能原因:
- 噪声数据:数据中包含错误信息
- 缺失值:大量缺失值影响模型学习
- 错误标签:标签标注错误
问题1.3:数据量不足
表现:
1
2
3
4
训练集性能:80%
测试集性能:75%
↓
性能都不高,可能欠拟合
可能原因:
- 样本太少:无法学习有效模式
- 特征太多:维度灾难
原因2:特征问题
问题2.1:特征与目标无关
表现:
1
2
3
特征重要性都很低(< 0.01)
↓
特征没有信息量
可能原因:
- 特征与目标变量不相关
- 特征选择不当
问题2.2:特征冗余
表现:
1
2
3
特征A和特征B高度相关(相关系数 > 0.9)
↓
信息重复
可能原因:
- 特征工程产生冗余特征
- 需要特征选择
问题2.3:特征缺失
表现:
1
2
3
模型性能达到上限,无法进一步提升
↓
可能缺少关键特征
可能原因:
- 特征工程不充分
- 缺少重要业务特征
原因3:模型问题
问题3.1:模型太简单(欠拟合)
表现:
1
2
3
4
训练集性能:60%
测试集性能:58%
↓
训练集和测试集性能都差
可能原因:
- 模型复杂度不够(max_depth太小)
- 正则化太强
- 特征不足
问题3.2:模型太复杂(过拟合)
表现:
1
2
3
4
训练集性能:99%
测试集性能:70%
↓
训练集好,测试集差
可能原因:
- 模型复杂度太高(max_depth太大)
- 正则化不够
- 数据量不足
原因4:优化问题
问题4.1:损失函数不合适
表现:
1
2
3
优化目标与业务目标不一致
↓
模型优化了错误的目标
问题4.2:训练不充分
表现:
1
2
3
训练集性能还在提升
↓
可能需要更多迭代
如何诊断问题?
方法1:对比训练集和测试集表现
诊断流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
训练集好,测试集差:
→ 过拟合
↓
改进:增加正则化、减少复杂度、增加数据量
训练集差,测试集差:
→ 欠拟合或数据问题
↓
改进:增加复杂度、特征工程、检查数据质量
训练集差,测试集好:
→ 可能数据划分有问题
↓
检查:数据划分是否正确
方法2:分析混淆矩阵
混淆矩阵:
1
2
3
4
实际\预测 | 预测为正 | 预测为负
---------|---------|---------
实际为正 | TP | FN
实际为负 | FP | TN
分析:
1
2
3
4
5
6
7
8
哪些类别容易混淆?
- TP多,FP少 → 模型表现好
- FP多 → 误报多(精确率低)
- FN多 → 漏报多(召回率低)
是否有系统性错误?
- 某些类别总是被误判
- 可能特征不足或数据问题
方法3:分析错误样本
流程:
1
2
3
4
5
6
7
8
9
收集错误预测的样本
↓
分析共同特征:
- 错误样本有什么共同点?
- 是噪声还是模式未学习到?
↓
判断:
- 如果是噪声 → 数据清洗
- 如果是模式 → 特征工程或模型改进
改进措施(从原理出发)
措施1:如果是过拟合
原理:模型太复杂,记住了训练数据的噪声
改进方法:
方法1:增加正则化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
增加L2正则化(reg_lambda):
reg_lambda: 1.0 → 5.0
↓
惩罚参数过大
增加L1正则化(reg_alpha):
reg_alpha: 0 → 1.0
↓
特征选择,减少参数
增加采样(subsample, colsample_bytree):
subsample: 0.8 → 0.6
↓
增加随机性
方法2:增加数据量
1
2
3
4
5
6
7
数据增强:
- 生成更多训练样本
- 增加数据多样性
收集更多数据:
- 扩大训练集规模
- 提高数据质量
方法3:降低模型复杂度
1
2
3
4
5
6
7
8
9
减少树的数量(n_estimators):
100 → 50
↓
模型更简单
减少树深度(max_depth):
8 → 4
↓
防止树过深
方法4:早停(Early Stopping)
早停的原理:
1
2
3
4
5
6
7
8
9
10
训练过程:
第1轮:验证集F1 = 0.75
第2轮:验证集F1 = 0.78
第3轮:验证集F1 = 0.82
第4轮:验证集F1 = 0.82
第5轮:验证集F1 = 0.81(下降)
...
第10轮:验证集F1 = 0.80(连续10轮不提升)
↓
早停:停止训练,使用第3轮的模型 ✅
为什么需要早停?
问题:树太多会导致过拟合。
例子:
1
2
3
4
5
6
7
8
9
不使用早停:
训练100棵树
训练集F1:0.95(很好)
测试集F1:0.75(过拟合)❌
使用早停(10轮不提升就停止):
训练30棵树(自动停止)
训练集F1:0.88(稍低)
测试集F1:0.85(泛化更好)✅
使用方法:
1
2
3
4
5
6
model.fit(
X_train, y_train,
eval_set=[(X_val, y_val)], # 验证集用于监控
early_stopping_rounds=10, # 10轮不提升就停止
verbose=False
)
关键理解:
- 验证集独立:验证集不能参与训练,只用于监控性能
- 早停轮数:通常设置为10-20轮(根据数据量调整)
- 自动优化:自动找到最优树数量,防止过拟合
措施2:如果是欠拟合
原理:模型太简单,无法捕捉数据中的模式
改进方法:
方法1:增加模型复杂度
1
2
3
4
5
6
7
8
9
增加树的数量(n_estimators):
50 → 200
↓
模型更复杂
增加树深度(max_depth):
3 → 8
↓
允许更深的树
方法2:特征工程
1
2
3
4
5
6
7
8
增加有用特征:
- 构造新特征
- 特征组合
- 特征变换
改进特征质量:
- 去除噪声特征
- 选择重要特征
方法3:减少正则化
1
2
3
4
5
6
7
8
9
减少L2正则化(reg_lambda):
5.0 → 1.0
↓
允许参数更大
减少采样(subsample):
0.6 → 0.8
↓
使用更多数据
措施3:如果是数据问题
改进方法:
方法1:数据清洗
1
2
3
4
5
6
7
去除噪声:
- 识别异常值
- 删除错误数据
处理缺失值:
- 填充缺失值
- 或删除缺失值过多的样本
方法2:数据增强
1
2
3
4
生成更多样本:
- SMOTE(合成少数类)
- 数据变换
- 数据组合
方法3:重新收集数据
1
2
3
4
确保数据质量:
- 正确的标签
- 完整的数据
- 代表性样本
措施4:如果是特征问题
改进方法:
方法1:特征选择
1
2
3
4
5
6
7
8
去除无关特征:
- 基于重要性
- 基于相关性
- 基于Permutation Importance
去除冗余特征:
- 相关性分析
- 特征聚类
方法2:特征工程
1
2
3
4
5
6
7
8
构造新特征:
- 特征组合
- 特征变换
- 特征交互
改进特征质量:
- 更好的特征提取
- 领域知识融入
措施5:如果是类别不平衡
改进方法:
方法1:使用合适的评估指标
1
2
3
4
5
6
不用准确率:
- 会被多数类主导
用F1或AUC:
- 关注少数类性能
- 不受类别分布影响
方法2:使用类别权重
1
2
3
4
计算scale_pos_weight:
scale_pos_weight = 负样本数 / 正样本数
↓
平衡正负样本的梯度贡献
方法3:采样策略
1
2
3
4
5
6
7
下采样:
- 减少多数类样本
- 平衡正负样本比例
上采样:
- 增加少数类样本
- SMOTE生成合成样本
方法4:使用合适的损失函数
1
2
3
4
5
Focal Loss:
- 关注难分类样本
- 降低易分类样本的权重
↓
更适合类别不平衡
8. 模型保存与加载
8.1 模型文件组织
每个标签的独立模型文件
文件结构:
1
2
3
4
5
6
7
model_dir/
├── multilabel_model_类别1.pkl # 类别1模型
├── multilabel_model_类别2.pkl # 类别2模型
├── feature_weights_类别1.yaml # 类别1特征权重
├── feature_weights_类别2.yaml # 类别2特征权重
├── feature_definitions.pkl # 特征定义(所有模型共享)
└── feature_database.pkl # 特征数据库(所有模型共享)
为什么每个标签独立文件?
原因1:易于扩展
1
2
3
4
5
6
新增风险类型:
只需训练新模型
↓
保存为新文件
↓
不影响已有模型 ✅
原因2:易于更新
1
2
3
4
更新某个标签的模型:
只需替换对应的模型文件
↓
其他标签的模型不受影响 ✅
原因3:易于管理
1
2
3
4
删除某个标签:
只需删除对应的模型文件
↓
其他标签的模型不受影响 ✅
特征定义文件的重要性
为什么需要保存特征定义?
问题:训练时和预测时特征必须一致
场景:
1
2
3
4
5
6
7
8
9
10
11
训练时:
特征1:COUNT(border_records)
特征2:MODE(border_records.地点)
特征3:MEAN(border_records.间隔天数)
↓
训练模型
预测时:
如果特征顺序或名称不一致
↓
模型无法正确预测 ❌
解决方案:保存特征定义文件
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
训练时:
生成特征定义(feature_definitions)
↓
保存到文件(feature_definitions.pkl)
↓
文件包含:特征名称、特征函数、特征结构
预测时:
加载特征定义文件
↓
使用相同的特征定义生成特征
↓
确保特征与训练时完全一致 ✅
特征数据库的作用
特征数据库包含:
1
2
3
4
5
feature_database.pkl:
- 特征矩阵:所有训练样本的特征向量
- 标签信息:每个样本的风险类型标签
- 户籍地信息:从身份证号提取的行政区划
- 轨迹信息:出入境轨迹数据
用途:
用途1:相似度检索
1
2
3
4
5
6
7
查询人员
↓
提取特征向量
↓
与特征数据库中的特征向量计算相似度
↓
找到相似人员
用途2:特征对齐
1
2
3
4
5
6
查询时:
确保特征格式与数据库一致
↓
可以直接使用数据库中的特征向量
↓
避免重复提取
用途3:轨迹匹配
1
2
3
4
5
查询条件:同轨迹
↓
从特征数据库查找轨迹信息
↓
匹配相同轨迹的人员
8.2 模型加载机制
加载流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
查找模型文件
- 模式:multilabel_model_*.pkl
↓
加载每个模型文件
- 每个文件包含:模型 + 元数据
↓
从第一个模型获取共享元数据
- feature_names(特征名称列表)
- label_types(标签类型列表)
- categorical_categories(类别编码)
↓
完成加载
- 所有模型可用
- 元数据完整
增量更新支持
场景:新增风险类型
流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
已有模型:
- multilabel_model_类别1.pkl
- multilabel_model_类别2.pkl
↓
新增类别:"类别3"
↓
训练新模型
↓
保存新文件:
- multilabel_model_其他风险.pkl
↓
加载时:
- 自动发现新文件
- 加载新模型
- 不影响已有模型 ✅
9. 最佳实践与注意事项
9.1 特征一致性保证
为什么需要特征一致性?
核心原因:训练时和预测时特征必须完全一致。
不一致的后果:
1
2
3
4
5
6
7
8
训练时:
特征顺序:[特征1, 特征2, 特征3]
特征名称:['COUNT(...)', 'MODE(...)', 'MEAN(...)']
预测时:
特征顺序:[特征2, 特征1, 特征3](顺序不同)
↓
模型预测错误 ❌
如何保证一致性?
方法1:保存特征定义文件
1
2
3
4
5
6
7
8
训练时:
保存特征定义(feature_definitions.pkl)
↓
预测时:
加载特征定义
使用相同的定义生成特征
↓
确保一致性 ✅
方法2:特征对齐检查
1
2
3
4
5
6
7
8
预测前检查:
- 特征名称是否一致?
- 特征顺序是否一致?
- 特征类型是否一致?
↓
不一致 → 对齐
↓
一致 → 预测
方法3:缺失特征处理
1
2
3
如果预测时缺少某个特征:
- 填充默认值(0或均值)
- 或报错(更安全)
9.2 缺失值处理的一致性
问题:训练和预测时处理方式不一致
场景:
1
2
3
4
5
6
7
训练时:
缺失值 → 填充0
预测时:
缺失值 → 填充均值
↓
处理方式不一致 → 预测错误 ❌
解决方案
统一处理规则:
1
2
3
4
5
6
7
8
9
规则1:数值特征
- 缺失值 → 填充0(训练和预测一致)
规则2:类别特征
- 缺失值 → 填充"未知"(训练和预测一致)
规则3:记录处理规则
- 在模型元数据中记录处理规则
- 预测时使用相同的规则
9.3 类别编码的一致性
问题:Categorical特征编码不一致
场景:
1
2
3
4
5
6
7
8
9
10
11
训练时:
类别特征"地点":
'北京' → 编码为 0
'上海' → 编码为 1
'深圳' → 编码为 2
预测时:
如果编码顺序不同:
'北京' → 编码为 1(错误!)
↓
预测错误 ❌
解决方案
保存类别编码映射:
1
2
3
4
5
6
7
8
9
10
11
12
训练时:
记录类别到编码的映射:
{'北京': 0, '上海': 1, '深圳': 2}
↓
保存到模型元数据
预测时:
加载类别编码映射
↓
使用相同的映射编码
↓
确保一致性 ✅
9.4 模型版本管理
为什么需要版本管理?
场景:
1
2
3
4
5
6
7
版本1:使用特征A、B、C训练模型1
版本2:使用特征A、B、D训练模型2(特征C改为D)
↓
问题:
- 模型1需要特征C
- 模型2需要特征D
- 如何管理不同版本?
解决方案
方法1:特征定义文件版本化
1
2
3
4
feature_definitions_v1.pkl # 版本1的特征定义
feature_definitions_v2.pkl # 版本2的特征定义
↓
每个版本的特征定义独立保存
方法2:模型元数据中包含特征定义
1
2
3
4
5
6
每个模型文件包含:
- 模型本身
- 特征定义(该模型使用的特征)
- 版本号
↓
模型文件自包含,包含所有必要信息
方法3:特征数据库
1
2
3
4
5
将特征定义存储在数据库中
↓
支持版本管理
- 不同版本的特征定义
- 版本查询和切换
总结
10. XGBoost训练最佳实践总结
10.1 数据预处理最佳实践
缺失值处理
数值特征:
- 推荐:使用中位数填充(对异常值更稳健)
- 备选:使用均值填充(适合正态分布数据)
- 注意:XGBoost可以自动处理缺失值,但显式处理更可控
类别特征:
- 推荐:使用”未知”类别填充(保留缺失值信息)
- 备选:使用众数填充(简单但可能丢失信息)
特征归一化
树模型(XGBoost使用决策树弱学习器):
- 不需要归一化:树模型基于排序分裂,不受尺度影响
- 可选归一化:可能提升计算效率或特征公平性
其他模型:
- 梯度下降类模型:必须归一化
- 距离计算类模型:必须归一化
10.2 数据划分最佳实践
三划分数据集
推荐划分:
1
2
3
训练集:70%(用于训练模型)
验证集:15%(用于早停和超参数调优)
测试集:15%(仅用于最终评估)
为什么需要三划分?
- 验证集:用于早停和超参数调优,不能用于最终评估
- 测试集:完全独立,仅用于最终评估,无偏估计
分层采样
适用场景:类别不平衡的数据
作用:确保训练集、验证集、测试集的类别分布一致
10.3 训练过程最佳实践
早停机制(Early Stopping)
原理:监控验证集性能,如果不再提升就停止训练
使用方法:
1
2
3
4
5
6
model.fit(
X_train, y_train,
eval_set=[(X_val, y_val)],
early_stopping_rounds=10,
verbose=False
)
优势:
- 防止过拟合
- 自动找到最优树数量
- 节省训练时间
类别不平衡处理
方法1:scale_pos_weight
1
scale_pos_weight = 负样本数 / 正样本数
方法2:下采样 + scale_pos_weight
1
先下采样平衡数据,再使用scale_pos_weight
10.4 超参数调优最佳实践
调优优先级
优先级1:核心参数
max_depth:树深度(影响模型复杂度)learning_rate:学习率(影响收敛速度和精度)reg_lambda:L2正则化(防止过拟合)
优先级2:正则化参数
reg_alpha:L1正则化(特征选择)gamma:最小损失减少量(控制分裂)
优先级3:采样参数
subsample:行采样比例colsample_bytree:列采样比例
调优方法
小数据集(< 500样本):
- 手动调优,重点调核心参数
中等数据集(500-5000样本):
- 网格搜索或随机搜索
大数据集(> 5000样本):
- 贝叶斯优化(Optuna等)
10.5 评估最佳实践
交叉验证
适用场景:
- 小数据集(< 500样本):使用3-5折交叉验证
- 中等数据集(500-5000样本):使用5-10折交叉验证
- 大数据集(> 5000样本):可以使用单次划分
优势:
- 更稳定的性能评估
- 充分利用数据
- 评估模型稳定性(通过标准差)
10.6 完整训练流程(优化版)
优化后的训练流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
步骤1:数据准备
- 特征矩阵(X)
- 二分类标签(y)
↓
步骤2:数据划分(三划分)
- 训练集(70%)
- 验证集(15%)
- 测试集(15%)
↓
步骤3:数据预处理
- 缺失值处理(中位数/"未知"类别)
- 特征归一化(可选,树模型不强制要求)
↓
步骤4:类别平衡处理
- 下采样(可选)
- 计算scale_pos_weight
↓
步骤5:模型训练(带早停)
- 设置参数
- 使用验证集早停
- 训练模型
↓
步骤6:超参数调优(可选)
- 在验证集上尝试不同参数
- 选择最优参数
↓
步骤7:最终评估
- 在测试集上评估(仅一次)
- 分析性能
↓
步骤8:特征重要性分析
- 提取特征重要性
- 归一化为权重
关键原则:
- 验证集独立:验证集不能参与训练,只用于早停和调参
- 测试集独立:测试集完全独立,仅用于最终评估
- 一致性:训练和预测时使用相同的预处理方法
本文深入介绍了多标签分类和XGBoost模型训练的核心概念和实践方法。关键要点:
- 多标签分类的本质:类别非互斥,一个样本可以属于多个类别
- Binary Relevance方案:将多标签问题分解为多个独立的二分类问题
- XGBoost的优势:二阶梯度优化、正则化机制、特征交互自动学习
- 类别不平衡处理:下采样 + scale_pos_weight的组合策略
- 评估指标的选择:根据业务目标选择合适的指标(精确率、召回率、F1、AUC)
- 问题诊断:从数据、特征、模型、优化四个维度系统分析
- 特征一致性:训练和预测时特征必须完全一致
