1.信息熵
熵在信息论中代表随机变量“不确定度”的度量。一个离散型随机变量的熵H(X)定义为:
直觉上,信息量等于传输该信息所用的代价,这个也是通信中考虑最多的问题。比如说:赌马比赛中,有4匹马{A,B,C,D},获胜概率分别为{1/2,1/4,1/8,1/8}。接下来,让我们将哪一匹马获胜视为一个随机变量X∈{A,B,C,D}。假定我们需要用尽可能少的二元问题来确定随机变量X的取值。
例如:
问题1:A获胜了吗?
问题2:B获胜了吗?
问题3:C获胜了吗?
最后我们可以通过最多3个二元问题,来确定X的取值,即哪一匹马赢得了比赛。
如果X=A,那么需要问1次,概率为1/2;
如果X=B,那么需要问2次,概率为1/4;
如果X=C,那么需要问3次,概率为1/8;
如果X=D,那么同样需要问3次,概率为1/8;
那么很容易计算,在这种问法之下,为确定X取值的二元问题数量为:
那么我们回到信息熵的定义,会发现通过之前的信息熵公式,神奇地得到了:
在二进制计算机中,一个比特为0或1,其实就代表了一个二元问题的回答。也就是说,在计算机中,我们给哪一匹马夺冠这个事件进行编码,所需要的平均码长为1.75个比特。
2.联合熵和条件熵
两个随机变量X,Y的联合分布,可以形成联合熵JointEntropy,用H(X,Y)表示。
H(X,Y) – H(Y)
(X,Y)发生所包含的信息熵,减去Y单独发生包含的信息熵等于在Y发生的前提下,X发生的信息熵。
该式子定义为Y发生前提下,X的熵:
条件熵H(X|Y) = H(X,Y) – H(Y)
3.信息增益
- 概念:当熵和条件熵中的概率由数据估计(特别是极大似然估计)得到时,所对应的熵和条件熵分别称为经验熵和经验条件熵。
- 信息增益表示得知特征A的信息而使得类X的信息的不确定性减少的程度。
- 定义:特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)只差,即:
-g(D,A)=H(D)-H(D|A)
4.信息增益比
单纯的信息增益只是个相对值,因为这依赖于H(D)的大小,所以信息增益比更能客观反映信息增益。特征A对训练数据集D的信息增益比gR(D,A)定义为其信息增益g(D,A)与训练数据集D关于特征A的值的熵HA(D)之比,即
其中,,n时特征A取值的个数。
5.决策树学习的生成算法
建立决策树的关键,即在当前状态下选择哪个属性作为分类依据。根据不同的目标函数,建立决策树主要有以下三种算法。
ID3
C4.5
CART
6.代码实现
package com.dengdan
import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.tree.DecisionTree
import org.apache.spark.mllib.tree.model.DecisionTreeModel
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.{SparkConf, SparkContext}
object DecisionTreeApp extends App {
//屏蔽日志
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
//创建SparkContext
val conf = new SparkConf().setMaster("local[4]").setAppName("DecisionTree")
val sc = new SparkContext(conf)
val path = "D:\\idea_workspace2020\\spark\\sparkMLib\\decision_tree\\src\\main\\resources\\data.txt";
//加载数据
val data = MLUtils.loadLibSVMFile(sc, path)
//将数据集切分成70%的训练数据集和30%的测试数据集
val splits = data.randomSplit(Array(0.7, 0.3))
val (trainingData, testData) = (splits(0), splits(1))
//训练决策树模型
//空的categoricalFeaturesInfo表示所有特征都是连续的。
val numClasses = 2
val categoricalFeaturesInfo = Map[Int, Int]()
val impurity = "gini"
val maxDepath = 5
val maxBins = 32
val model = DecisionTree.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo, impurity, maxDepath, maxBins)
//评估模型
val labelAndPreds = testData.map { point =>
val prediction = model.predict(point.features)
(point.label, prediction)
}
//模型错误率
val testErr = labelAndPreds.filter(r => r._1 != r._2).count.toDouble / testData.count()
println(s"分类错误率=${testErr}")
println(s"训练的决策树模型:\n${model.toDebugString}")
val modelPath = "target/tmp/myDecisionTreeClassificationModel"
//保存决策树模型
model.save(sc, modelPath)
//重新读取决策树模型
val sameModel = DecisionTreeModel.load(sc, modelPath)
sc.stop()
}