聊聊基于Alink库的决策树模型算法实现
示例代码及相关内容来源于《Alink权威指南(Java版)》
概述
决策树模型再现了人们做决策的过程,该过程由一系列的判断构成,后面的判断基于前面的判断结果,不断缩小范围,最终推出结果。
如下,基于决策树模型预测天气,是最常见的示例。天气的整个预测过程,就是不断地判断推测的过程。
特征分类
特征(Feature)是对事物某种特性的描述,是建立在原始数据之上的特定表示,它是一个可识别的属性。日常生活中的很多事物我们都可以用二维表格来表示(这就是为什么Excel这么通用的原因),我们收集到的数据同样也可以用二维表格表示,那么通常特征就对应这种表示中的某一列。对于一个通用的二维数据集,每个观测值由一行表示,每个特征由一列表示,对于每一个观测具有一个特定的值。下面就是用户基本属性表,其中每一列就是一个特征,其中年龄、身高、体重是数值的,是数值特征,数值特征也叫做连续特征,而性别是用文本描述的,并且只有男女两种取值,是离散特征。
连续特征
以用户属性数据为例,比如身高、年龄、体重等特征数据,可以看作是连续特征数据,因为其分布一般是连续且不均匀的数值数据。
离散数据
以用户属性数据为例,比如性别数据,只有两种取值,是分布均匀,分组清晰的文本数据。
决策树模型处理这两种数据的区别其实也就是需要考虑数据是否分组聚集,以及是否划分数据,如何划分数据。导致其数学形式的表述有差异。
决策树分类与算法
常见决策树算法
目前常用的决策树模型有三种,分别是
- ID3
- C4.5
- CART
虽然这三种算法的区别以及实现初衷不尽相同,但其实可以都是基于三种不同类型的决策树模型来实现的。而这三种类型分别是:
- GINI:基尼值,CART算法模型
- INFOGAIN:信息增益,ID3算法模型
- INFOGAINRATIO:信息增益率,C4.5算法模型
如上所示,不同的决策树算法对应着不同类型的决策树模型。
决策树分类
决策树分为两大类:回归树与分类树,其分别对应解决机器学习领域中的分类和回归问题。分类树预测分类标签值,回归树用于预测数值。
分类树在每次分枝时,会针对当前枝节点的样本,找出最优的分裂特征和分裂方式,从而得到若干新节点;继续分枝,直到所有样本都被分入类别唯一的叶节点。
回归树的建模也差不多,但分裂指标不同,回归树一般以均方差为分裂指标。
Alink实现决策树算法模型
实现概览
在Alink库中,已经封装好了决策树算法的相关细节,使得业务开发及其简单——简单的API调用即可。
实现Demo如下:
/**
* 基于C45决策树算法进行模型训练,并输出模型
* 1. 设置C45决策树模型参数
* 1.1 设置特征列
* 1.2 设置离散特征列
* 1.3 设置标签列
* 1.4 打印输出模型
* */
static void c_2_5() throws Exception {
MemSourceBatchOp source = new MemSourceBatchOp(
new Row[] {
Row.of("sunny", 85.0, 85.0, false, "no"),
Row.of("sunny", 80.0, 90.0, true, "no"),
Row.of("overcast", 83.0, 78.0, false, "yes"),
Row.of("rainy", 70.0, 96.0, false, "yes"),
Row.of("rainy", 68.0, 80.0, false, "yes"),
Row.of("rainy", 65.0, 70.0, true, "no"),
Row.of("overcast", 64.0, 65.0, true, "yes"),
Row.of("sunny", 72.0, 95.0, false, "no"),
Row.of("sunny", 69.0, 70.0, false, "yes"),
Row.of("rainy", 75.0, 80.0, false, "yes"),
Row.of("sunny", 75.0, 70.0, true, "yes"),
Row.of("overcast", 72.0, 90.0, true, "yes"),
Row.of("overcast", 81.0, 75.0, false, "yes"),
Row.of("rainy", 71.0, 80.0, true, "no")
},
new String[] {"Outlook", "Temperature", "Humidity", "Windy", "Play"}
);
source.lazyPrint(-1);
source
.link(
new C45TrainBatchOp()
.setFeatureCols("Outlook", "Temperature", "Humidity", "Windy") // 设置特征列
.setCategoricalCols("Outlook", "Windy") // 设置离散特征
.setLabelCol("Play") // 设置标签列
.lazyPrintModelInfo()
.lazyCollectModelInfo(new Consumer <DecisionTreeModelInfo>() {
@Override
public void accept(DecisionTreeModelInfo decisionTreeModelInfo) {
try {
decisionTreeModelInfo.saveTreeAsImage(
DATA_DIR + "weather_tree_model.png", true);
} catch (IOException e) {
e.printStackTrace();
}
}
})
);
BatchOperator.execute();
}
最终生成一个决策树图
算子函数
C45TrainBatchOp
API说明
简单看看其构造函数
@NameCn("C45决策树分类训练")
@NameEn("C45 Decision Tree Training")
@EstimatorTrainerAnnotation(
estimatorName = "com.alibaba.alink.pipeline.classification.C45"
)
public class C45TrainBatchOp extends BaseRandomForestTrainBatchOp<C45TrainBatchOp> implements C45TrainParams<C45TrainBatchOp>, WithModelInfoBatchOp<DecisionTreeModelInfo, C45TrainBatchOp, C45ModelInfoBatchOp> {
private static final long serialVersionUID = -1894634246411633664L;
public C45TrainBatchOp() {
this((Params)null);
}
/**
* 主要是这里,构造了决策树模型的类别为INFOGAINRATIO
*/
public C45TrainBatchOp(Params parameter) {
super(parameter);
this.getParams().set(TreeUtil.TREE_TYPE, TreeType.INFOGAINRATIO);
this.getParams().set(HasNumTreesDefaltAs10.NUM_TREES, 1);
this.getParams().set(HasFeatureSubsamplingRatio.FEATURE_SUBSAMPLING_RATIO, 1.0D);
this.getParams().set(HasSubsamplingRatio.SUBSAMPLING_RATIO, 1.0D);
}
public C45ModelInfoBatchOp getModelInfoBatchOp() {
return (C45ModelInfoBatchOp)(new C45ModelInfoBatchOp(this.getParams())).linkFrom(new BatchOperator[]{this});
}
}