决策树(Decision tree),通俗来讲就是对数据的特征进行一系列的 if 判断从而分类数据。在数据的特征属性中,指定一些条件,从根节点一层一层决策到子节点,最终所有数据都在叶子节点上。
应用:决策树可以做分类,也可以做回归。
注意,决策树对于条件的层级(先后顺序)严格,不能乱。
如何评价特征强弱?需要一种评价标准,通过计算不同特征分类后的情况,寻找到最好的那个特征作为根节点。为了评判特征,不得不先了解一个概念,熵(entropy)。
H ( x ) = − ∑ p i ∗ l o g p i H(x)=- \sum p_i * log p_i H(x)=−∑pi∗logpi , i = 1 , 2 , 3 , 4 , 5..... n i=1,2,3,4,5.....n i=1,2,3,4,5.....n
确定根节点特征的方法:
衡量特征强弱的指标除了信息增益之外,还有信息增益率和CART(使用基尼系数计算)
注意:多项类别计算熵值和时注意加权。
对于回归问题,选取连续值中的一个切分数据,寻找最优的点。(连续值离散化)
连续值离散化在遥感影像中的直方图匹配中也有重要应用。通过将遥感影像中连续的灰度值设置一定的区间bins来分类数据,从而得到一系列离散的数据点。
预防过拟合,所有的数据无限地分类,直到每个节点都只有一个值,准确率全是100%。太庞大,不合适。
限制树的深度,叶子节点个数,叶子节点样本数,信息增益率
通过一定评价标准, C α ( T ) = C ( T ) + α ∗ ∣ T l e a f ∣ C_α(T)=C(T)+α*|T_{leaf}| Cα(T)=C(T)+α∗∣Tleaf∣
α α α 一般看需求,关注叶子节点数量可以增大,需要数据精确则减小。
决策树应用回归问题,评估标准采用方差计算。
单一的决策树在面对一些复杂的问题存在一定的限制和不足。因此通过集成算法将模型进行组合,一次来解决复杂问题。通常集成算法有三种方式:
使用bagging方式集成算法的典型代表就是随机森林(Random Forest)算法
这种方式将许多决策树并行起来对数据进行分类处理,每颗树模型都是并行计算,不会产生干扰。
此时有一个问题,多棵决策树一起分类,数据还是原来的,结果不还是一样的嘛,有什么意义?
当然,随机森林之所以称之为随机森林因为它随机嘛(说了话跟说了话是的,(●ˇ∀ˇ●))
这样就保证了每一颗树模型产生的结果不会完全相同了。
代表:AdaBoost、XGBoost
这种方式能够提升算法精度,将决策树串联起来进行一步一步的分类,每一次都比上一次好。
对于一个回归问题,首先第一棵树模型对数据进行训练,然后第二棵树对A的不足,loss进行改进弥补,然后第三棵树将前两棵树当作整体,进行loss改进,以此类推。
加入的树模型一定要比前面的模型强,即加入后的总体loss减少。
暴力、拿一堆分类器来堆
单纯为了刷结果,不考虑时间成本,效率等等。
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)