决策树之ID3算法及其Python实现,具体内容如下

主要内容

决策树背景知识
决策树一般构建过程
ID3算法分裂属性的选择
ID3算法流程及其优缺点分析
ID3算法Python代码实现

1. 决策树背景知识

"color: #800000">注:分裂属性的选取是决策树生产过程中的关键,它决定了生成的决策树的性能、结构。分裂属性选择的评判标准是决策树算法之间的根本区别。

3. ID3算法分裂属性的选择——信息增益

"htmlcode">

# -*- coding: utf-8 -*-
__author__ = 'zhihua_oba'

import operator
from numpy import *
from math import log

#文件读取
def file2matrix(filename, attribute_num): #传入参数:文件名,属性个数
 fr = open(filename)
 arrayOLines = fr.readlines()
 numberOfLines = len(arrayOLines) #统计数据集行数(样本个数)
 dataMat = zeros((numberOfLines, attribute_num))
 classLabelVector = [] #分类标签
 index = 0
 for line in arrayOLines:
  line = line.strip() #strip() 删除字符串中的'\n'
  listFromLine = line.split() #将一个字符串分裂成多个字符串组成的列表,不带参数时以空格进行分割,当代参数时,以该参数进行分割
  dataMat[index, : ] = listFromLine[0:attribute_num] #读取数据对象属性值
  classLabelVector.append(listFromLine[-1]) #读取分类信息
  index += 1
 dataSet = [] #数组转化成列表
 index = 0
 for index in range(0, numberOfLines):
  temp = list(dataMat[index, :])
  temp.append(classLabelVector[index])
  dataSet.append(temp)
 return dataSet

#划分数据集
def splitDataSet(dataSet, axis, value):
 retDataSet = []
 for featvec in dataSet: #每行
  if featvec[axis] == value: #每行中第axis个元素和value相等 #删除对应的元素,并将此行,加入到rerDataSet
   reducedFeatVec = featvec[:axis]
   reducedFeatVec.extend(featvec[axis+1:])
   retDataSet.append(reducedFeatVec)
 return retDataSet

#计算香农熵 #计算数据集的香农熵 == 计算数据集类标签的香农熵
def calcShannonEnt(dataSet):
 numEntries = len(dataSet) #数据集样本点个数
 labelCounts = {} #类标签
 for featVec in dataSet: #统计数据集类标签的个数,字典形式
  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)
 return shannonEnt

#根据香农熵,选择最优的划分方式 #根据某一属性划分后,类标签香农熵越低,效果越好
def chooseBestFeatureToSplit(dataSet):
 baseEntropy = calcShannonEnt(dataSet) #计算数据集的香农熵
 numFeatures = len(dataSet[0])-1
 bestInfoGain = 0.0 #最大信息增益
 bestFeature = 0 #最优特征
 for i in range(0, numFeatures):
  featList = [example[i] for example in dataSet] #所有子列表(每行)的第i个元素,组成一个新的列表
  uniqueVals = set(featList)
  newEntorpy = 0.0
  for value in uniqueVals: #数据集根据第i个属性进行划分,计算划分后数据集的香农熵
   subDataSet = splitDataSet(dataSet, i, value)
   prob = len(subDataSet)/float(len(dataSet))
   newEntorpy += prob*calcShannonEnt(subDataSet)
  infoGain = baseEntropy-newEntorpy #划分后的数据集,香农熵越小越好,即信息增益越大越好
  if(infoGain > bestInfoGain):
   bestInfoGain = infoGain
   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.iteritems(), 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]
 if len(dataSet[0]) == 1: #如果数据集样本只有一列(该列是类标签),说明所有属性都划分完毕,则根据多数表决方法,对该叶子结点进行分类
  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[:]
  subDataSet = splitDataSet(dataSet, bestFeat, value)
  myTree[bestFeatLabel][value] = createTree(subDataSet, subLabels)
 return myTree

#测试算法:使用决策树,对待分类样本进行分类
def classify(inputTree, featLabels, testVec): #传入参数:决策树,属性标签,待分类样本
 firstStr = inputTree.keys()[0] #树根代表的属性
 secondDict = inputTree[firstStr]
 featIndex = featLabels.index(firstStr) #树根代表的属性,所在属性标签中的位置,即第几个属性
 for key in secondDict.keys():
  if testVec[featIndex] == key:
   if type(secondDict[key]).__name__ == 'dict':
    classLabel = classify(secondDict[key], featLabels, testVec)
   else:
    classLabel = secondDict[key]
 return classLabel

def main():
 dataSet = file2matrix('test_sample.txt', 4)
 labels = ['attr01', 'attr02', 'attr03', 'attr04']
 labelsForCreateTree = labels[:]
 Tree = createTree(dataSet, labelsForCreateTree )
 testvec = [2, 3, 2, 3]
 print classify(Tree, labels, testvec)
if __name__ == '__main__':
  main()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?