————致力于用代码改变世界

决策树熵计算程序[Python+CSV格式数据集]

0 前言

  • 为了便于学习决策树信息熵相关知识,笔者编写了一个专门用于计算变量信息熵、条件熵、信息增益、信息增益比的程序,方便提升学习效率。
  • 程序中包含了计算过程的数据和详细信息以及最终计算结果。
  • 编程语言为Python,搭配CSV数据格式使用。

1 数据集

1.1 游玩数据集

根据天气状况判断是否出去玩。

  • 属性id表示每个样本的编号。
  • 属性outlook表示户外天气。sunny晴天,overcast阴天,rainy雨天。
  • 属性temperature表示温度,hot热,mild温暖,cool冷。
  • 属性humidity表示湿度。high高,normal正常。
  • 属性windy表示是否有风。not没有,yes有。
  • 属性play表示是否出去玩。yes出去玩,no不出去玩。

数据集如下图(1-1)所示。
image

点击查看游玩.CSV
id,outlook,temperature,humidity,windy,play
1,sunny,hot,high,not,no
2,sunny,hot,high,yes,no
3,overcast,hot,high,not,yes
4,rainy,mild,high,not,yes
5,rainy,cool,normal,not,yes
6,rainy,cool,normal,yes,no
7,overcast,cool,normal,yes,yes
8,sunny,mild,high,not,no
9,sunny,cool,normal,not,yes
10,rainy,mild,normal,not,yes
11,sunny,mild,normal,yes,yes
12,overcast,mild,high,yes,yes
13,overcast,hot,normal,not,yes
14,rainy,mild,high,yes,no

1.2 西瓜数据集

该数据集来源于西瓜书上,如下图(1-2)所示。
根据西瓜的特征等判断是否是好瓜。
image

点击查看西瓜.CSV
编号,色泽,根蒂,敲声,纹理,脐部,触感,好瓜
1,青绿,蜷缩,浊响,清晰,凹陷,硬滑,是
2,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,是
3,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,是
4,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,是
5,浅白,蜷缩,浊响,清晰,凹陷,硬滑,是
6,青绿,稍蜷,浊响,清晰,稍凹,软粘,是
7,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,是
8,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,是
9,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,否
10,青绿,硬挺,清脆,清晰,平坦,软粘,否
11,浅白,硬挺,清脆,模糊,平坦,硬滑,否
12,浅白,蜷缩,浊响,模糊,平坦,软粘,否
13,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,否
14,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,否
15,乌黑,稍蜷,浊响,清晰,稍凹,软粘,否
16,浅白,蜷缩,浊响,模糊,平坦,硬滑,否
17,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,否

1.3 贷款数据集

该数据集来源于统计学习方法,数据如下图(1-3)所示。
根据一个人的家庭经济等条件判断是否要贷款给这个人,类别为是表示同意给此人贷款。反之不同意给此人贷款。
image

点击查看贷款.CSV
id,年龄,有工作,有房子,信贷情况,类别
1,青年,否,否,一般,否
2,青年,否,否,好,否
3,青年,是,否,好,是
4,青年,是,是,一般,是
5,青年,否,否,一般,否
6,中年,否,否,一般,否
7,中年,否,否,好,否
8,中年,是,是,好,是
9,中年,否,是,非常好,是
10,中年,否,是,非常好,是
11,老年,否,是,非常好,是
12,老年,否,是,好,是
13,老年,是,否,好,是
14,老年,是,否,非常好,是
15,老年,否,否,一般,否

2 程序解读

程序函数解读如下图(2-1)所示,从上至下浏览。
image

3 运行结果解读

此处笔者使用了西瓜数据集。
data = pd.read_csv('./Datasets/信息熵/西瓜.csv')
运行结果如下图(2-2)所示。
image
注:若计算信息增益比出现nan并非错误,而是出现分母为0。

4 程序源代码

点击查看代码
import numpy as np
import pandas as pd


#获取信息熵    H(play)
# #data:df   col:play  show:是否信息计算信息
def get_information_entropy(data,col,show=False):
    #获取col列列名
    str_col_names = data.columns.values
    col=str_col_names[col]
    i_cnt=data.shape[0]  #总行数
    if show==True:
        print('数据总样本:{}个'.format(i_cnt),end='\t')
    df_end_uni=np.unique(data[col].values) #最后一列去重 ['no' 'yes']
    arr_uni_cnt=np.array([],dtype=np.int32) #保存去重后每一个col的个数 [12,12]
    for s in df_end_uni:
        df_filter=data[data[col]==s]
        arr_uni_cnt=np.append(arr_uni_cnt,df_filter.shape[0])
        if show == True:
            print('{}=\'{}\'有{}个  '.format(col,s,df_filter.shape[0]),end='')
    if show == True:
        print('\nH({})='.format(col),end='')
        for i in arr_uni_cnt:
            print('-({}/{})log2({}/{})'.format(i,i_cnt,i,i_cnt),end='')
    arr_uni_cnt=arr_uni_cnt/i_cnt
    arr_uni_cnt=arr_uni_cnt*np.log2(arr_uni_cnt)
    f_res=np.sum(arr_uni_cnt*-1)
    if show == True:
        print('={:.4f}'.format(f_res),end='\n\n')
    return f_res

