基本概念和公式
- 信息
- 信息熵
度量樣本集合純度最常用的一種指標:
Ent(D)值越小,則D純度越高 - 信息增益
(信息增益標準對可取數目較多的屬性有所偏好) - 信息增益率
(信息增益率標準對可取數目較少的屬性有所偏好)
(C4.5採取的策略是,先從候選屬性中找出信息增益高於平均值的屬性,再從中選擇增益率最高的) - 基尼指數
基尼值:
反映從數據集D中隨機抽取兩個樣本,其類別標誌不一致的概率
Gini(D)越小,數據集D的純度越高
屬性a的基尼指數:
- 剪枝處理
剪枝處理是對付過擬合的一種方法。
預剪枝:
在決策樹生成過程中,對每個節點在劃分前後進行估計,若當前節點劃分不能帶來決策樹泛化性能的提升(即:訓練集精度提升),則停止劃分當前結點,並將當前節點作爲葉子節點。
後剪枝:
從訓練集中生成一棵完整的決策樹,然後對節點(子節點都是葉節點)進行剪枝,若剪枝後決策樹的泛化能力比未剪枝前好,則將此節點剪掉,作爲葉節點,葉節點的標記爲所有包含的樣本中個數最多的標記。
兩種剪枝方法的比較:
後剪枝保留了更多的分支,欠擬合風險小,但訓練時間開銷更大。 - 連續值處理
候選劃分點集合:
T_a={(ai+a(i+1))/2|1≤i≤n-1}
根據信息增益公式:
計算每個劃分集合的點劃分出來的信息增益值,然後選擇信息增益值最大的點作爲最佳劃分點。 - 缺失值的處理
樣本集在屬性a上沒有缺失的集合記爲,權重Wx。
若樣本在屬性a上的值缺失,則同時將樣本華人與所有子節點,權值設爲R*W
決策樹的代碼實現
- 香農公式的代碼實現
from math import log
def calcshannonEnt(dataset):
numData =len(dataset)
featVect = {}
calcshannon = 0.0
for data in dataset:
label =data[-1]
if label not in featVect.keys():
featVect[label] = 0
featVect[label] +=1
for i in featVect.keys():
sublabels =featVect[i]
p = float(sublabels)/numData
calcshannon -= p*log(p, 2)
return calcshannon
- 數據集的代碼實現
def createDataSet():
data = [
[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'no'],
[0, 1, 'no'],
[0, 1, 'no']
]
labels = ['no surfacing', 'flippers']
return data, labels
- 劃分數據集
# coding=utf-8
#劃分數據集
def splitDataSet(dataset, axis, value):
newDataSet = []
for data in dataset:
feature = data[axis]
if feature == value:
addFeat = data[:axis]
addFeat.extend(data[axis+1:])
newDataSet.append(addFeat)
return newDataSet
- 找最好的特徵對數據集進行劃分
# coding=utf-8
#信息增益最大即爲最好特徵
from calcshannonEnt import *
from splitDataSet import *
def chooseBestFeaturetoSplit(dataset):
numFeature = len(dataset[0])-1
baseCalcshannon = calcshannonEnt(dataset)
bestInfoGain = 0.0
bestFeature = -1
for i in range(numFeature):
numFeatureValue = [example[i] for example in dataset]
uniqueValue = set(numFeatureValue)
currentCalcshannon = 0.0
for value in uniqueValue:
subData = splitDataSet(dataset, i, value)
p = float(len(subData))/len(dataset)
currentCalcshannon += p*calcshannonEnt(subData)
infoGain = baseCalcshannon - currentCalcshannon
if infoGain>bestInfoGain:
bestInfoGain = infoGain
bestFeature = i
return bestFeature
- 構造決策樹
# coding=utf-8
"""決策樹創建設計遞歸過程"""
from chooseBestFeaturetoSplit import *
from majority import *
def createTree(dataset,labels):
#遞歸出口:樣本所有分類標籤一致,所有特徵值考察完畢
labelsValue = [example[-1] for example in dataset]
if labelsValue.count(labelsValue[0]) == len(labelsValue):
return labelsValue[0]
if len(dataset
[0]) == 1:
return majority(dataset)
bestFeature = chooseBestFeaturetoSplit(dataset)
featureLabels = labels[bestFeature]
myTree = {featureLabels: {}}
del(labels[bestFeature])
valueVect = [example[bestFeature] for example in dataset]
uniqueVect = set(valueVect)
for value in uniqueVect:
subLabel = labels[:]
myTree[featureLabels][value] = createTree(splitDataSet(dataset, bestFeature, value), subLabel)
return myTree
確定同一類別中葉節點的標籤
import operator
def majority(dataset):
label = [example[-1] for example in dataset]
uniqueLabel = set(label)
labelList = {}
for data in dataset:
subLabel =data[-1]
if subLabel not in labelList:
labelList[subLabel] = 0
labelList[subLabel] +=1
labelCount = sorted(labelList.iteritems(), key=operator.itemgetter(1), reverse=True)
return labelCount[0][0]
- 確定測試數據標籤
from createTree import *
def classify(myTree,labels,testVect):
firstStr = myTree.keys()
secondStr = myTree.keys()[0]
labelsIndex = labels.index(firstStr)
for i in secondStr:
subValue = i.keys()
if testVect == subValue:
if subValue.__name__ == 'dict':
classify(subValue,labels,testVect)
else:
return subValue
將決策樹程序存儲起來
import pickle
def storeTree(tree, filename):
fw = open(filename, 'w')
pickle.dump(tree, fw)
fw.close()
def grapTree(filename):
fr = open(filename)
return pickle.load(fr)
決策樹優缺點
優點:計算複雜度不高,輸出結果易於理解,對中間值的缺失不敏感,可以處理不相關特徵數據
缺點:可能會產生過度匹配