机器学习算法篇:决策树和随机森林算法

机器学习算法篇:决策树和随机森林算法

基本概念

决策树(Decision tree),通俗来讲就是对数据的特征进行一系列的 if 判断从而分类数据。在数据的特征属性中,指定一些条件,从根节点一层一层决策到子节点,最终所有数据都在叶子节点上。

应用:决策树可以做分类,也可以做回归。

注意,决策树对于条件的层级(先后顺序)严格,不能乱。

如何选择特征?

如何评价特征强弱?需要一种评价标准,通过计算不同特征分类后的情况,寻找到最好的那个特征作为根节点。为了评判特征,不得不先了解一个概念,熵(entropy)。

H ( x ) = − ∑ p i ∗ l o g p i H(x)=- \sum p_i * log p_i H(x)=pilogpi , i = 1 , 2 , 3 , 4 , 5..... n i=1,2,3,4,5.....n i=1,2,3,4,5.....n
确定根节点特征的方法:

  1. 首先,计算初始数据的基础熵值,对每个类别的熵值求和。
  2. 然后,对通过特征分类后的左右子树的数据进行熵值求和。
  3. 对比熵值下降的多少来比较特征好坏,哪个特征分类后熵值下降快(信息增益大)就当作根节点。
    信息增益计算公式: I g a i n = H b a s e ( x ) − H c u r r e n t ( x ) I_{gain}=H_{base}(x)-H_{current}(x) Igain=Hbase(x)Hcurrent(x)
    即信息增益越小每一层必须比上一层的熵值小才好(信息增益)

衡量特征强弱的指标除了信息增益之外,还有信息增益率和CART(使用基尼系数计算)

注意:多项类别计算熵值和时注意加权。

连续值怎么处理?

