一种非线性有监督分类模型

一种非线性有监督分类模型

随机森林是一种非线性有监督的分类模型。随机森林的决策树的升级版,由多个随机数据集的决策树组合而成。

决策树

决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。

决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。

决策树算法目的:

利用数据的一些规则来尽可能的降低数据集的不确定性,即给定一些特征来降低数据的不确定性。

决策树的核心思想:

就是在一个数据集中找到一个最优特征,根据这个最优特征将数据集分为多个子数据集,然后递归操作,直到满足指定条件为止。

案例:判断一个人是否有偿还能力

决策树是一种非线性有监督的分类模型。

线性分类模型比如说逻辑回归,可能会存在不可分问题,但是非线性分类就不存在这个问题。

如下图,决策树的非线性分割:

决策树案例分析

例如:我们来判断车祸与天气的关系。

数据离散化:

决策树是通过固定的条件来对类别进行判断:

决策树的生成:

数据不断分裂的递归过程,每一次分裂,尽可能让类别一样的数据在树的一边,当树的叶子节点的数据都是一类的时候,则停止分类。(相当于if else 语句)

决策树最优特征选取

决策树的生成最关键的条件是树的头部,也就是第一次分裂特征的选取,选取的好坏直接影响到分裂的效率。

由上图可看出,我们首先选取的天气进行分类,那为什么先选取天气这个特征呢。

假如我们首先选取的是湿度这个特征:

下面再选取天气这个特征:

我们会发现,只有选天气的这个特征,才能第一时间得到当天气为overcast时,是肯定发生车祸的。这样,我们后面就不用再分裂,结果直接就出来了。

分割方式

假如如下图,数据集有两种分割方式,你会选择哪种?

结论是:方式2会更好,因为分的会更彻底。方式1分完之后,彼此之间还是没有分开,效果不大。

评判准则

树的每一次分类,都有很多种选择标准,每种标准产生不同的分类结果,因此我们需要一个评判指标,看看哪种选择最合适。

评判标准是每一个叶子里面的类别尽可能一致。

幸运的是,Spark已经将评价标准作了很好的封装,用户只需调用API即可。Spark MLlib会自动帮我们去做。

最优特征怎么找?

这里就引入两个词,信息熵和条件熵。

信息熵条件熵

**信息熵 H(X)H(X):**数据集不确定性的比例。熵的定义如下:

其中 D 表示训练数据集,c 表示数据类别数,Pi 表示类别 i 样本数量占所有样本的比例

**条件熵 H(X,Y)H(X,Y):**类似于条件概率,在知道 Y 的情况下,X 的不确定性

**信息增益:**代表熵的变化程度

特征 Y 对训练集 D 的信息增益:g(D,Y)=H(X)H(X,Y)g (D,Y)=H(X)-H(X,Y)

决策树 API 演示

得到一颗树之后,我们就可以用这棵树来做预测了。

训练集:

汽车数据样本.txt

下面是Spark MLlib 代码:

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.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object ClassificationDecisionTree {
val conf = new SparkConf()
conf.setAppName("analysItem")
conf.setMaster("local[3]")
val sc = new SparkContext(conf)

def main(args: Array[String]): Unit = {
val data = MLUtils.loadLibSVMFile(sc, "汽车数据样本.txt")
// Split the data into training and test sets (30% held out for testing)
val splits = data.randomSplit(Array(0.7, 0.3))
val (trainingData, testData) = (splits(0), splits(1))
//指明类别
val numClasses = 2
//指定离散变量,未指明的都当作连续变量处理
//1,2,3,4维度进来就变成了0,1,2,3
//这里天气维度有3类,但是要指明4,这里是个坑,后面以此类推
val categoricalFeaturesInfo = Map[Int, Int](0 -> 4, 1 -> 4, 2 -> 3, 3 -> 3)
//设定评判标准
val impurity = "entropy"
//树的最大深度,太深运算量大也没有必要 剪枝
val maxDepth = 3
//设置离散化程度,连续数据需要离散化,分成32个区间,默认其实就是32,分割的区间保证数量差不多 这个参数也可以进行剪枝
val maxBins =10
//生成模型
val model: DecisionTreeModel = DecisionTree.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo, impurity, maxDepth, maxBins)
//测试

val labelAndPreds: RDD[(Double, Double)] = 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("Test Error = " + testErr)
println("Learned classification tree model:\n" + model.toDebugString)

}
}

