安静到无声

V1

2022/10/21阅读:30主题:萌绿

决策树分男女性别

前言

本文是笔者“机器学习与人工智能”的一个作业题,题目是按照要求采用决策树是实现男女的分类,整体来说是非常简单的,考虑老师要求以书面的形式上交,所以就进行了简单的分析并撰写的此文章。

数据集分析

首先给出了本题目数据集,如图1所示,主要有头发、声音、脸型和肤质四种属性,这四种属性均有两种可能,即(长,短)、(粗,细)、(方,圆)和(粗糙,细腻),样本一共为10个,其中男生样本有5个,女生样本有5个。

图1 数据集呈现
图1 数据集呈现

决策树实现过程

由于样本有多个属性,具体按照那个属性进行划分呢?

其实划分是有一定原则的,就是决策树的分支点所包含的样本应该尽可能的属于一分类,即样本的纯度越来越高就好。由此我们可以想到有信息论所学习的信息熵,熵是用于衡量混乱程度的,信息熵越大,说明不确定性越大,所含的信息就是越丰富的,相反样本的纯度越高,信息熵的值就越低。假设样本集 中第 类样本占的比例为 (k=( ), 为类别数),则 的信息熵为:

其中 越小,则纯度越低,我们以上文男女分类的数据集为例,已知有两类,男生样本有5个,女生样本有5个,则可以计算样本集的信息熵为:

除了样本信息熵之外,还有一个需要介绍的概念是信息增益,使用样本属性 对样本集 进行划分所获得的“信息增益”的计算方法是,用样本集的总信息熵减去属性 的每个分支的信息熵与权重(该分支的样本数除以总样本数)的乘积,通常,信息增益越大,意味着用属性 进行划分所获得的“纯度提升”越大。因此,优先选择信息增益最大的属性来划分。

为表述方便,假设头发、声音、脸型和肤质四种属性分别是 ,针对竖属性为头发来讲, 的女生有1个,男生3个; 的女生有4个,男生2个。所以可得:

则最终的信息增益

程序实现

import pandas as pd
import numpy as np

#计算信息熵
def cal_information_entropy(data):
    data_label = data.iloc[:,-1]
    label_class =data_label.value_counts() #总共有多少类
    Ent = 0
    for k in label_class.keys():
        p_k = label_class[k]/len(data_label)
        Ent += -p_k*np.log2(p_k)
    return Ent

#计算给定数据属性a的信息增益
def cal_information_gain(data, a):
    Ent = cal_information_entropy(data)
    feature_class = data[a].value_counts() #特征有多少种可能
    gain = 0
    for v in feature_class.keys():
        weight = feature_class[v]/data.shape[0]
        Ent_v = cal_information_entropy(data.loc[data[a] == v])
        gain += weight*Ent_v
    return Ent - gain

#获取标签最多的那一类
def get_most_label(data):
    data_label = data.iloc[:,-1]
    label_sort = data_label.value_counts(sort=True)
    return label_sort.keys()[0]

#挑选最优特征,即信息增益最大的特征
def get_best_feature(data):
    features = data.columns[:-1]
    res = {}
    for a in features:
        temp = cal_information_gain(data, a)
        res[a] = temp
    res = sorted(res.items(),key=lambda x:x[1],reverse=True)
    return res[0][0]

##将数据转化为(属性值:数据)的元组形式返回,并删除之前的特征列
def drop_exist_feature(data, best_feature):
    attr = pd.unique(data[best_feature])
    new_data = [(nd, data[data[best_feature] == nd]) for nd in attr]
    new_data = [(n[0], n[1].drop([best_feature], axis=1)) for n in new_data]
    return new_data

#创建决策树
def create_tree(data):
    data_label = data.iloc[:,-1]
    if len(data_label.value_counts()) == 1: #只有一类
        return data_label.values[0]
    if all(len(data[i].value_counts()) == 1 for i in data.iloc[:,:-1].columns): #所有数据的特征值一样,选样本最多的类作为分类结果
        return get_most_label(data)
    best_feature = get_best_feature(data) #根据信息增益得到的最优划分特征
    Tree = {best_feature:{}} #用字典形式存储决策树
    exist_vals = pd.unique(data[best_feature]) #当前数据下最佳特征的取值
    if len(exist_vals) != len(column_count[best_feature]): #如果特征的取值相比于原来的少了
        no_exist_attr = set(column_count[best_feature]) - set(exist_vals) #少的那些特征
        for no_feat in no_exist_attr:
            Tree[best_feature][no_feat] = get_most_label(data) #缺失的特征分类为当前类别最多的

    for item in drop_exist_feature(data,best_feature): #根据特征值的不同递归创建决策树
        Tree[best_feature][item[0]] = create_tree(item[1])
    return Tree

def predict(Tree , test_data):
    first_feature = list(Tree.keys())[0]
    second_dict = Tree[first_feature]
    input_first = test_data.get(first_feature)
    input_value = second_dict[input_first]
    if isinstance(input_value , dict): #判断分支还是不是字典
        class_label = predict(input_value, test_data)
    else:
        class_label = input_value
    return class_label
    
    
data = pd.read_csv('data_word.csv',encoding='gbk')
#读取数据

#统计每个特征的取值情况作为全局变量
column_count = dict([(ds, list(pd.unique(data[ds]))) for ds in data.iloc[:, :-1].columns])

#创建决策树
dicision_Tree = create_tree(data)
print(dicision_Tree)

test_data_1 = {'头发':'长','声音':'粗','脸型':'方','肤质':'粗糙'}
test_data_2 = {'头发':'短','声音':'粗','脸型':'圆','肤质':'细腻'}
result = predict(dicision_Tree,test_data_2)
print('分类结果为'+'男生'if result == 1 else '女生')

参考

https://blog.csdn.net/IT23131/article/details/121068259 https://zhuanlan.zhihu.com/p/499238588

分类:

后端

标签:

后端

作者介绍

安静到无声
V1

公众号:安静到无声成长之路