1.构建决策树的算法有很多,比如:ID3、C4.5、CART,我们选择ID3。
ID3算法的核心是在决策树各个节点上对应信息增益准则选择特征,递归的构建决策树。具体方法
从根节点开始,对节点计算所有可能的特征的增益,选择信息增益最大的特征作为节点的特征,由
该特征的不同取值建立子节点,再对子节点递归调用以上方法,构建决策树;直到所有特征的信息
增益均很小或没有特征可以选择为止,最后得到一个决策树。
递归结束的条件是:程序遍历完所有的特征列,或者每个分支下的所有实例都具有相同的分类。
如果所有实例具有相同分类,则得到一个叶节点,任何到达叶节点的数据必然属于叶节点的分类,
即叶节点里面必须是标签。
2.信息熵:熵定义为信息的期望值,在信息论与概率统计中,熵是表示随机变量不确定性的度量。
熵越大,不确定性越大。
假定当前样本集合D中一共有n类样本,第i类样本为xi,那么xi的信息定义为:
其中,p(xi)是选择该分类的概率。
所有类别所有可能值包含的信息期望值:
3.信息增益:就是父节点的信息熵与其下所有子节点总信息熵(赋予权重)之差。
计算公式:
其中为子节点(某一特征)的权重。
4.python实战:
#决策树
import numpy as np
import pandas as pd
def createDataSet():
row_data = {'no surfacing':[1,1,1,0,0],
'flippers':[1,1,0,1,1],
'fish':['yes','yes','no','no','no']}
dataSet = pd.DataFrame(row_data)
return dataSet
#信息熵
def calEnt(dataSet):
n = dataSet.shape[0] #总样本数
iset = dataSet.iloc[:,-1].value_counts() #不同标签的个数
p = iset/n
ent = (-p*np.log2(p)).sum()
return ent
#选择最大的信息增益,即信息下降最快的方向
#选择最优的列进行切分
def bestSplit(dataSet):
baseEnt = calEnt(dataSet)
bestGain = 0
axis = -1
for i in range(dataSet.shape[1]-1):
levels = dataSet.iloc[:,i].value_counts().index
ents = 0
for j in levels:
childSet = dataSet[dataSet.iloc[:,i]==j]
ent = calEnt(childSet)
ents += (childSet.shape[0]/dataSet.shape[0])*ent
infoGain = baseEnt-ents
if (infoGain>bestGain):
bestGain = infoGain
axis = i #最大信息增益所在列的索引
return axis
def mySplit(dataSet,axis,value):
col = dataSet.columns[axis]
redataSet = dataSet.loc[dataSet[col]==value,:].drop(col,axis=1)
return redataSet
def createTree(dataSet):
featlist = list(dataSet.columns)
classlist = dataSet.iloc[:,-1].value_counts()
#递归结束条件:判断最多标签数目是否等于数据集行数(只有一类),
#或者数据集是否只有一列(只剩一个特征了)
if classlist[0]==dataSet.shape[0] or dataSet.shape[1]==1:
return classlist.index[0]
axis = bestSplit(dataSet)
bestfeat = featlist[axis]
myTree = {bestfeat:{}}
del featlist[axis]
valuelist = set(dataSet.iloc[:,axis])
for value in valuelist:
myTree[bestfeat][value] = createTree(mySplit(dataSet,axis,value))
return myTree
def classify(inputTree,labels,testVec):
firstStr = next(iter(inputTree)) #获取决策树第一个节点
secondDict = inputTree[firstStr]
featIndex = labels.index(firstStr) #第一个节点所在列的索引
for key in secondDict.keys():
if testVec[featIndex] == key:
if type(secondDict[key]) == dict:
classLabel = classify(secondDict[key],labels,testVec)
else:
classLabel = secondDict[key]
return classLabel
def acc_classify(train,test):
inputTree = createTree(train) #根据训练集生成一棵树
labels = list(train.columns) #数据集所有的列名称
result = []
for i in range(test.shape[0]):
testVec = test.iloc[i,:-1] #测试集中的一个实例
classLabel = classify(inputTree,labels,testVec) #预测该实例的分类
result.append(classLabel)
test['predict'] = result
acc = (test.iloc[:,-1] == test.iloc[:,-2]).mean() #计算准确度
print(f'模型预测准确率为{acc}')
return test
if __name__ == '__main__':
dataSet = createDataSet()
train = dataSet
#用训练集的前三个作为测试样本
test = dataSet.iloc[:3,:]
print(acc_classify(train,test))
输出结果:
5.sklearn:
#使用sklearn中graphviz包实现决策树的绘制
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
#特征
xtrain = dataSet.iloc[:,:-1]
#标签
ytrain = dataSet.iloc[:,-1]
labels = ytrain.unique().tolist()
ytrain = ytrain.apply(lambda x:labels.index(x))
#绘制树模型
clf = DecisionTreeClassifier()
clf = clf.fit(xtrain,ytrain)
tree.export_graphviz(clf)
输出结果:
最后,感谢菊安酱在哔站的认真讲解!