单颗决策树的缺点

1、运算量大,需要一次加载所有数据进内存。并且找寻分割条件是一个极耗资源的工作。

2、训练样本中出现异常数据时,将会对决策树产生很大影响。抗干扰能力差,逻辑回归怎么解决抗干扰能力的?

解决方法:

1、减少决策树所需训练样本(不可取)

2、随机采样,降低异常数据的影响。和逻辑回归比,逻辑回归可以告诉我们概率,而决策树只能取 0 或 1

于是随机森林就出来了!!!

随机森林

随机森林是一种非线性有监督分类模型。

  • 森林:由树组成
  • 随机:生成树的数据都是从数据集中随机选取的。

生成方式

当数据集很大的时候,我们随机选取数据集的一部分,生成一棵树,重复上述过程,我们可以生成一堆形态各异的树,这些树放在一起就叫森林。

随机森林将数据放入模型,产生的结果少数服从多数!!!

分割方式

随机森林跟决策树一样,是非线性,不存在不可分割的问题。

随机森林VS逻辑回归

逻辑回归 随机森林
软分类 硬分类
线性模型 非线性模型
输出有概率意义 输出无概率意义
抗干扰能力强 抗干扰能力弱

森林的生成

森林是由树组成的,这里的树是决策树,训练的过程就是利用数据集生成决策树的过程。

随机森林案例分析

例如:我们来判断对收入的关系。

数据的三种类型

1、连续型可比较:收入,身高

2、离散型可半比较:学历

3、离散型无比较:行业

随机森林的优点

1、分布式,速度快

2、可以有效避开异常数据(少数服从多数)

随机森林 API

训练集还是使用决策树的训练集。

训练集:

汽车数据样本.txt

下面是随机森林 API 代码:

import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.mllib.util.MLUtils
import org.apache.spark.mllib.tree.RandomForest

object ClassificationRandomForest {
val conf = new SparkConf()
conf.setAppName("analysItem")
conf.setMaster("local[3]")
val sc = new SparkContext(conf)

def main(args: Array[String]): Unit = {
//读取数据
val data = MLUtils.loadLibSVMFile(sc, "汽车数据样本.txt")
//将样本按7:3的比例分成
val splits = data.randomSplit(Array(0.7, 0.3))
val (trainingData, testData) = (splits(0), splits(1))
//分类数
val numClasses = 2
// categoricalFeaturesInfo 为空,意味着所有的特征为连续型变量
val categoricalFeaturesInfo = Map[Int, Int](0 -> 4, 1 -> 4, 2 -> 3, 3 -> 3)
//树的个数
val numTrees = 3
//特征子集采样策略,auto 表示算法自主选取
//"auto"根据特征数量在4个中进行选择
// 1,all 全部特征 2,sqrt 把特征数量开根号后随机选择的 3,log2 取对数个 4,onethird 三分之一
val featureSubsetStrategy = "auto"
//纯度计算
val impurity = "entropy"
//树的最大层次
val maxDepth = 3
//特征最大装箱数,即连续数据离散化的区间
val maxBins = 32
//训练随机森林分类器,trainClassifier 返回的是 RandomForestModel 对象
val model = RandomForest.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo,
numTrees, featureSubsetStrategy, impurity, maxDepth, maxBins)
//打印模型
println(model.toDebugString)
//保存模型
//model.save(sc,"汽车保险")
//在测试集上进行测试
val count = testData.map { point =>
val prediction = model.predict(point.features)
// Math.abs(prediction-point.label)
(prediction, point.label)
}.filter(r => r._1 != r._2).count()
println("Test Error = " + count.toDouble / testData.count().toDouble)
}
}