对于回归问题,选取连续值中的一个切分数据,寻找最优的点。(连续值离散化
连续值离散化在遥感影像中的直方图匹配中也有重要应用。通过将遥感影像中连续的灰度值设置一定的区间bins来分类数据,从而得到一系列离散的数据点。

决策树剪枝策略

预防过拟合,所有的数据无限地分类,直到每个节点都只有一个值,准确率全是100%。太庞大,不合适。

预剪枝

限制树的深度,叶子节点个数,叶子节点样本数,信息增益率

后剪枝

通过一定评价标准, C α ( T ) = C ( T ) + α ∗ ∣ T l e a f ∣ C_α(T)=C(T)+α*|T_{leaf}| Cα(T)=C(T)+αTleaf

α α α 一般看需求,关注叶子节点数量可以增大,需要数据精确则减小。

回归问题

决策树应用回归问题,评估标准采用方差计算。

集成算法

单一的决策树在面对一些复杂的问题存在一定的限制和不足。因此通过集成算法将模型进行组合,一次来解决复杂问题。通常集成算法有三种方式:

  1. Bagging:训练多个分类器取平均
  2. Boosting:从弱学习器开始加强,通过加权来进行计算
  3. Stacking:聚合多个分类或回归模型

Bagging方式

使用bagging方式集成算法的典型代表就是随机森林(Random Forest)算法
这种方式将许多决策树并行起来对数据进行分类处理,每颗树模型都是并行计算,不会产生干扰。
此时有一个问题,多棵决策树一起分类,数据还是原来的,结果不还是一样的嘛,有什么意义?

当然,随机森林之所以称之为随机森林因为它随机嘛(说了话跟说了话是的,(●ˇ∀ˇ●))

  • 每一颗树使用的样本都是随机的(样本随机性)
  • 每一颗树随机取特征中的几个(特征随机性)

这样就保证了每一颗树模型产生的结果不会完全相同了。

特征

  1. 它能够处理很高维度( feature很多)的数据,并且不用做特征选择(强特征就在上面,弱特征在下面)
  2. 在训练完后,它能够给出哪些feature比较重要
  3. 容易做成并行化方法,速度比较快
  4. 可以进行可视化展示,便于分析

Boosting 方式

代表:AdaBoost、XGBoost

这种方式能够提升算法精度,将决策树串联起来进行一步一步的分类,每一次都比上一次好。
对于一个回归问题,首先第一棵树模型对数据进行训练,然后第二棵树对A的不足,loss进行改进弥补,然后第三棵树将前两棵树当作整体,进行loss改进,以此类推。
加入的树模型一定要比前面的模型强,即加入后的总体loss减少。

Stacking方式

暴力、拿一堆分类器来堆
单纯为了刷结果,不考虑时间成本,效率等等。

决策树构造实例

from matplotlib.font_manager import FontProperties
import matplotlib.pyplot as plt
from math import log
import operator
import pickle

def crateDataSet():
    dataSet = [[0, 0, 0, 0, 'no'],
               [0, 0, 0, 1, 'no'],
               [0, 1, 0, 1, 'yes'],
               [0, 1, 1, 0, 'yes'],
               [0, 0, 0, 0, 'no'],
               [1, 0, 0, 0, 'no'],
               [1, 0, 0, 1, 'no'],
               [1, 1, 1, 1, 'yes'],
               [1, 0, 1, 2, 'yes'],
               [1, 0, 1, 2, 'yes'],
               [2, 0, 1, 2, 'yes'],
               [2, 0, 1, 1, 'yes'],
               [2, 1, 0, 1, 'yes'],
               [2, 1, 0, 2, 'yes'],
               [2, 0, 0, 0, 'no']]
    labels = ['F1-AGE','F2-wORK', 'F3-HOME','F4-LOAN']
    return dataSet, labels

def createTree(dataSet,labels,featurelabels):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList):
        return classList[0]
    if len(dataSet[0]) == 1:
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureTosplit(dataSet)
    bestFeatLabel=labels[bestFeat]
    featurelabels.append(bestFeatLabel)
    myTree={bestFeatLabel:{}}
    del labels[bestFeat]
    featValue=[example[bestFeat] for example in dataSet]
    uniqueVals=set(featValue)
    for value in uniqueVals:
        sublabels = labels[:]
        myTree[bestFeatLabel][value]=createTree(spiltDataSet(dataSet,bestFeat,value),sublabels,featurelabels)
    return  myTree

def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys(): classCount[vote] = 0
        classCount[vote] += 1
    sortedclassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedclassCount[0][0]

def chooseBestFeatureTosplit(dataset):
    numFeatures = len(dataset[0]) - 1
    baseEntropy = calcShannonEnt(dataset)
    bestInfoGain = 0
    bestFeature  = -1
    for i in range(numFeatures):
        featList = [example[i] for example in dataset]
        uniqueVals = set(featList)
        newEntropy = 0
        for val in uniqueVals:
            subDataSet =spiltDataSet(dataset,i,val)
            prob =len(subDataSet)/float(len(dataset))
            newEntropy += prob*calcShannonEnt(subDataSet)
        infoGain =baseEntropy-newEntropy
        if(infoGain>bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature


def  spiltDataSet(dataset,axis,val):
    retDataSet = []
    for featVec in dataset:
        if featVec[axis] == val:
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet

##计算熵值
def calcShannonEnt(dataset):
    numexamples = len(dataset)
    labelCounts ={}
    for featVec in dataset:
        currentlabel= featVec[-1]
        if currentlabel not in labelCounts.keys():
            labelCounts[currentlabel]=0
        labelCounts[currentlabel]+=1

    shannonEnt = 0
    for key in labelCounts:
        prob = float(labelCounts[key])/numexamples
        shannonEnt-=prob*log(prob,2)
        return shannonEnt
if __name__ == '__main__':
    dataset,labels= crateDataSet()
    featlabel=[]
    myTree=createTree(dataset,labels,featlabel)

你可能感兴趣的:(机器学习算法,机器学习,决策树,随机森林)