机器学习--决策树实践

机器学习 | 决策树实践

今天我们将进行决策树的实践,老规矩,我们将分别手动实现决策树、使用sklearn实现决策树。

首先是基于ID3算法手动实现决策树:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#ID3是基于信息熵增益构建决策树的,所以要先计算信息熵
def calInformationEntropy(dataSet):
numData = len(dataSet) #样本数量
labelCounts = {} # 创建一个数据字典:key是最后一列的数值(即标签,也就是目标分类的类别),value是属于该类别的样本个数
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 splitDataSet(dataSet, axis, value): #axis是dataSet数据集下要进行特征划分的列号
retDataSet = []
for featVec in dataSet: #遍历数据集,并抽取按axis的当前value特征进划分的数据集(不包括axis列的值)
if featVec[axis] == value:
reducedFeatVec = featVec[:axis]
reducedFeatVec.extend(featVec[axis+1:])
retDataSet.append(reducedFeatVec)
return retDataSet

######选取当前数据集下用于划分数据集的最优特征
def chooseBestFeatureToSplit(dataSet):
numFeatures = len(dataSet[0]) - 1 #获取当前数据集的特征个数
baseEntropy = calInformationEntropy(dataSet) #计算当前数据集的信息熵
bestInfoGain = 0.0; bestFeature = -1 #初始化最优信息增益和最优的特征
for i in range(numFeatures): #遍历每个特征
featList = [example[i] for example in dataSet]#获取数据集中当前特征下的所有值
uniqueVals = set(featList) # 获取当前特征值
newEntropy = 0.0
for value in uniqueVals: #计算每种划分方式的信息熵
subDataSet = splitDataSet(dataSet, i, value)
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * calInformationEntropy(subDataSet)
infoGain = baseEntropy - newEntropy #计算信息增益
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: #遍历完所有的特征时,仍然不能将数据集划分成仅包含唯一类别的分组 dataSet
return majorityCnt(classList) #由于无法简单的返回唯一的类标签,这里就返回出现次数最多的类别作为返回值
bestFeat = chooseBestFeatureToSplit(dataSet) # 获取最好的分类特征索引
bestFeatLabel = labels[bestFeat] #获取该特征的名字

myTree = {bestFeatLabel:{} } #当前数据集选取最好的特征存储在bestFeat中
del(labels[bestFeat]) #删除已经在选取的特征
featValues = [example[bestFeat] for example in dataSet]
uniqueVals = set(featValues)
for value in uniqueVals:
subLabels = labels[:]
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
return myTree

然后,我们用sklearn实现决策树:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer #特征转换器
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import classification_report
from sklearn import tree

# 这里没有数据集,默认x_train, x_test, y_train, y_test作为为训练集和测试集的数据

#转换特征后,凡是类别型型的特征都单独独成剥离出来,独成一列特征,数值型的则不变
vec = DictVectorizer(sparse=False)
X_train = vec.fit_transform(X_train.to_dict(orient='record'))# 对训练数据的特征进行提取
X_test = vec.transform(X_test.to_dict(orient='record'))# 对测试数据的特征进行提取

# 训练决策树模型并用决策树模型进行预测
dtc = DecisionTreeClassifier()
dtc.fit(X_train,y_train)
y_predict = dtc.predict(X_test)

以上就是今天的内容,谢谢大家的观看!