李航老师《统计学习方法》第二版学习笔记
数据集:test1.txt
编号,色泽,根蒂,敲声,纹理,脐部,触感,好瓜
1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,否
'''读取西瓜数据集'''
import numpy as np
import pandas as pd
df =pd.read_table('test1.txt',encoding='utf8',delimiter=',',index_col=0)
'''计算信息熵'''
import math
def info_entropy(df):
class_num = len(df)
class_1 = df[df["好瓜"]=="是"]
class_0 = df[df['好瓜']=="否"]
p_1 = len(class_1)/class_num
p_0 = len(class_0)/class_num
if p_1==0 and p_0!=0:
info_entropy = -p_0*math.log2(p_0)
elif p_0==0 and p_1!=0:
info_entropy = -p_1*math.log2(p_1)
else:
info_entropy = -(p_1*math.log2(p_1)+p_0*math.log2(p_0))
return info_entropy
'''划分数据集'''
def split_data(data_property,df):
data_property_values = list(set(df[data_property]))
data = [0]*len(data_property_values)
for j,i in enumerate(data_property_values):
data[j] = df[df[data_property]==i]
return data
'''计算信息增益'''
def gain_func(data_property,df):
df_len = len(df)
dataset = split_data(data_property,df)
dataset_num = len(dataset)
entropy_Das = []
dataset_each_nums =[]
gain = {}
for dataset_each in dataset:
dataset_each_num = len(dataset_each)
dataset_each_nums.append(dataset_each_num)
# 计算分支节点的信息熵
entropy_Da = info_entropy(dataset_each)
entropy_Das.append(entropy_Da)
# 计算信息增益
entropy_D = info_entropy(df)
entropy_condition = [entropy_Das[i]/df_len*y for i,y in enumerate(dataset_each_nums)]
gain[data_property] = entropy_D-np.sum(entropy_condition)
return gain
'''数据集中具有的属性'''
def propertys(root_property,df):
data_propertys = []
for column in df.columns:
data_propertys.append(column)
data_propertys.pop(-1)
if root_property != None:
data_propertys.remove(root_property)
return data_propertys
'''确定划分属性'''
def choose_node(root_property,df):
class_num = len(df)
class_1 = df[df["好瓜"]=="是"]
class_0 = df[df['好瓜']=="否"]
if len(class_1)== class_num:
print("叶节点:好瓜")
# 这里如果为叶节点,返回其父节点
return root_property
elif len(class_0)== class_num:
print("叶节点:坏瓜")
# 这里如果为叶节点,返回其父节点
return root_property
else:
gains = {}
data_propertys = propertys(root_property,df)
for data_property in data_propertys:
gains.update(gain_func(data_property,df))
gain_max_property = max(gains,key=gains.get)
print("属性节点",gain_max_property)
return gain_max_property
'''生成树,按层生成'''
current_node = choose_node(None,df)
nodes = []
nodes_data = []
def tree(father_node,df):
if nodes!=[]:
nodes.pop(0)
nodes_data.pop(0)
data = split_data(father_node,df)
for branch_data in data:
print("结点{'",father_node,"'}=",set(branch_data[father_node]),"的分支节点为")
child_node = choose_node(father_node,branch_data)
print("\n")
if child_node==father_node:
continue
else:
nodes.append(child_node)
nodes_data.append(branch_data)
for i,node_i in enumerate(nodes):
# 递归
tree(node_i,nodes_data[i])
tree(current_node,df)
输出结果:与西瓜书上结果一致
属性节点 纹理
结点{' 纹理 '}= {'稍糊'} 的分支节点为
属性节点 触感
结点{' 纹理 '}= {'清晰'} 的分支节点为
属性节点 根蒂
结点{' 纹理 '}= {'模糊'} 的分支节点为
叶节点:坏瓜
结点{' 触感 '}= {'硬滑'} 的分支节点为
叶节点:坏瓜
结点{' 触感 '}= {'软粘'} 的分支节点为
叶节点:好瓜
结点{' 根蒂 '}= {'蜷缩'} 的分支节点为
叶节点:好瓜
结点{' 根蒂 '}= {'稍蜷'} 的分支节点为
属性节点 色泽
结点{' 根蒂 '}= {'硬挺'} 的分支节点为
叶节点:坏瓜
结点{' 色泽 '}= {'青绿'} 的分支节点为
叶节点:好瓜
结点{' 色泽 '}= {'乌黑'} 的分支节点为
属性节点 触感
结点{' 触感 '}= {'硬滑'} 的分支节点为
叶节点:好瓜
结点{' 触感 '}= {'软粘'} 的分支节点为
叶节点:坏瓜