目录
简单理论介绍
ID3--信息增益
信息熵( Information Entropy):度量了事物的不确定性,越不确定的事物,它的熵就越大;
随机变量X它的熵表达式如下:
其中 n 代表 X 的 n 种不同的离散取值。而 代表了X取值为 i 时的概率。熵只依赖X的分布,和X的取值没有关系
联合熵:熟悉上面单个变量的熵,多个变量的联合熵就很好理解了,此处给出两个变量X,Y的联合熵。
条件熵H(X|Y):条件熵类似于条件概率,它度量了我们的X在知道Y以后剩下的不确定性。
信息增益(Information Gain):它度量了X在知道Y以后不确定性减少程度,这个度量我们在信息论中称为互信息,记为I(X,Y)。在决策树ID3算法中叫做信息增益。
=================================================================
举一个信息增益计算的具体的例子。比如我们有15个样本D,输出为0或者1。其中有9个输出为0, 6个输出为1。 样本中有个特征A,取值为A1,A2和A3。在取值为A1的样本的输出中,有3个输出为1, 2个输出为0,取值为A2的样本输出中,2个输出为1,3个输出为0, 在取值为A3的样本中,4个输出为1,1个输出为0.
样本D的熵
样本D在特征A下的条件熵为:
信息增益为:
ID3的缺点:
1,不能处理连续特征;
2,用信息增益作为标准容易偏向于取值较多的特征;
3,缺失值处理的问题
4,过拟合问题
=================================================================
C4.5--信息增益率
对ID3的改进方案。
对于ID3不能处理连续特征, C4.5的思路是将连续的特征离散化。(二分法,区间划分)
对于ID3容易偏向于取值较多的特征的问题。C4.5引入一个信息增益比的变量IR(X,Y),它是信息增益和特征熵的比值:
其中D为样本特征输出的集合,A为样本特征,对于特征熵, 表达式如下:
其中n为特征A的类别数,为特征A的第i个取值对应的样本个数。D为样本个数。特征数越多的特征对应的特征熵越大,它作为分母,可以校正信息增益容易偏向于取值较多的特征的问题。
CART--基尼系数
在ID3算法中我们使用了信息增益来选择特征,信息增益大的优先选择。在C4.5算法中,采用了信息增益比来选择特征,以减少信息增益容易选择特征值多的特征的问题。但是无论是ID3还是C4.5,都是基于信息论的熵模型的,这里面会涉及大量的对数运算。能不能简化模型同时也不至于完全丢失熵模型的优点呢?有!CART分类树算法使用基尼系数来代替信息增益比,基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好
在分类问题中,假设有K个类别,第k个类别的概率为 , 则基尼系数的表达式为
如果是二类分类问题,计算就更加简单了,如果属于第一个样本输出的概率是 p,则基尼系数的表达式为:
对于个给定的样本D,假设有K个类别, 第k个类别的数量为,则样本D的基尼系数表达式为:
特别的,对于样本D,如果根据特征A的某个值a,把D分成D1和D2两部分,则在特征A的条件下,D的基尼系数表达式为:
决策树对比:
模型 | 支持任务 | 树结构 | 特征选择 | 连续值处理 | 缺失值处理 | 剪枝 |
ID3 | 分类 | 多叉树 | 信息增益 | - | - | - |
C4.5 | 分类 | 多叉树 | 信息增益比 | 支持 | 支持 | 支持 |
CART | 分类、回归 | 二叉树 | 基尼系数 | 支持 | 支持 | 支持 |
机器学习实战-决策树预测隐形眼镜类型(ID3)
Python实现
定义熵
from math import log
import operator
#熵的定义
def calcShannonEnt(dataSet):
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet: #the the number of unique elements and their occurance
currentLabel = featVec[-1]
if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0
labelCounts[currentLabel] += 1
shannonEnt = 0.0
for key in labelCounts:
prob = float(labelCounts[key])/numEntries
shannonEnt -= prob * log(prob, 2) #log base 2
return shannonEnt
划分数据集:按照给定的特征划分数据集
def splitDataSet(dataSet, axis, value):
retDataSet = []
for featVec in dataSet:
if featVec[axis] == value:
reducedFeatVec = featVec[:axis] #chop out axis used for splitting
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet
选择最好的数据集划分方式
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #the last column is used for the labels
baseEntropy = calcShannonEnt(dataSet)
bestInfoGain = 0.0; bestFeature = -1
for i in range(numFeatures): #iterate over all the features
featList = [example[i] for example in dataSet]#create a list of all the examples of this feature
uniqueVals = set(featList) #get a set of unique values
newEntropy = 0.0
for value in uniqueVals:
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calcShannonEnt(subDataSet)
infoGain = baseEntropy - newEntropy #calculate the info gain; ie reduction in entropy
if (infoGain > bestInfoGain): #compare this to the best gain so far
bestInfoGain = infoGain #if better than current best, set to best
bestFeature = i
return bestFeature
多数表决发决定该叶子节点的分类
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 createTree(dataSet, labels):
classList = [example[-1] for example in dataSet]
if classList.count(classList[0]) == len(classList):
return classList[0]#stop splitting when all of the classes are equal
if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet
return majorityCnt(classList)
bestFeat = chooseBestFeatureToSplit(dataSet)
bestFeatLabel = labels[bestFeat]
myTree = {bestFeatLabel:{}}
del(labels[bestFeat])
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:] #copy all of labels, so trees don't mess up existing labels
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels)
return myTree
使用决策树执行分类
def classify(inputTree, featLabels, testVec):
firstStr = list(inputTree)[0]
secondDict = inputTree[firstStr]
featIndex = featLabels.index(firstStr)
key = testVec[featIndex]
valueOfFeat = secondDict[key]
if isinstance(valueOfFeat, dict):
classLabel = classify(valueOfFeat, featLabels, testVec)
else: classLabel = valueOfFeat
return classLabel
使用决策树预测隐形眼镜类型
fr = open('lenses.txt')
lenses = [inst.strip().split('\t') for inst in fr.readlines()]
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
lensesTree = createTree(lenses,lensesLabels)
print(lensesTree)
使用决策树自行预测
lensesLabels = ['age', 'prescript', 'astigmatic', 'tearRate']
classify(lensesTree, lensesLabels, lenses[0][:-1])
preds = []
for i in range(len(lenses)):
pred = classify(lensesTree, lensesLabels, lenses[i][:-1])
preds.append(pred)
print(preds)
Scikit-learn实现
这里用scikit-learn自带的数据-红酒数据
from sklearn import tree #导包
from sklearn.datasets import load_wine #红酒数据集
from sklearn.model_selection import train_test_split #数据划分训练集与测试集
#获取数据
wine = load_wine()
#划分训练集与测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
#实例化模型,划分规则用的是熵
clf = tree.DecisionTreeClassifier(criterion="entropy")
#拟合数据
clf = clf.fit(Xtrain, Ytrain)
#测试评分
score = clf.score(Xtest, Ytest)
#查看特征重要程度
clf.feature_importances_
#决策树参数表
class sklearn.tree.DecisionTreeClassifier(
criterion=’gini’, #划分规则,基尼系数 或者 信息熵
splitter=’best’,
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.0,
max_features=None,
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
class_weight=None,
presort=False)