一.方法简介
决策树是一种基本的分类与回归方法,这里主要介绍用于分类的决策树。决策树模式呈树形结构,其中每
个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一个类别。学习时利用
训练数据,根据损失函数最小化的原则建立决策树模型;预测时,对新的数据,利用决策树模型进行分类
二.基本原理
决策树学习通常包括三个步骤:特征选择,决策树的生成和决策树的剪枝
(1)特征选择
特征选择在于选取对训练数据具有分类能力的特征,这样可以提高决策树学习的效率。通常特征选择的准则是信息增益(或信息增益比、
基尼指数等),每次计算每个特征的信息增益,并比较它们的大小,选择信息增益最大(信息增益比最大、基尼指数最小)的特征。下面
我们重点介绍一下特征选择的准则:信息增益。首先定义信息论中广泛使用的一个度量标准——熵(entropy),它是表示随机变量不确
定性的度量。熵越大,随机变量的不确定性就越大。而信息增益(informational entropy)表示得知某一特征后使得信息的不确定性减
少的程度。简单的说,一个属性的信息增益就是由于使用这个属性分割样例而导致的期望熵降低。信息增益、信息增益比和基尼指数的具
体定义如下:信息增益:特征A对训练数据集D的信息增益,定义为集合D的经验熵与特征A给定条件下D的经验条件熵之差,
即信息增益比:特征A对训练数据集D的信息增益比定义为其信息增益与训练数据集D关于特征A的值的熵之比,即其中,,n是特征A取值的个
数。基尼指数:分类问题中,假设有K个类,样本点属于第K类的概率,则概率分布的基尼指数定义为
(二)决策树的生成
从根结点开始,对结点计算所有可能的特征的信息增益,选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点,再对
子结点递归地调用以上方法,构建决策树;直到所有特征的信息增均很小或没有特征可以选择为止,最后得到一个决策树。
决策树需要有停止条件来终止其生长的过程。一般来说最低的条件是:当该节点下面的所有记录都属于同一类,或者当所有的记录属性都具
有相同的值时。这两种条件是停止决策树的必要条件,也是最低的条件。在实际运用中一般希望决策树提前停止生长,限定叶节点包含的最低
数据量,以防止由于过度生长造成的过拟合问题。
(三)决策树的剪枝
决策树生成算法递归地产生决策树,直到不能继续下去为止。这样产生的树往往对训练数据的分类很准确,但对未知的测试数据的分类却没有
那么准确,即出现过拟合现象。解决这个问题的办法是考虑决策树的复杂度,对已生成的决策树进行简化,这个过程称为剪枝。
决策树的剪枝往往通过极小化决策树整体的损失函数来实现。一般来说,损失函数可以进行如下的定义: 其中,
T为任意子树, 为对训练数据的预测误差(如基尼指数),为子树的叶结点个数,为参数,为参数是时的子树T的整
体损失,参数权衡训练数据的拟合程度与模型的复杂度。对于固定的,一定存在使损失函数最小的子树,将其表示为。当大的时
候,最优子树偏小;当小的时候,最优子树 偏大。
#导入需要的包
from pyspark import SparkContext
from pyspark.sql import SparkSession,Row
from pyspark.ml.feature import IndexToString, StringIndexer, VectorIndexer
from pyspark.ml import Pipeline
from pyspark.ml.linalg import Vector,Vectors
from pyspark.ml.evaluation import MulticlassClassificationEvaluator
from pyspark.ml.classification import DecisionTreeClassificationModel,DecisionTreeClassifier
from pyspark.ml.regression import DecisionTreeRegressionModel,DecisionTreeRegressor
from pyspark.ml.evaluation import RegressionEvaluator
sc = SparkContext('local','决策树分类器')
spark = SparkSession.builder.master('local').appName('决策树分类器').getOrCreate()
#读取数据,简要分析
def f(x):
rel = {}
rel['features'] = Vectors.dense(float(x[0]), float(x[1]), float(x[2]), float(x[3]))
rel['label'] = str(x[4])
return rel
data = sc.textFile("file:///usr/local/spark/mycode/exercise/iris.txt").map(lambda line: line.split(',')).map(lambda p: Row(**f(p))).toDF()
data.createOrReplaceTempView("iris")
df =spark.sql("select * from iris")
rel = df.rdd.map(lambda t: str(t[1])+":"+str(t[0])).collect()
# for item in rel:
# print(item)
#进一步处理特征和标签,以及数据分组
#1.分别获取标签列和特征列,进行索引,并进行了重命名
labelIndexer = StringIndexer().setInputCol("label").setOutputCol("indexedLabel").fit(df)
featuresIndexer = VectorIndexer().setInputCol("features").setOutputCol("indexedFeatures").fit(df)
#这里我们设置一个labelConverter,目的是把预测的类别重新转化成字符型的
labelConverter = IndexToString().setInputCol("prediction").setOutputCol("predictedLabel").setLabels(labelIndexer.labels)
#把数据分为训练集与测试集
trainingData, testData = data.randomSplit([0.7,0.3])
#训练决策树模型
dt = DecisionTreeClassifier().setLabelCol("indexedLabel").setFeaturesCol("indexedFeatures")
#在Pipeline中进行设置
pipelineClassfier = Pipeline().setStages([labelIndexer, featuresIndexer, dt, labelConverter])
#训练决策树模型
modelClassifer = pipelineClassfier.fit(trainingData)
#进行预测
predictionClassifier = modelClassifer.transform(testData)
#查看部分预测结果
predictionClassifier.select("predictedLabel", "label", "features").show(20)
#2.评估决策树模型
evaluatorClassifier = MulticlassClassificationEvaluator().setLabelCol("indexedLabel").setPredictionCol("prediction").setMetricName("accuracy")
accuracy = evaluatorClassifier.evaluate(predictionClassifier)
print("Descion Tree Test Error:"+str(1.0-accuracy))
treeModelClassifier = modelClassifer.stages[2]
print("Learned classification tree model:\n"+str(treeModelClassifier.toDebugString))
#3.构建决策树回归模型
#训练决策树模型
dtRegressor = DecisionTreeRegressor().setLabelCol("indexedLabel").setFeaturesCol("indexedFeatures")
#在pipeline中进行训练
pipelineReggressor =Pipeline().setStages([labelIndexer, featuresIndexer, dtRegressor, labelConverter])
#训练决策树模型
modelRegressor = pipelineReggressor.fit(trainingData)
#进行测试
predictionRegressor = modelRegressor.transform(testData)
#查看部分结果
predictionRegressor.select("predictedLabel", "label", "features").show(20)
#评估决策树回归模型
evalorRegressor = RegressionEvaluator().setLabelCol("indexedLabel").setPredictionCol("prediction").setMetricName("rmse")
rmse = evalorRegressor.evaluate(predictionRegressor)
print("Root Mean Squared Error (RMSE) on test data= "+ str(rmse))
treeModelRegressor = modelRegressor.stages[2]
print("Learn regression tree model:\n"+ str(treeModelRegressor.toDebugString))