ID3算法原理
ID3算法的基本策略如下:
(1)树以代表训练样本的单个节点开始;
(2)如果样本都在同一个类中,则这个节点成为树叶结点并标记为该类别;
(3)否则算法使用信息熵(称为信息增益)作为启发知识来帮助选择合适的将样本分类的属性,以便将样本集划分为若干子集,
(4)对测试属性的每个已知的离散值创建一个分支,并据此划分样本;
(5)算法使用类似的方法,递归地形成每个划分上的样本决策树:
(6)整个递归过程在下列条件之一成立时停止。
ID3算法的核心是在决策树各级结点上选择属性时,用信息增益作为属性的选择标准,以使得在每一个非结点进行测试时,能获得关于被测试记录最大的类别信息
python3
from math import log
def createDataSet():
labels = ['Outlook','Temperature','Humidity','Windy','PlayGolf']
dataset = [['2', '2', '1', '0', 'no'],
['2', '2', '1', '1', 'no'],
['1', '2', '1', '0', 'yes'],
['0', '1', '1', '0', 'yes'],
['0', '0', '0', '0', 'yes'],
['0', '0', '0', '1', 'no'],
['1', '0', '0', '1', 'yes'],
['2', '1', '1', '0', 'no'],
['2', '0', '0', '0', 'yes'],
['0', '1', '0', '0', 'yes'],
['2', '1', '0', '1', 'yes'],
['1', '1', '1', '1', 'yes'],
['1', '2', '0', '0', 'yes'],]
return dataset,labels
def entropy(S): #计算熵
C={} #初始类别字典,key为类别,value为出现次数
e=0 #初始化熵
#为C赋值
for x in S:
if x[-1] not in C: #i为一条数据,最后一项即类别
C[x[-1]]=1
else:
C[x[-1]]+=1
#计算熵
for x in C:
Pi=C[x]/len(S)
e+=Pi*log(Pi,2)
return -e
def gain(A,S): #计算信息增益,A为属性下标
Si={} #初始化根据属性A划分的子集字典,key为属性A,value为属性A为key的数据集合
e=0 #初始化子集的熵
g=0 #初始化信息增益
#为Si赋值
for x in S:
if x[A] not in Si:
Si[x[A]]=[x]
else:
Si[x[A]].append(x)
#计算子集的熵
for x in Si:
e+=len(Si[x])/len(S)*entropy(Si[x])
g=entropy(S)-e
return g
def split(S, index, value): #根据属性划分集合,index为属性下标,value为属性值
split_dataSet = [] #初始化被划分的子集
for x in S:
if x[index] == value:
#去掉下标为index的属性
temp=x[:index]
temp.extend(x[index+1:])
split_dataSet.append(temp)
return split_dataSet
def choose(S): #选择最优属性,返回属性下标
index=0 #初始最优属性下标
for i in range(len(S[0])-1):
if gain(i,S)>gain(index,S):
index=i
return index
def primary_class(S): #从一个属性为空的样本集中返回出现次数最多的类别
C={} #初始类别字典,key为类别,value为出现次数
for x in S:
for c in x:
if c not in C:
C[c]=1
else:
C[c]+=1
primary_class=x[0]
for x in C:
if C[x]>C[primary_class]:
primary_class=x
return primary_class
def create_tree(dataset,labels): #创建决策树,dataset为样本集,label为标签
C=set() #初始化类别集合
for i in dataset:
C.add(i[-1])
if len(C)==1: #如果都属于同一类则返回该类别
return C.pop()
if len(dataset[0])==1: #如果属性为空则返回出现次数最多的类别
return primary_class(dataset)
best_attribute=choose(dataset) #得到最优属性下标
best_attribute_label=labels[best_attribute] #最优属性标签
tree={best_attribute_label:{}} #生成决策树
del(labels[best_attribute]) #删除已使用的标签(在split函数中会删除该标签属性列,这里要同步删除标签,才能对应上)
best_attribute_values=set() #初始化训练集中所有最优属性值
for x in dataset:
best_attribute_values.add(x[best_attribute])
for value in best_attribute_values:
subLabels=labels.copy()
tree[best_attribute_label][value] = create_tree(split(dataset, best_attribute, value), subLabels)
return tree
def classify(tree,data): #使用决策树进行分类,data为字典类型数据,key为lable,value为值
decision=tree.copy() #获取tree的拷贝,以免后面的操作改变tree
while isinstance(decision,type({})): #decision是随着决策逐步改变,直到decision不是字典的时候才停止
label=list(decision.keys())[0] #获取decision的第一个键
decision=decision[label][data[label]] #decision的第一个键对应的值将又是一个字典或一个字符串,如果是字典,那么这个字典的键是属性值,值是一个字典或字符串
return decision #最后decision将是类别
dataset,labels=createDataSet()
tree=create_tree(dataset,labels)
print("决策树为:")
print(tree)
print()
test={'Outlook':'0','Temperature':'1','Humidity':'1','Windy':'1'}
c=classify(tree,test) #no
print("{} 数据属于的类别为:".format(test))
print(c)