核心思路是照着题面给的公式把决策树建出来,难点不在算法而在实现细节:特征只在"从根到当前节点"这条路径上禁用、增益并列取编号最小的特征、叶节点多数表决并列时取 0。
训练集只有 3 个布尔特征,决策树的深度最多为 3(一条路径上每个特征最多用一次),所以整棵树的规模是常数级,不需要任何剪枝或优化技巧,按定义递归即可。
实现方法:
一款 5v5 竞技手游每逢版本更新都会上新皮肤。商店推荐位如果不加区分地把所有皮肤推给所有玩家,玩家划得累,购买转化率也上不去。项目组的做法是:先从历史数据里攒一批"看过页面、最终买没买"的记录,用决策树把购买意向学出来,再把新玩家逐条喂进这棵树做预测。
购买意向只用三个布尔特征描述,编号为 0、1、2:
| 特征编号 | 含义 | 取值 |
|---|---|---|
| 0 | 是否 VIP 会员(含月卡) | 0 表示否,1 表示是 |
| 1 | 是否买过该英雄的皮肤 | 0 表示否,1 表示是 |
| 2 | 是否把该英雄打上过最高段位 | 0 表示否,1 表示是 |
训练样本的类别也只有两种:0 表示不购买(不推荐),1 表示购买(推荐)。
对只含两类的样本集 S,记类别 0、1 的样本占比为 p0、p1(p0+p1=1),熵定义为
H(S)=−x∈{0,1}∑pxlog2px其中 px=0 的项按 0log20=0 处理。
用特征 A 把 S 分成 S0(取值为 0 的样本)与 S1(取值为 1 的样本),分裂后的条件熵是两棵子树熵按样本量加权平均:
H(S∣A)=v∈{0,1}∑∣S∣∣Sv∣H(Sv)特征 A 的信息增益,是分裂前后不确定性的减少量:
IG(S,A)=H(S)−H(S∣A)从根节点开始递归建树。在当前节点上,对尚未出现在从根到该节点的路径上的特征逐个计算信息增益,取增益最大的特征作为分裂特征;若几个特征的增益并列最大,取编号最小的那一个。然后按该特征的取值把节点内的样本分成两类:取值为 0 的进左子树,取值为 1 的进右子树。
某个特征一旦在某条路径上用过了,就不能在这条路径的下层节点上再用;但在另一条分支上它仍然可用。
满足下列任意一条,当前节点就成为叶节点,不再分裂:
条件 1 的叶节点,类别就是节点内样本的类别;条件 2、3 的叶节点按多数表决定类:节点内类别 1 的样本多于类别 0 就取 1,少于就取 0,两者数量相等时取 0。
对一条待预测样本,从根节点出发,读出当前节点分裂特征的取值:0 走左子树,1 走右子树,直到落在叶节点,输出该叶节点的类别。
例如下面这段输入描述 4 条训练样本与 4 条待预测样本:
4 4
1 1 1 1
1 1 0 0
1 1 1 0
0 0 0 0
1 1 1
1 1 0
1 0 1
0 0 1
共 M 行,每行一个整数 0 或 1,按输入顺序给出每条待预测样本的类别。不要输出多余的空格或空行。
时间限制:C/C++ 1000ms,其他语言 2000ms
内存限制:C/C++ 512MB,其他语言 1024MB
输入
5 5
1 0 1 1
1 1 0 1
0 0 1 0
0 1 1 1
1 0 0 0
1 0 1
1 1 0
0 0 1
0 1 1
1 0 0
输出
1
1
0
1
0
解释:训练集共 5 条,类别 0 有 2 条、类别 1 有 3 条,H(S)≈0.9710。三个特征的信息增益分别约为 0.0200、0.4200、0.0200,最大的是特征 1,根节点按特征 1 分裂。特征 1 取 0 的一侧有 3 条样本,类别为 1、0、0,此时特征 0 与特征 2 的增益并列(都约为 0.2516),按规则取编号较小的特征 0;其中特征 0 取 1 的两条样本类别仍不同,再按特征 2 分开。特征 1 取 1 的一侧两条样本类别都是 1,直接成为叶节点。5 条待预测样本依次落到类别 1、1、0、1、0 的叶节点上。
输入
7 5
0 1 0 1
0 0 1 0
0 1 1 1
0 0 0 0
1 0 0 0
1 0 1 1
1 1 0 0
0 0 0
1 1 1
1 0 1
0 1 0
1 1 0
输出
0
0
1
1
0
解释:训练集共 7 条,类别 0 有 4 条、类别 1 有 3 条,H(S)≈0.9852。特征 0 的增益约为 0.0202,特征 1 与特征 2 的增益并列最大(都约为 0.1281),按规则取编号较小的特征 1 作为根节点。特征 1 取 1 的一侧有 3 条样本,类别为 1、1、0,特征 0 的增益约为 0.9183,大于特征 2 的 0.2516,按特征 0 分裂后两类完全分开。特征 1 取 0 的一侧有 4 条样本,类别为 0、0、0、1,特征 0 与特征 2 的增益并列(都约为 0.3113),取特征 0;其取值 1 的两条样本再按特征 2 分开。5 条待预测样本依次落到类别 0、0、1、1、0 的叶节点上。
| 要点 | 说明 |
|---|---|
| 并列取小 | 增益并列时一律取编号最小的特征,"并列"指数学上严格相等,不要用过大的容差把不并列的情形判成并列 |
| 特征按路径禁用 | 禁用范围是"从根到当前节点"这一条路径,不是整棵树;另一条分支上同一个特征仍可再分裂 |
| 增益为 0 | 特征在该节点上取值全同、或两侧类别分布相同时,信息增益为 0,不能作为分裂特征 |
| 表决并列 | 多数表决时两类样本数量相等,取类别 0 |
| 样本不会分空 | 只有增益大于 0 的特征才会被选中,选中的特征在节点内两种取值都出现过,因此左右子树都不会为空 |
© CodeFun2000 · 使用条款
Scan the QR code below with WeChat to sign in
First-time scan will create your account automatically
请使用微信扫描下方二维码完成注册