#获取data第c1列等于s1条件下c2列等于s2的个数 及 data第c1列等于s1条件下的个数
def counter(data,c1,s1,c2,s2):
    df_filter1 = data[data[c1] == s1]
    df_filter2 = df_filter1[df_filter1[c2] == s2]
    return df_filter2.shape[0],df_filter1.shape[0]

def calculater(arr_val):
    arr_res=np.array([])
    for a in range(0,len(arr_val),2):
        v1=0
        if arr_val[a]==0 or arr_val[a]==arr_val[a+1]:
            v1=0
        else:
            v1=-(arr_val[a]/arr_val[a+1]) * np.log2(arr_val[a]/arr_val[a+1])
        arr_res=np.append(arr_res,v1)
    return np.sum(arr_res)

#某一列条件熵  H(play|outlook=sunny)
# #  col表示outlook  key表示play   show:是否显示计算信息
def get_conditional_entropy(data,col,key,show=False):
    i_total=data.shape[0]
    str_col_names=data.columns.values #['id' 'overlook' 'temperature' 'humidity' 'windy' 'play']
    df_end_uni = np.unique(data[str_col_names[key]].values)  # 最后一列去重  ['no' 'yes']
    df_col_uni = np.unique(data[str_col_names[col]].values)  # 某一列去重 ['overcast' 'rainy' 'sunny']
    str_key=str_col_names[key]
    dict_single_item={}
    for a in df_col_uni:
        dict_single_item[a]=np.array([])
    for s in df_col_uni: #在outlook=overcast条件下
        arr_temp=np.array([])
        for ss in df_end_uni:#play=no
            cnt,sample=counter(data,str_col_names[col],s,str_col_names[key],ss)
            if show == True:
                print('当{}=\'{}\'时,样本有{}个,{}=\'{}\'有{}个'.format(str_col_names[col],s,sample,str_col_names[key],ss,cnt))
            arr_temp=np.append(arr_temp,[cnt,sample])
        dict_single_item[s]=arr_temp
        if show == True:
            print('H({}|{}=\'{}\')='.format(str_key,str_col_names[col],s),end='')
            for a in range(0,len(arr_temp),2):
                print('-({}/{})log2({}/{})'.format(arr_temp[a],arr_temp[a+1],arr_temp[a],arr_temp[a+1]),end='')
            print('={:.4f}\n'.format(calculater(arr_temp)))
    if show == True:
        print('H({}|{})='.format(str_key,str_col_names[col]),end='')
    i_idx=0
    i_idx_end=len(dict_single_item)
    i_sum=0
    for k in dict_single_item:
        arr_val=dict_single_item[k]
        if show == True:
            print('({}/{})*{:.4f}'.format(arr_val[1],i_total,calculater(arr_val)),end='')
        i_sum+=(arr_val[1]/i_total)*calculater(arr_val)
        if show == True:
            if i_idx<i_idx_end-1:
                print('+',end='')
            else:
                print('={:.4f}'.format(i_sum),end='\n')
        i_idx+=1
    return i_sum

#获取信息增益 g(D,A)=H(D)-H(D|A)
#data:df    key:D   col:A   show:是否显示计算信息
def get_information_gain(data,key,col,show=False):
    f_ie=get_information_entropy(data,key,False)
    f_ce=get_conditional_entropy(data,col,key,False)
    str_col_names = data.columns.values
    str_key = str_col_names[key]
    str_col = str_col_names[col]
    f_ig=f_ie-f_ce
    if show == True:
        print('g({},{})=H({})-H({}|{})={:.4f}-{:.4f}={:.4f}\n'.format(
            str_key,str_col,str_key,str_key,str_col,f_ie,f_ce,f_ig)
        )
    return f_ig

#获取信息增益比   gr(play,outlook)= g(play,outlook) / Ha(play)
# data:df   key:play    col:outlook     show:是否显示计算信息
def get_information_gain_ratio(data,key,col,show=False):
    str_col_names = data.columns.values
    str_key=str_col_names[key]
    str_col=str_col_names[col]
    f_ig=get_information_gain(data,key,col,False)
    f_ie=get_information_entropy(data,col,False)
    f_igr =None
    if f_ie==0:
        f_igr=np.nan
    else:
        f_igr=f_ig / f_ie
    if show == True:
        print('gr({},{})=g({},{}) / H({})={:.4f}/{:.4f}={:.4f}\n'.format(
            str_key,str_col,str_key,str_col,str_col,f_ig,f_ie,f_igr)
        )
    return f_igr

if __name__ == '__main__':
    data = pd.read_csv('./Datasets/信息熵/西瓜.csv')

    i_key = data.shape[1]-1  # 最终判别特征索引     默认最后一列
    #获取每个特征的信息熵、条件熵、信息增益、信息增益比
    for i_col in range(1,data.shape[1],1):
        print('-'*100)
        f_ie_col=get_information_entropy(data,i_col,True)
        f_ce_col=get_conditional_entropy(data,i_col,i_key,True)
        f_ig_col=get_information_gain(data,i_key,i_col,True)
        f_igr_col=get_information_gain_ratio(data,i_key,i_col,True)

5 结语

如有错误请指正,禁止商用。

posted @ 2024-08-28 13:51  hello_nullptr  阅读(135)  评论(0编辑  收藏  举报