from random import choice
from collections import Counter
import math
D = [
{'色泽': '青绿', '根蒂': '蜷缩', '敲声': '浊响', '纹理': '清晰', '脐部': '凹陷', '触感': '硬滑', '好瓜': '是'},
{'色泽': '乌黑', '根蒂': '蜷缩', '敲声': '沉闷', '纹理': '清晰', '脐部': '凹陷', '触感': '硬滑', '好瓜': '是'},
{'色泽': '乌黑', '根蒂': '蜷缩', '敲声': '浊响', '纹理': '清晰', '脐部': '凹陷', '触感': '硬滑', '好瓜': '是'},
{'色泽': '青绿', '根蒂': '蜷缩', '敲声': '沉闷', '纹理': '清晰', '脐部': '凹陷', '触感': '硬滑', '好瓜': '是'},
{'色泽': '浅白', '根蒂': '蜷缩', '敲声': '浊响', '纹理': '清晰', '脐部': '凹陷', '触感': '硬滑', '好瓜': '是'},
{'色泽': '青绿', '根蒂': '稍蜷', '敲声': '浊响', '纹理': '清晰', '脐部': '稍凹', '触感': '软粘', '好瓜': '是'},
{'色泽': '乌黑', '根蒂': '稍蜷', '敲声': '浊响', '纹理': '稍糊', '脐部': '稍凹', '触感': '软粘', '好瓜': '是'},
{'色泽': '乌黑', '根蒂': '稍蜷', '敲声': '浊响', '纹理': '清晰', '脐部': '稍凹', '触感': '硬滑', '好瓜': '是'},
{'色泽': '乌黑', '根蒂': '稍蜷', '敲声': '沉闷', '纹理': '稍糊', '脐部': '稍凹', '触感': '硬滑', '好瓜': '否'},
{'色泽': '青绿', '根蒂': '硬挺', '敲声': '清脆', '纹理': '清晰', '脐部': '平坦', '触感': '软粘', '好瓜': '否'},
{'色泽': '浅白', '根蒂': '硬挺', '敲声': '清脆', '纹理': '模糊', '脐部': '平坦', '触感': '硬滑', '好瓜': '否'},
{'色泽': '浅白', '根蒂': '蜷缩', '敲声': '浊响', '纹理': '模糊', '脐部': '平坦', '触感': '软粘', '好瓜': '否'},
{'色泽': '青绿', '根蒂': '稍蜷', '敲声': '浊响', '纹理': '稍糊', '脐部': '凹陷', '触感': '硬滑', '好瓜': '否'},
{'色泽': '浅白', '根蒂': '稍蜷', '敲声': '沉闷', '纹理': '稍糊', '脐部': '凹陷', '触感': '硬滑', '好瓜': '否'},
{'色泽': '乌黑', '根蒂': '稍蜷', '敲声': '浊响', '纹理': '清晰', '脐部': '稍凹', '触感': '软粘', '好瓜': '否'},
{'色泽': '浅白', '根蒂': '蜷缩', '敲声': '浊响', '纹理': '模糊', '脐部': '平坦', '触感': '硬滑', '好瓜': '否'},
{'色泽': '青绿', '根蒂': '蜷缩', '敲声': '沉闷', '纹理': '稍糊', '脐部': '稍凹', '触感': '硬滑', '好瓜': '否'},
]
class DecisionTree:
def __init__(self, D, label, chooseA):
self.D = D
self.label = label
self.chooseA = chooseA
self.A = list(filter(lambda key: key != label, D[0].keys()))
self.A_item = {}
for a in self.A:
self.A_item.update({a: set(self.getClassValues(D, a))})
'''
# print("self.A_item is" ,self.A_item)
最终的A_item:
{
'色泽': {'乌黑', '青绿', '浅白'},
'根蒂': {'硬挺', '稍蜷', '蜷缩'},
'敲声': {'清脆', '浊响', '沉闷'},
'纹理': {'清晰', '稍糊', '模糊'},
'脐部': {'稍凹', '凹陷', '平坦'},
'触感': {'硬滑', '软粘'}
}
'''
self.root = self.generate(self.D, self.A)
def getClassValues(self, D, className):
'''
:param D: 数据集
:param className: 每个className
:return: D中className属性对应的所有值
'''
return list(map(lambda sample: sample[className], D))
def isSameInA(self, D, A):
for a in A:
types = set(self.getClassValues(D, a))
if len(types) > 1:
return False
return True
def generate(self, D, A):
'''
:param D: 数据集
:param A: 所有className属性(不包含"好瓜")
:return:
'''
node = {}
remainLabelValues = self.getClassValues(D, self.label)
remainLabelTypes = set(remainLabelValues)
if len(remainLabelTypes) == 1:
return remainLabelTypes.pop()
most = max(remainLabelTypes, key=remainLabelValues.count)
if len(A) == 0 or self.isSameInA(D, A):
return most
a = self.chooseA(D, A, self)
print("a(每次选的最大信息增益属性) is ", a)
for type in self.A_item[a]:
condition = (lambda sample: sample[a] == type)
remainD = list(filter(condition, D))
if len(remainD) == 0:
node.update({type: most})
else:
remainA = list(filter(lambda x: x != a, A))
_node = self.generate(remainD, remainA)
node.update({type: _node})
return {a: node}
def Ent(D, label, a, a_v):
'''
:param D:
:param label:
:param a: 某一具体className属性 如"色泽"
:param a_v: 此属性对应的具体值 ,如"青绿、乌黑、浅白"三种中的一个
:return:
'''
D_v = filter(lambda sample: sample[a] == a_v, D)
D_v = map(lambda sample: sample[label], D_v)
D_v = list(D_v)
D_v_length = len(D_v)
counter = Counter(D_v)
info_entropy = 0
for k, v in counter.items():
p_k = v / D_v_length
info_entropy += p_k * math.log(p_k, 2)
return -info_entropy
def information_gain(D, A, tree: DecisionTree):
gain = {}
for a in A:
gain[a] = 0
values = tree.getClassValues(D, a)
counter = Counter(values)
for a_v, nums in counter.items():
gain[a] -= (nums / len(D)) * Ent(D, tree.label, a, a_v)
return max(gain.keys(), key=lambda key: gain[key])
if __name__ == '__main__':
desicionTreeRoot = DecisionTree(D, label='好瓜', chooseA=information_gain).root
print('决策树:', desicionTreeRoot)
最终生成的决策树如下:
a(每次选的最大信息增益属性) is 纹理
a(每次选的最大信息增益属性) is 触感
a(每次选的最大信息增益属性) is 根蒂
a(每次选的最大信息增益属性) is 色泽
a(每次选的最大信息增益属性) is 触感
决策树: {'纹理': {'稍糊': {'触感': {'软粘': '是', '硬滑': '否'}}, '清晰': {'根蒂': {'稍蜷': {'色泽': {'乌黑': {'触感': {'软粘': '否', '硬滑': '是'}}, '浅白': '是', '青绿': '是'}}, '蜷缩': '是', '硬挺': '否'}}, '模糊': '否'}}
有话就说, 感谢ww提供的材料~哈哈游表示很开心哈
|